BufferProvider: skeleton for thread-local service dispatch
- Use a ''monostate'' as access point to thread-local service instances - rely on a configuration-context to setup the actual service - investigate runtime overhead using a multithreaded microbenchmark
This commit is contained in:
parent
8d563d1ea9
commit
a06ef95e94
6 changed files with 389 additions and 20 deletions
77
src/lib/local-slice.hpp
Normal file
77
src/lib/local-slice.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
LOCAL-SLICE.hpp - access front-end to thread-local instances
|
||||
|
||||
Copyright (C)
|
||||
2026, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version. See the file COPYING for further details.
|
||||
|
||||
*/
|
||||
|
||||
/** @file local-slice.hpp
|
||||
** Front-end to attach to a set of thread-local instances.
|
||||
** This setup helps to adapt a given service implementation to be deployed
|
||||
** as per-thread instances, operating in a massively concurrent situation.
|
||||
** The services installed this way must be able to work as self-contained
|
||||
** instances transparently, possibly cooperating with a central hub behind
|
||||
** the scenes, which however must be coordinated by the services themselves.
|
||||
**
|
||||
** Since thread-local storage is effectively static, the configuration of
|
||||
** instances happens at some point _prior_ to the first use from within a
|
||||
** thread, and otherwise not further specified. The LocalSlice access front-end
|
||||
** is a _monostate_ and all instances thus expose the same set of per-thread
|
||||
** service instances, which are created on-demand (by the C++ runtime system).
|
||||
**
|
||||
** @warning as of 2022 the implementation of `thread_local` in the GNU runtime
|
||||
** was observed to incur seemingly unnecessary overhead, which however
|
||||
** is relevant only in a high-performance environment.
|
||||
** @todo WIP-WIP 4/2026 prototyping an Engine Buffer manager /////////////////////////////////////////////TICKET #1425
|
||||
** @see LocalSlice_test
|
||||
** @see ////TODO usage example
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef LIB_LOCAL_SLICE_H_
|
||||
#define LIB_LOCAL_SLICE_H_
|
||||
|
||||
#include "lib/integral.hpp"
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
/**
|
||||
* Common access point to thread-local service instances.
|
||||
* @tparam CONF static config / setup to initialise the service.
|
||||
*/
|
||||
template<class CONF>
|
||||
class LocalSlice
|
||||
{
|
||||
using Service = CONF::Service;
|
||||
|
||||
public:
|
||||
LocalSlice() = default;
|
||||
|
||||
// using default copy/assignment
|
||||
|
||||
|
||||
/** service access */
|
||||
Service&
|
||||
operator*() const
|
||||
{
|
||||
thread_local Service srvInstance{CONF::init()};
|
||||
return srvInstance;
|
||||
}
|
||||
|
||||
Service*
|
||||
operator->() const
|
||||
{
|
||||
return & LocalSlice::operator*();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif /*LIB_LOCAL_SLICE_H_*/
|
||||
|
|
@ -269,11 +269,6 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Linked iterable elements" LinkedElements_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Polymorphic value objects" PolymorphicValue_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
|
|
@ -473,6 +473,15 @@ TEST "Lazy init of a functor" LazyInit_test <<END
|
|||
END
|
||||
|
||||
|
||||
TEST "Intrusive linked elements" LinkedElements_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Thread-local service instances" LocalSlice_test <<END
|
||||
END
|
||||
|
||||
|
||||
TEST "configurable Factory" MultiFact_test <<END
|
||||
END
|
||||
|
||||
|
|
|
|||
204
tests/lib/local-slice-test.cpp
Normal file
204
tests/lib/local-slice-test.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
LocalSlice(Test) - verify access to thread-local services
|
||||
|
||||
Copyright (C)
|
||||
2026, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version. See the file COPYING for further details.
|
||||
|
||||
* *****************************************************************/
|
||||
|
||||
/** @file local-slice-test.cpp
|
||||
** unit test \ref LocalSlice_test
|
||||
*/
|
||||
|
||||
#include "test/run.hpp"
|
||||
#include "test/test-helper.hpp"
|
||||
#include "lib/scoped-collection.hpp"
|
||||
#include "test/microbenchmark.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/thread.hpp"
|
||||
|
||||
#include "lib/local-slice.hpp"
|
||||
|
||||
using lib::Thread;
|
||||
using lib::explore;
|
||||
using test::threadBenchmark;
|
||||
using std::this_thread::yield;
|
||||
using std::this_thread::sleep_for;
|
||||
using std::chrono_literals::operator ""us;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test {
|
||||
|
||||
namespace { // test fixture...
|
||||
|
||||
const uint NUM_THREADS = 200;
|
||||
|
||||
constexpr size_t CONCURR_BENCH = 4;
|
||||
const size_t REPETITIONS_BENCH = 1'000'000;
|
||||
|
||||
/**
|
||||
* the "service" to be instantiated thread-local
|
||||
*/
|
||||
class DummyBackend
|
||||
{
|
||||
uint step{0};
|
||||
public:
|
||||
uint
|
||||
getStep()
|
||||
{
|
||||
return ++step;
|
||||
}
|
||||
};
|
||||
|
||||
struct DummySetup
|
||||
{
|
||||
using Service = DummyBackend;
|
||||
|
||||
static Service init() { return Service(); }
|
||||
};
|
||||
|
||||
using DummySlice = LocalSlice<DummySetup>;
|
||||
|
||||
|
||||
/**
|
||||
* A common shared service instance
|
||||
* that dispatches through LocalSlice
|
||||
* into the thread-local service back-ends
|
||||
*/
|
||||
class DummyFrontend
|
||||
{
|
||||
DummySlice dummySrv_;
|
||||
|
||||
public:
|
||||
uint
|
||||
invoke()
|
||||
{
|
||||
return dummySrv_->getStep()
|
||||
+ dummySrv_->getStep()
|
||||
+ dummySrv_->getStep()
|
||||
+ dummySrv_->getStep()
|
||||
;
|
||||
}
|
||||
};
|
||||
//
|
||||
} //(End) test fixture
|
||||
|
||||
|
||||
/***********************************************************************//**
|
||||
* @test demonstrate access to thread-local service instances.
|
||||
* - setup a common front-end service instance
|
||||
* - its functionality is implemented by delegating
|
||||
* through the LocalSlice into the thread-local back-ends
|
||||
* - launch threads and invoke the front-end concurrently
|
||||
* @see local-slice.hpp
|
||||
*/
|
||||
class LocalSlice_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
investigatePerformance();
|
||||
}
|
||||
|
||||
|
||||
/** @test access thread-local service back-ends
|
||||
* through a shared front-end instance;
|
||||
* verify that each thread invokes a
|
||||
* separate instance without interference
|
||||
* @see ThreadWrapper_test
|
||||
*/
|
||||
void
|
||||
simpleUsage ()
|
||||
{
|
||||
// Σi ≡ N/2·(N+1)
|
||||
auto expectSum = [](uint n){ return n/2 * (n+1); };
|
||||
|
||||
// the front-end invokes the back-end four times in row...
|
||||
uint i1 = expectSum(4);
|
||||
uint i2 = expectSum(8) - expectSum(4);
|
||||
uint i3 = expectSum(12) - expectSum(8);
|
||||
|
||||
// Note: all threads use this common service front-end instance
|
||||
DummyFrontend myDummy;
|
||||
|
||||
// Now invoke through this front-end
|
||||
CHECK (i1 == myDummy.invoke());
|
||||
CHECK (i2 == myDummy.invoke());
|
||||
|
||||
// launch a significant number of threads,
|
||||
// each verifying the same invocation sequence
|
||||
lib::ScopedCollection<Thread> threads{NUM_THREADS};
|
||||
for (uint i=1; i<=NUM_THREADS; ++i)
|
||||
threads.emplace ([&]{
|
||||
CHECK (i1 == myDummy.invoke());
|
||||
|
||||
sleep_for (100us);
|
||||
|
||||
CHECK (i2 == myDummy.invoke());
|
||||
|
||||
sleep_for (100us);
|
||||
|
||||
CHECK (i3 == myDummy.invoke());
|
||||
});
|
||||
|
||||
while (explore(threads).has_any())
|
||||
yield(); // wait for all threads to finish
|
||||
|
||||
|
||||
// ...without any interference with the main thread's instance
|
||||
CHECK (i3 == myDummy.invoke());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test investigate performance of thread-local dispatch
|
||||
* - subject-1 accesses the increment through the common thread-local dispatch
|
||||
* - subject-2 increments just a local variable in each thread
|
||||
* - run a multithreaded benchmark with 1 million repetitions
|
||||
* - but only small number of threads to avoid OS scheduler congestion
|
||||
* @see test::threadBenchmark()
|
||||
*/
|
||||
void
|
||||
investigatePerformance()
|
||||
{
|
||||
DummySlice threadLocalBackend;
|
||||
auto testThreadLocal = [&]{
|
||||
auto volatile result = threadLocalBackend->getStep();
|
||||
return result;
|
||||
};
|
||||
|
||||
auto testLocalInc = [cnt=0] mutable
|
||||
{
|
||||
auto volatile result = ++cnt;
|
||||
return result;
|
||||
};
|
||||
|
||||
cout << "µ-benchmark :: thread-local" <<endl;
|
||||
|
||||
auto [t1, s1] = ::test::threadBenchmark<CONCURR_BENCH> (testThreadLocal, REPETITIONS_BENCH);
|
||||
cout << "thread-local dispatch: "<<t1<<"µs" <<endl;
|
||||
|
||||
auto [t2, s2] = ::test::threadBenchmark<CONCURR_BENCH> (testLocalInc, REPETITIONS_BENCH);
|
||||
cout << "increment local var : "<<t2<<"µs" <<endl;
|
||||
|
||||
CHECK (s1 == s2);
|
||||
CHECK (t1 > t2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER(LocalSlice_test, "unit common");
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
@ -17,15 +17,14 @@
|
|||
|
||||
|
||||
#include "test/run.hpp"
|
||||
#include "test/tracking-dummy.hpp"
|
||||
#include "lib/thread.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
using test::Test;
|
||||
using test::Dummy;
|
||||
using lib::explore;
|
||||
using std::atomic_uint;
|
||||
using std::this_thread::yield;
|
||||
|
|
@ -138,8 +137,6 @@ namespace test{
|
|||
sleep_for (5ms);
|
||||
}
|
||||
};
|
||||
// Note the Dummy member allows to watch instance lifecycle
|
||||
CHECK (0 == Dummy::checksum());
|
||||
|
||||
// the frontEnd allows to access the TestThread component
|
||||
// and also represents the running state
|
||||
|
|
|
|||
|
|
@ -144086,6 +144086,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776296068447" ID="ID_882324053" LINK="https://alexander-ostrovskiy-c.co.uk/posts/thread-local-storage-in-c-best-practices-and-pitfalls/" MODIFIED="1776299538975" TEXT="Practical usage and hidden risks"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1776296046515" ID="ID_962020738" LINK="https://yosefk.com/blog/cxx-thread-local-storage-performance.html" MODIFIED="1776299543765" TEXT="Thread-local Performance">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1776475228247" ID="ID_566732298" MODIFIED="1776476062001" TEXT="besteht dieses Problem noch?">
|
||||
<arrowlink COLOR="#5423b6" DESTINATION="ID_751382987" ENDARROW="Default" ENDINCLINATION="918;0;" ID="Arrow_ID_1654719917" STARTARROW="None" STARTINCLINATION="897;75;"/>
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#172ce6" CREATED="1776475271089" ID="ID_622277074" MODIFIED="1776475364341" TEXT="mein Microbenchmark sieht nicht so schlimm aus">
|
||||
<linktarget COLOR="#515284" DESTINATION="ID_622277074" ENDARROW="Default" ENDINCLINATION="296;0;" ID="Arrow_ID_1814168977" SOURCE="ID_580360080" STARTARROW="Default" STARTINCLINATION="296;0;"/>
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1776299548025" ID="ID_410006825" MODIFIED="1776299559493" TEXT="ist das jetzt schlimmmmm?">
|
||||
|
|
@ -144195,10 +144203,17 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1776359147782" ID="ID_49027423" MODIFIED="1776359159216" TEXT="als notieren wir dieses potentielle Problem"/>
|
||||
<node CREATED="1776359147782" ID="ID_49027423" MODIFIED="1776359159216" TEXT="als notieren wir dieses potentielle Problem">
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1776475337836" ID="ID_580360080" LINK="https://issues.lumiera.org/ticket/1427" MODIFIED="1776475378273" TEXT="#1427 performance-impact of thread_local ">
|
||||
<arrowlink COLOR="#515284" DESTINATION="ID_622277074" ENDARROW="Default" ENDINCLINATION="296;0;" ID="Arrow_ID_1814168977" STARTARROW="Default" STARTINCLINATION="296;0;"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776359159957" ID="ID_611795063" MODIFIED="1776359168445" TEXT="untersuchen es ggfs. später empirisch"/>
|
||||
<node CREATED="1776359169275" ID="ID_1606858571" MODIFIED="1776359191747" TEXT="und bauen notfalls ein »ThreadLocal«, das optimal effizient ist"/>
|
||||
<node CREATED="1776359203560" ID="ID_240001081" MODIFIED="1776359249485" TEXT="⟹ den aktuellen Entwruf unter dieser Maßgabe weiterentwickeln">
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1776359203560" ID="ID_240001081" MODIFIED="1776477644814" TEXT="⟹ den aktuellen Entwruf unter dieser Maßgabe weiterentwickeln">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1776359250702" ID="ID_1110100689" MODIFIED="1776359257699" TEXT="er ist klar strukturiert"/>
|
||||
<node CREATED="1776359258534" ID="ID_193416980" MODIFIED="1776359267522" TEXT="er enthält ein Element der Eleganz"/>
|
||||
<node CREATED="1776359271069" ID="ID_859503094" MODIFIED="1776359280656" TEXT="er ist noch nicht optimiert (was gut ist)"/>
|
||||
|
|
@ -144206,11 +144221,16 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776204526672" ID="ID_961403309" MODIFIED="1776204711931" TEXT="Prototyping (testgetrieben)">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1776204526672" ID="ID_961403309" MODIFIED="1776477618192" TEXT="Prototyping (testgetrieben)">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1776204565654" ID="ID_45614742" MODIFIED="1776204569140" TEXT="generischer Slice">
|
||||
<node CREATED="1776292208608" ID="ID_1141218614" MODIFIED="1776292245482" TEXT="Zweck: Anbinden eines Slice in einem normalen Objekt-Kontext">
|
||||
<node CREATED="1776292987880" ID="ID_808037956" MODIFIED="1776292998479" TEXT="Zugriff über Pointer-artige Syntax"/>
|
||||
<node CREATED="1776293021744" ID="ID_808171568" MODIFIED="1776293034905" TEXT="Problem: thread_local ist implizit statisch">
|
||||
<node CREATED="1776292208608" ID="ID_1141218614" MODIFIED="1776477482889" TEXT="Zweck: Anbinden eines Slice in einem normalen Objekt-Kontext">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1776292987880" ID="ID_808037956" MODIFIED="1776477504910" TEXT="Zugriff über Pointer-artige Syntax">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776293021744" ID="ID_808171568" MODIFIED="1776477489785" TEXT="Problem: thread_local ist implizit statisch">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1776293040334" ID="ID_555811092" MODIFIED="1776293060463" TEXT="das heißt es ist eine »versteckte globale Variable«"/>
|
||||
<node CREATED="1776295872712" ID="ID_906429004" MODIFIED="1776295889501" TEXT="stellt das für den konkteten Use-Case überhaupt eine Beschränkung dar?">
|
||||
<node CREATED="1776295891705" ID="ID_877250740" MODIFIED="1776295921697" TEXT="ja — eine hexagonale Beschränkung: ⟹ man kann's nur einmal Unit-testen"/>
|
||||
|
|
@ -144253,8 +144273,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776442726252" ID="ID_1448305654" MODIFIED="1776442778834" TEXT="dadurch würde »automatisch« eine einzige Metadata-Storage im System entstehen">
|
||||
<linktarget COLOR="#fefdd2" DESTINATION="ID_1448305654" ENDARROW="Default" ENDINCLINATION="480;17;" ID="Arrow_ID_972765157" SOURCE="ID_1548755064" STARTARROW="None" STARTINCLINATION="469;0;"/>
|
||||
<node CREATED="1776442726252" ID="ID_1448305654" MODIFIED="1776477701154" TEXT="dadurch würde »automatisch« eine einzige Metadata-Storage im System entstehen">
|
||||
<linktarget COLOR="#fefdd2" DESTINATION="ID_1448305654" ENDARROW="Default" ENDINCLINATION="480;17;" ID="Arrow_ID_972765157" SOURCE="ID_1548755064" STARTARROW="None" STARTINCLINATION="613;24;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1776442794218" HGAP="25" ID="ID_1105253979" MODIFIED="1776442814861" TEXT="man müßte dann nur noch OutputSlot »einfangen«" VSHIFT="-3"/>
|
||||
</node>
|
||||
|
|
@ -144273,6 +144293,62 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776438572468" ID="ID_1804894411" MODIFIED="1776438590402" TEXT="die einzelne Instanz ist Monostate und default-konstruierbar und kopierbar"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1776461384382" ID="ID_43420839" MODIFIED="1776477478439" TEXT="Implementierung / Test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1776461548757" ID="ID_1399164537" MODIFIED="1776477531388">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<b>Name</b>: <font face="Monospaced">LocalSlice<CONF></font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1776474854867" ID="ID_1487038882" MODIFIED="1776474859837" TEXT="CONF">
|
||||
<node CREATED="1776474861216" ID="ID_399712480" MODIFIED="1776474870435" TEXT="typedef Service"/>
|
||||
<node CREATED="1776474871327" ID="ID_142831800" MODIFIED="1776474879674" TEXT="eine init-Funktion"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1776474884669" ID="ID_66962199" MODIFIED="1776477543983" TEXT="LocalSlice_test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1776474892988" ID="ID_1841154811" MODIFIED="1776474911245" TEXT="verwende ein Backend das eine Variable inkrementiert"/>
|
||||
<node CREATED="1776474912122" ID="ID_225188556" MODIFIED="1776474931651" TEXT="verwende einen front-End-Service, der das Backend mehrfach aufruft"/>
|
||||
<node CREATED="1776474932743" ID="ID_285414025" MODIFIED="1776474959191" TEXT="erst mal im main-Thread: stimmen die produzierten Zahlen?"/>
|
||||
<node CREATED="1776474960491" ID="ID_670758355" MODIFIED="1776474975933" TEXT="massiv mit parallellen Threads pressen"/>
|
||||
<node BACKGROUND_COLOR="#a1d4d1" COLOR="#135d40" CREATED="1776474978433" ID="ID_104524737" MODIFIED="1776477604743" TEXT="Benchmark">
|
||||
<node CREATED="1776474985168" ID="ID_722554158" MODIFIED="1776475006881" TEXT="verwende mein threadBenchmark"/>
|
||||
<node CREATED="1776475011468" ID="ID_572983472" MODIFIED="1776475941260" TEXT="dieses Mal nur 4 Threads">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
wir wollen nicht die Contention des OS-Schedulers messen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1776475054583" ID="ID_139797430" MODIFIED="1776475070624" TEXT="aber eine Million mal in jedem Thread wiederholen"/>
|
||||
<node CREATED="1776475071885" ID="ID_1243408123" MODIFIED="1776475095349" TEXT="zum Vergleich: ein Lambda das direkt eine lokale Variable im Thread hochzählt"/>
|
||||
<node COLOR="#435e98" CREATED="1776475100532" ID="ID_1636417377" MODIFIED="1776475388401" TEXT="Ergebnis">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node BACKGROUND_COLOR="#e1efac" COLOR="#0155a5" CREATED="1776475103868" ID="ID_751382987" MODIFIED="1776475434097" TEXT="naja ... also soooo dramatisch langsamer ist das nicht">
|
||||
<linktarget COLOR="#5423b6" DESTINATION="ID_751382987" ENDARROW="Default" ENDINCLINATION="918;0;" ID="Arrow_ID_1654719917" SOURCE="ID_566732298" STARTARROW="None" STARTINCLINATION="897;75;"/>
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1776475117023" ID="ID_1331151971" MODIFIED="1776475997517" TEXT="mit thread_local : ~ 20ns"/>
|
||||
<node CREATED="1776475134176" ID="ID_462698106" MODIFIED="1776476001516" TEXT="lokale Variable : ~ 9ns"/>
|
||||
<node CREATED="1776475155945" ID="ID_4564368" MODIFIED="1776475171818" TEXT="Auch ein nicht-trivialer Konstruktor macht keinen meßbaren Unterschied"/>
|
||||
<node CREATED="1776475174183" ID="ID_562193803" MODIFIED="1776475187901" TEXT="und zudem linken wir ja schon in eine Shared-Lib mit -fPIC"/>
|
||||
<node CREATED="1776476081141" ID="ID_1398683528" MODIFIED="1776476100906" TEXT="Anzahl Threads variieren">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1776476103003" ID="ID_1673139479" MODIFIED="1776476126644" TEXT="die thread-local-Variante wächst linear mit der Zahl der Threads"/>
|
||||
<node CREATED="1776476128271" ID="ID_452771680" MODIFIED="1776476144920" TEXT="die lokale Variable ändert sich fast gar nicht"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776204569932" ID="ID_1285006287" MODIFIED="1776204574453" TEXT="Stage-Slice"/>
|
||||
<node CREATED="1776204575221" ID="ID_869340284" MODIFIED="1776204579271" TEXT="Store-Slice"/>
|
||||
|
|
@ -144312,14 +144388,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776442525319" ID="ID_401093527" MODIFIED="1776442557719" TEXT="es gibt nur den einen Aufruf aus der BufferStage-Impl (+Tests)"/>
|
||||
<node CREATED="1776442560275" ID="ID_993355013" MODIFIED="1776442576727" TEXT="⟹ die FamilyID könnte auch als Parameter kommen"/>
|
||||
</node>
|
||||
<node CREATED="1776442580542" ID="ID_1214945994" MODIFIED="1776442607448" TEXT="es wäre ohne Weiteres möglich, die Family-ID in die Buffer-Stage-Implementierung zu heben">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1776442580542" ID="ID_1214945994" MODIFIED="1776477692805" TEXT="es wäre ohne Weiteres möglich, die Family-ID in die Buffer-Stage-Implementierung zu heben">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1776442609827" ID="ID_570121338" MODIFIED="1776442627773" TEXT="damit wäre sie aus der »Thread-Local-Zone« raus"/>
|
||||
<node CREATED="1776442630476" ID="ID_1314697653" MODIFIED="1776442651841" TEXT="und eine einzige BufferMetadata-Storage könnte alle BufferProvider im Stystem bedienen"/>
|
||||
<node CREATED="1776442666774" ID="ID_1548755064" MODIFIED="1776442784578" TEXT="das würde dann sogar implizit passieren — weil thread_local ⟹ static">
|
||||
<arrowlink COLOR="#fefdd2" DESTINATION="ID_1448305654" ENDARROW="Default" ENDINCLINATION="480;17;" ID="Arrow_ID_972765157" STARTARROW="None" STARTINCLINATION="469;0;"/>
|
||||
<node CREATED="1776442666774" ID="ID_1548755064" MODIFIED="1776477701154" TEXT="das würde dann sogar implizit passieren — weil thread_local ⟹ static">
|
||||
<arrowlink COLOR="#fefdd2" DESTINATION="ID_1448305654" ENDARROW="Default" ENDINCLINATION="480;17;" ID="Arrow_ID_972765157" STARTARROW="None" STARTINCLINATION="613;24;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1776477706236" ID="ID_17016961" MODIFIED="1776477711154" TEXT="gesägt ... getan">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1776477731488" ID="ID_1764139922" MODIFIED="1776477873117" TEXT="Fazit">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<node CREATED="1776477743564" ID="ID_893955025" MODIFIED="1776477774653" TEXT="durch Heben in die BufferStage wird BufferMetadata ein beliebig nutzbarer Service"/>
|
||||
<node CREATED="1776477775546" ID="ID_1413251785" MODIFIED="1776477827799" TEXT="zudem noch Import/Export von Registrierungen ⟹ thread-local aufrufbar"/>
|
||||
<node CREATED="1776477847655" ID="ID_1038306996" MODIFIED="1776477868291" TEXT="einen globalen Metadataten-Store bekommt man so »nebenbei geschenkt«">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue