>From 047e2e2aa09633f5605111119e2f45fd43f6febc Mon Sep 17 00:00:00 2001 From: Akira Yokosawa <akiyks@xxxxxxxxx> Date: Tue, 2 Oct 2018 23:54:33 +0900 Subject: [PATCH 1/2] count: Employ new scheme for snippet from count_stat.c Also add necessary READ_ONCE()/WRITE_ONCE() as par. the rule of where to use them provided by Paul as an outline on perfbook mail-list [1]. [1]: https://www.spinics.net/lists/perfbook/msg01788.html Suggested by: Paul E. McKenney <paulmck@xxxxxxxxxxxxx> Signed-off-by: Akira Yokosawa <akiyks@xxxxxxxxx> --- CodeSamples/count/count_stat.c | 22 +++++++++++++--------- count/count.tex | 33 ++++++++------------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/CodeSamples/count/count_stat.c b/CodeSamples/count/count_stat.c index 1d72f99..0675320 100644 --- a/CodeSamples/count/count_stat.c +++ b/CodeSamples/count/count_stat.c @@ -20,28 +20,32 @@ #include "../api.h" -DEFINE_PER_THREAD(unsigned long, counter); +//\begin{snippet}[labelbase=ln:count:count_stat:inc-read,commandchars=\\\[\]] +DEFINE_PER_THREAD(unsigned long, counter); //\lnlbl{define} -void inc_count(void) +static __inline__ void inc_count(void) //\lnlbl{inc:b} { - __get_thread_var(counter)++; -} + unsigned long *p_counter = &__get_thread_var(counter); + + WRITE_ONCE(*p_counter, *p_counter + 1); +} //\lnlbl{inc:e} -__inline__ unsigned long read_count(void) +static __inline__ unsigned long read_count(void) //\lnlbl{read:b} { int t; unsigned long sum = 0; for_each_thread(t) - sum += per_thread(counter, t); + sum += READ_ONCE(per_thread(counter, t)); return sum; -} +} //\lnlbl{read:e} +//\end{snippet} -__inline__ void count_init(void) +void count_init(void) { } -__inline__ void count_cleanup(void) +void count_cleanup(void) { } diff --git a/count/count.tex b/count/count.tex index a7d4c9d..4f760a4 100644 --- a/count/count.tex +++ b/count/count.tex @@ -477,28 +477,7 @@ thread (presumably cache aligned and padded to avoid false sharing). } \QuickQuizEnd \begin{listing}[tbp] -{ \scriptsize -\begin{verbbox} - 1 DEFINE_PER_THREAD(long, counter); - 2 - 3 void inc_count(void) - 4 { - 5 __get_thread_var(counter)++; - 6 } - 7 - 8 long read_count(void) - 9 { - 10 int t; - 11 long sum = 0; - 12 - 13 for_each_thread(t) - 14 sum += per_thread(counter, t); - 15 return sum; - 16 } -\end{verbbox} -} -\centering -\theverbbox +\input{CodeSamples/count/count_stat@xxxxxxxxxxxx} \caption{Array-Based Per-Thread Statistical Counters} \label{lst:count:Array-Based Per-Thread Statistical Counters} \end{listing} @@ -506,22 +485,26 @@ thread (presumably cache aligned and padded to avoid false sharing). Such an array can be wrapped into per-thread primitives, as shown in Listing~\ref{lst:count:Array-Based Per-Thread Statistical Counters} (\path{count_stat.c}). -Line~1 defines an array containing a set of per-thread counters of +\begin{lineref}[ln:count:count_stat:inc-read] +Line~\lnref{define} defines an array containing a set of per-thread counters of type \co{long} named, creatively enough, \co{counter}. -Lines~3-6 show a function that increments the counters, using the +Lines~\lnref{inc:b}-\lnref{inc:e} +show a function that increments the counters, using the \co{__get_thread_var()} primitive to locate the currently running thread's element of the \co{counter} array. Because this element is modified only by the corresponding thread, non-atomic increment suffices. -Lines~8-16 show a function that reads out the aggregate value of the counter, +Lines~\lnref{read:b}-\lnref{read:e} +show a function that reads out the aggregate value of the counter, using the \co{for_each_thread()} primitive to iterate over the list of currently running threads, and using the \co{per_thread()} primitive to fetch the specified thread's counter. Because the hardware can fetch and store a properly aligned \co{long} atomically, and because \GCC\ is kind enough to make use of this capability, normal loads suffice, and no special atomic instructions are required. +\end{lineref} \QuickQuiz{} What other choice does \GCC\ have, anyway??? -- 2.7.4