* [PATCH 1/7] count: Employ new scheme for inline code snippets
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
@ 2018-10-26 15:24 ` Akira Yokosawa
2018-10-26 15:24 ` [PATCH 2/7] toolsoftrade: Use 'VerbatimU' for inline snippets Akira Yokosawa
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:24 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From c8ed9b923cfdc68403998cd154f07f7834ad4edb Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 10:50:24 +0900
Subject: [PATCH 1/7] count: Employ new scheme for inline code snippets
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
count/count.tex | 89 +++++++++++++++++++++++++++++----------------------------
1 file changed, 46 insertions(+), 43 deletions(-)
diff --git a/count/count.tex b/count/count.tex
index 4d13394..0f35042 100644
--- a/count/count.tex
+++ b/count/count.tex
@@ -2679,30 +2679,33 @@ when updating the counter, and to write-acquire that same reader-writer
lock when checking the counter.
Code for doing I/O might be as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
- 1 read_lock(&mylock);
- 2 if (removing) {
- 3 read_unlock(&mylock);
- 4 cancel_io();
- 5 } else {
- 6 add_count(1);
- 7 read_unlock(&mylock);
- 8 do_io();
- 9 sub_count(1);
- 10 }
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
-
-Line~1 read-acquires the lock, and either line~3 or~7 releases it.
-Line~2 checks to see if the device is being removed, and, if so,
-line~3 releases the lock and line~4 cancels the I/O, or takes whatever
+\begin{linelabel}[ln:count:inline:I/O]
+\begin{VerbatimN}[commandchars=\\\[\]]
+read_lock(&mylock); \lnlbl[acq]
+if (removing) { \lnlbl[check]
+ read_unlock(&mylock); \lnlbl[rel1]
+ cancel_io(); \lnlbl[cancel]
+} else {
+ add_count(1); \lnlbl[inc]
+ read_unlock(&mylock); \lnlbl[rel2]
+ do_io(); \lnlbl[do]
+ sub_count(1); \lnlbl[dec]
+}
+\end{VerbatimN}
+\end{linelabel}
+
+\begin{lineref}[ln:count:inline:I/O]
+Line~\lnref{acq} read-acquires the lock, and either
+line~\lnref{rel1} or~\lnref{rel2} releases it.
+Line~\lnref{check} checks to see if the device is being removed, and, if so,
+line~\lnref{rel1} releases the lock and
+line~\lnref{cancel} cancels the I/O, or takes whatever
action is appropriate given that the device is to be removed.
-Otherwise, line~6 increments the access count, line~7 releases the
-lock, line~8 performs the I/O, and line~9 decrements the access count.
+Otherwise, line~\lnref{inc} increments the access count,
+line~\lnref{rel2} releases the
+lock, line~\lnref{do} performs the I/O, and
+line~\lnref{dec} decrements the access count.
+\end{lineref}
\QuickQuiz{}
This is ridiculous!
@@ -2717,27 +2720,27 @@ lock, line~8 performs the I/O, and line~9 decrements the access count.
The code to remove the device might be as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
- 1 write_lock(&mylock);
- 2 removing = 1;
- 3 sub_count(mybias);
- 4 write_unlock(&mylock);
- 5 while (read_count() != 0) {
- 6 poll(NULL, 0, 1);
- 7 }
- 8 remove_device();
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
-
-Line~1 write-acquires the lock and line~4 releases it.
-Line~2 notes that the device is being removed, and the loop spanning
-lines~5-7 wait for any I/O operations to complete.
-Finally, line~8 does any additional processing needed to prepare for
+\begin{linelabel}[ln:count:inline:remove]
+\begin{VerbatimN}[commandchars=\\\[\]]
+write_lock(&mylock); \lnlbl[acq]
+removing = 1; \lnlbl[note]
+sub_count(mybias);
+write_unlock(&mylock); \lnlbl[rel]
+while (read_count() != 0) { \lnlbl[loop:b]
+ poll(NULL, 0, 1);
+} \lnlbl[loop:e]
+remove_device(); \lnlbl[remove]
+\end{VerbatimN}
+\end{linelabel}
+
+\begin{lineref}[ln:count:inline:remove]
+Line~\lnref{acq} write-acquires the lock and
+line~\lnref{rel} releases it.
+Line~\lnref{note} notes that the device is being removed, and the loop spanning
+lines~\lnref{loop:b}-\lnref{loop:e} wait for any I/O operations to complete.
+Finally, line~\lnref{remove} does any additional processing needed to prepare for
device removal.
+\end{lineref}
\QuickQuiz{}
What other issues would need to be accounted for in a real system?
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 2/7] toolsoftrade: Use 'VerbatimU' for inline snippets
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
2018-10-26 15:24 ` [PATCH 1/7] count: Employ new scheme for inline code snippets Akira Yokosawa
@ 2018-10-26 15:24 ` Akira Yokosawa
2018-10-26 15:26 ` [PATCH 3/7] toolsoftrade: Employ new scheme for snippets of lock.c Akira Yokosawa
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:24 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From f65277139c063f4b44987edb0eee40ade1957df2 Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 14:54:14 +0900
Subject: [PATCH 2/7] toolsoftrade: Use 'VerbatimU' for inline snippets
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
toolsoftrade/toolsoftrade.tex | 90 ++++++++++---------------------------------
1 file changed, 20 insertions(+), 70 deletions(-)
diff --git a/toolsoftrade/toolsoftrade.tex b/toolsoftrade/toolsoftrade.tex
index 6896997..601829c 100644
--- a/toolsoftrade/toolsoftrade.tex
+++ b/toolsoftrade/toolsoftrade.tex
@@ -88,14 +88,9 @@ of \co{cat} execute sequentially.
\QuickQuizAnswer{
One straightforward approach is the shell pipeline:
-\begin{minipage}[t]{\columnwidth}
-\vspace{0.1ex}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
grep $pattern1 | sed -e 's/a/b/' | sort
-\end{verbatim}
-\vspace{0.1ex}
-\end{minipage}
+\end{VerbatimU}
For a sufficiently large input file,
\co{grep} will pattern-match in parallel with \co{sed}
@@ -648,15 +643,10 @@ Lines~7-11 create a thread running \co{lock_writer()}.
Lines~12-19 wait for both threads to complete.
The output of this code fragment is as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\scriptsize
-\begin{verbatim}
+\begin{VerbatimU}
Creating two threads using same lock:
lock_reader(): x = 0
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
Because both threads are using the same lock, the \co{lock_reader()}
thread cannot see any of the intermediate values of \co{x} produced
@@ -718,18 +708,13 @@ shows a similar code fragment, but this time using different locks:
\co{lock_writer()}.
The output of this code fragment is as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\scriptsize
-\begin{verbatim}
+\begin{VerbatimU}
Creating two threads w/different locks:
lock_reader(): x = 0
lock_reader(): x = 1
lock_reader(): x = 2
lock_reader(): x = 3
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
Because the two threads are using different locks, they do not exclude
each other, and can run concurrently.
@@ -1144,16 +1129,11 @@ If you instead need the new value, you can instead use the
For example, one could implement \co{__sync_nand_and_fetch()}
in terms of \co{__sync_fetch_and_nand()} as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\scriptsize
-\begin{verbatim}
+\begin{VerbatimU}
tmp = v;
ret = __sync_fetch_and_nand(p, tmp);
ret = ~ret & tmp;
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
It is similarly possible to implement \co{__sync_fetch_and_add()},
\co{__sync_fetch_and_sub()}, and \co{__sync_fetch_and_xor()}
@@ -1615,16 +1595,11 @@ allowing other threads to acquire it.
A spinlock named \co{mutex} may be used to protect a variable
\co{counter} as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
spin_lock(&mutex);
counter++;
spin_unlock(&mutex);
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
\QuickQuiz{}
What problems could occur if the variable {\tt counter} were
@@ -1633,16 +1608,11 @@ spin_unlock(&mutex);
On CPUs with load-store architectures, incrementing {\tt counter}
might compile into something like the following:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
LOAD counter,r0
INC r0
STORE r0,counter
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
On such machines, two threads might simultaneously load the
value of {\tt counter}, each increment it, and each store the
@@ -2505,51 +2475,31 @@ Section~\ref{sec:count:Statistical Counters},
it is helpful to implement such a counter using a per-thread variable.
Such a variable can be defined as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
DEFINE_PER_THREAD(int, counter);
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
The counter must be initialized as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
init_per_thread(counter, 0);
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
A thread can increment its instance of this counter as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
p_counter = &__get_thread_var(counter);
WRITE_ONCE(*p_counter, *p_counter + 1);
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
The value of the counter is then the sum of its instances.
A snapshot of the value of the counter can thus be collected
as follows:
-\vspace{5pt}
-\begin{minipage}[t]{\columnwidth}
-\small
-\begin{verbatim}
+\begin{VerbatimU}
for_each_thread(t)
sum += READ_ONCE(per_thread(counter, t));
-\end{verbatim}
-\end{minipage}
-\vspace{5pt}
+\end{VerbatimU}
Again, it is possible to gain a similar effect using other mechanisms,
but per-thread variables combine convenience and high performance,
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 3/7] toolsoftrade: Employ new scheme for snippets of lock.c
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
2018-10-26 15:24 ` [PATCH 1/7] count: Employ new scheme for inline code snippets Akira Yokosawa
2018-10-26 15:24 ` [PATCH 2/7] toolsoftrade: Use 'VerbatimU' for inline snippets Akira Yokosawa
@ 2018-10-26 15:26 ` Akira Yokosawa
2018-10-26 15:27 ` [PATCH 4/7] toolsoftrade: Employ new scheme for snippet of rwlockscale.c Akira Yokosawa
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:26 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From 4bf3961a5c8501a9983a196119038b74cff7a18d Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 16:23:34 +0900
Subject: [PATCH 3/7] toolsoftrade: Employ new scheme for snippets of lock.c
NOTE: Several "if" statements, which are too wide for 2c layout,
are divided into a statement to get error code and a simple "if"
statement.
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/toolsoftrade/lock.c | 76 +++++++++--------
toolsoftrade/toolsoftrade.tex | 175 +++++++++++-----------------------------
2 files changed, 89 insertions(+), 162 deletions(-)
diff --git a/CodeSamples/toolsoftrade/lock.c b/CodeSamples/toolsoftrade/lock.c
index 6bb3c23..7b56c0f 100644
--- a/CodeSamples/toolsoftrade/lock.c
+++ b/CodeSamples/toolsoftrade/lock.c
@@ -26,62 +26,64 @@
#include <errno.h>
#include "../api.h"
-pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
+//\begin{snippet}[labelbase=ln:toolsoftrade:lock:reader_writer,commandchars=\$\[\]]
+pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER; //\lnlbl{lock_a}
+pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER; //\lnlbl{lock_b}
-int x = 0;
+int x = 0; //\lnlbl{x}
-void *lock_reader(void *arg)
+void *lock_reader(void *arg) //\lnlbl{reader:b}
{
int en;
int i;
int newx = -1;
int oldx = -1;
- pthread_mutex_t *pmlp = (pthread_mutex_t *)arg;
+ pthread_mutex_t *pmlp = (pthread_mutex_t *)arg; //\lnlbl{reader:cast}
- if ((en = pthread_mutex_lock(pmlp)) != 0) {
+ if ((en = pthread_mutex_lock(pmlp)) != 0) { //\lnlbl{reader:acq:b}
fprintf(stderr, "lock_reader:pthread_mutex_lock: %s\n",
strerror(en));
exit(EXIT_FAILURE);
- }
- for (i = 0; i < 100; i++) {
- newx = READ_ONCE(x);
+ } //\lnlbl{reader:acq:e}
+ for (i = 0; i < 100; i++) { //\lnlbl{reader:loop:b}
+ newx = READ_ONCE(x); //\lnlbl{reader:read_x}
if (newx != oldx) {
printf("lock_reader(): x = %d\n", newx);
}
oldx = newx;
- poll(NULL, 0, 1);
- }
- if ((en = pthread_mutex_unlock(pmlp)) != 0) {
+ poll(NULL, 0, 1); //\lnlbl{reader:sleep}
+ } //\lnlbl{reader:loop:e}
+ if ((en = pthread_mutex_unlock(pmlp)) != 0) { //\lnlbl{reader:rel:b}
fprintf(stderr, "lock_reader:pthread_mutex_lock: %s\n",
strerror(en));
exit(EXIT_FAILURE);
- }
- return NULL;
-}
+ } //\lnlbl{reader:rel:e}
+ return NULL; //\lnlbl{reader:return}
+} //\lnlbl{reader:e}
-void *lock_writer(void *arg)
+void *lock_writer(void *arg) //\lnlbl{writer:b}
{
int en;
int i;
- pthread_mutex_t *pmlp = (pthread_mutex_t *)arg;
+ pthread_mutex_t *pmlp = (pthread_mutex_t *)arg; //\lnlbl{writer:cast}
- if ((en = pthread_mutex_lock(pmlp)) != 0) {
+ if ((en = pthread_mutex_lock(pmlp)) != 0) { //\lnlbl{writer:acq:b}
fprintf(stderr, "lock_writer:pthread_mutex_lock: %s\n",
strerror(en));
exit(EXIT_FAILURE);
- }
- for (i = 0; i < 3; i++) {
- WRITE_ONCE(x, READ_ONCE(x) + 1);
+ } //\lnlbl{writer:acq:e}
+ for (i = 0; i < 3; i++) { //\lnlbl{writer:loop:b}
+ WRITE_ONCE(x, READ_ONCE(x) + 1); //\lnlbl{writer:inc}
poll(NULL, 0, 5);
- }
- if ((en = pthread_mutex_unlock(pmlp)) != 0) {
+ } //\lnlbl{writer:loop:e}
+ if ((en = pthread_mutex_unlock(pmlp)) != 0) { //\lnlbl{writer:rel:b}
fprintf(stderr, "lock_writer:pthread_mutex_lock: %s\n",
strerror(en));
exit(EXIT_FAILURE);
- }
+ } //\lnlbl{writer:rel:e}
return NULL;
-}
+} //\lnlbl{writer:e}
+//\end{snippet}
int main(int argc, char *argv[])
{
@@ -90,31 +92,38 @@ int main(int argc, char *argv[])
pthread_t tid2;
void *vp;
+//\begin{snippet}[labelbase=ln:toolsoftrade:lock:same_lock,commandchars=\$\[\]]
printf("Creating two threads using same lock:\n");
- if ((en = pthread_create(&tid1, NULL, lock_reader, &lock_a)) != 0) {
+ en = pthread_create(&tid1, NULL, lock_reader, &lock_a); //\lnlbl{cr:reader:b}
+ if (en != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(en));
exit(EXIT_FAILURE);
- }
- if ((en = pthread_create(&tid2, NULL, lock_writer, &lock_a)) != 0) {
+ } //\lnlbl{cr:reader:e}
+ en = pthread_create(&tid2, NULL, lock_writer, &lock_a); //\lnlbl{cr:writer:b}
+ if (en != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(en));
exit(EXIT_FAILURE);
- }
- if ((en = pthread_join(tid1, &vp)) != 0) {
+ } //\lnlbl{cr:writer:e}
+ if ((en = pthread_join(tid1, &vp)) != 0) { //\lnlbl{wait:b}
fprintf(stderr, "pthread_join: %s\n", strerror(en));
exit(EXIT_FAILURE);
}
if ((en = pthread_join(tid2, &vp)) != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(en));
exit(EXIT_FAILURE);
- }
+ } //\lnlbl{wait:e}
+//\end{snippet}
+//\begin{snippet}[labelbase=ln:toolsoftrade:lock:diff_lock,commandchars=\$\[\]]
printf("Creating two threads w/different locks:\n");
x = 0;
- if ((en = pthread_create(&tid1, NULL, lock_reader, &lock_a)) != 0) {
+ en = pthread_create(&tid1, NULL, lock_reader, &lock_a);
+ if (en != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(en));
exit(EXIT_FAILURE);
}
- if ((en = pthread_create(&tid2, NULL, lock_writer, &lock_b)) != 0) {
+ en = pthread_create(&tid2, NULL, lock_writer, &lock_b);
+ if (en != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(en));
exit(EXIT_FAILURE);
}
@@ -126,6 +135,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "pthread_join: %s\n", strerror(en));
exit(EXIT_FAILURE);
}
+//\end{snippet}
return EXIT_SUCCESS;
}
diff --git a/toolsoftrade/toolsoftrade.tex b/toolsoftrade/toolsoftrade.tex
index 601829c..e699b6e 100644
--- a/toolsoftrade/toolsoftrade.tex
+++ b/toolsoftrade/toolsoftrade.tex
@@ -460,82 +460,32 @@ lock~\cite{Hoare74}.
} \QuickQuizEnd
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
- 2 pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
- 3 int x = 0;
- 4
- 5 void *lock_reader(void *arg)
- 6 {
- 7 int i;
- 8 int newx = -1;
- 9 int oldx = -1;
- 10 pthread_mutex_t *pmlp = (pthread_mutex_t *)arg;
- 11
- 12 if (pthread_mutex_lock(pmlp) != 0) {
- 13 perror("lock_reader:pthread_mutex_lock");
- 14 exit(EXIT_FAILURE);
- 15 }
- 16 for (i = 0; i < 100; i++) {
- 17 newx = READ_ONCE(x);
- 18 if (newx != oldx) {
- 19 printf("lock_reader(): x = %d\n", newx);
- 20 }
- 21 oldx = newx;
- 22 poll(NULL, 0, 1);
- 23 }
- 24 if (pthread_mutex_unlock(pmlp) != 0) {
- 25 perror("lock_reader:pthread_mutex_unlock");
- 26 exit(EXIT_FAILURE);
- 27 }
- 28 return NULL;
- 29 }
- 30
- 31 void *lock_writer(void *arg)
- 32 {
- 33 int i;
- 34 pthread_mutex_t *pmlp = (pthread_mutex_t *)arg;
- 35
- 36 if (pthread_mutex_lock(pmlp) != 0) {
- 37 perror("lock_writer:pthread_mutex_lock");
- 38 exit(EXIT_FAILURE);
- 39 }
- 40 for (i = 0; i < 3; i++) {
- 41 WRITE_ONCE(x, READ_ONCE(x) + 1);
- 42 poll(NULL, 0, 5);
- 43 }
- 44 if (pthread_mutex_unlock(pmlp) != 0) {
- 45 perror("lock_writer:pthread_mutex_unlock");
- 46 exit(EXIT_FAILURE);
- 47 }
- 48 return NULL;
- 49 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/toolsoftrade/lock@reader_writer.fcv}
\caption{Demonstration of Exclusive Locks}
\label{lst:toolsoftrade:Demonstration of Exclusive Locks}
\end{listing}
+\begin{lineref}[ln:toolsoftrade:lock:reader_writer]
This exclusive-locking property is demonstrated using the code shown in
Listing~\ref{lst:toolsoftrade:Demonstration of Exclusive Locks}
(\path{lock.c}).
-Line~1 defines and initializes a POSIX lock named \co{lock_a}, while
-line~2 similarly defines and initializes a lock named \co{lock_b}.
-Line~3 defines and initializes a shared variable~\co{x}.
+Line~\lnref{lock_a} defines and initializes a POSIX lock named \co{lock_a}, while
+line~\lnref{lock_b} similarly defines and initializes a lock named \co{lock_b}.
+Line~\lnref{x} defines and initializes a shared variable~\co{x}.
+\end{lineref}
-Lines~5-28 defines a function \co{lock_reader()} which repeatedly
+\begin{lineref}[ln:toolsoftrade:lock:reader_writer:reader]
+Lines~\lnref{b}-\lnref{e} defines a function \co{lock_reader()} which repeatedly
reads the shared variable \co{x} while holding
the lock specified by \co{arg}.
-Line~10 casts \co{arg} to a pointer to a \co{pthread_mutex_t}, as
+Line~\lnref{cast} casts \co{arg} to a pointer to a \co{pthread_mutex_t}, as
required by the \co{pthread_mutex_lock()} and \co{pthread_mutex_unlock()}
primitives.
+\end{lineref}
\QuickQuiz{}
Why not simply make the argument to \co{lock_reader()}
- on line~5 of
+ on line~\ref{ln:toolsoftrade:lock:reader_writer:reader:b} of
Listing~\ref{lst:toolsoftrade:Demonstration of Exclusive Locks}
be a pointer to a \co{pthread_mutex_t}?
\QuickQuizAnswer{
@@ -547,9 +497,12 @@ primitives.
} \QuickQuizEnd
\QuickQuiz{}
- What is the \co{READ_ONCE()} on lines~17 and~41 and the
- \co{WRITE_ONCE()} on line~41 of
+ \begin{lineref}[ln:toolsoftrade:lock:reader_writer]
+ What is the \co{READ_ONCE()} on
+ lines~\lnref{reader:read_x} and~\lnref{writer:inc} and the
+ \co{WRITE_ONCE()} on line~\lnref{writer:inc} of
Listing~\ref{lst:toolsoftrade:Demonstration of Exclusive Locks}?
+ \end{lineref}
\QuickQuizAnswer{
These macros constrain the compiler so as to prevent it from
carrying out optimizations that would be problematic for concurrently
@@ -569,16 +522,21 @@ primitives.
Chapter~\ref{chp:Advanced Synchronization: Memory Ordering}.
} \QuickQuizEnd
-Lines~12-15 acquire the specified \co{pthread_mutex_t}, checking
+\begin{lineref}[ln:toolsoftrade:lock:reader_writer:reader]
+Lines~\lnref{acq:b}-\lnref{acq:e} acquire the specified
+\co{pthread_mutex_t}, checking
for errors and exiting the program if any occur.
-Lines~16-23 repeatedly check the value of \co{x}, printing the new value
+Lines~\lnref{loop:b}-\lnref{loop:e} repeatedly check the value of \co{x},
+printing the new value
each time that it changes.
-Line~22 sleeps for one millisecond, which allows this demonstration
+Line~\lnref{sleep} sleeps for one millisecond, which allows this demonstration
to run nicely on a uniprocessor machine.
-Lines~24-27 release the \co{pthread_mutex_t}, again checking for
+Lines~\lnref{rel:b}-\lnref{rel:e} release the \co{pthread_mutex_t},
+again checking for
errors and exiting the program if any occur.
-Finally, line~28 returns \co{NULL}, again to match the function type
+Finally, line~\lnref{return} returns \co{NULL}, again to match the function type
required by \co{pthread_create()}.
+\end{lineref}
\QuickQuiz{}
Writing four lines of code for each acquisition and release
@@ -593,55 +551,39 @@ required by \co{pthread_create()}.
\co{spin_lock()} and \co{spin_unlock()} APIs.
} \QuickQuizEnd
-Lines~31-49 of
+\begin{lineref}[ln:toolsoftrade:lock:reader_writer:writer]
+Lines~\lnref{b}-\lnref{e} of
Listing~\ref{lst:toolsoftrade:Demonstration of Exclusive Locks}
shows \co{lock_writer()}, which
periodically update the shared variable \co{x} while holding the
specified \co{pthread_mutex_t}.
-As with \co{lock_reader()}, line~34 casts \co{arg} to a pointer
-to \co{pthread_mutex_t}, lines~36-39 acquires the specified lock,
-and lines~44-47 releases it.
-While holding the lock, lines~40-43 increment the shared variable \co{x},
+As with \co{lock_reader()}, line~\lnref{cast} casts \co{arg} to a pointer
+to \co{pthread_mutex_t},
+lines~\lnref{acq:b}-\lnref{acq:e} acquires the specified lock,
+and lines~\lnref{rel:b}-\lnref{rel:e} releases it.
+While holding the lock, lines~\lnref{loop:b}-\lnref{loop:e}
+increment the shared variable \co{x},
sleeping for five milliseconds between each increment.
-Finally, lines~44-47 release the lock.
+Finally, lines~\lnref{rel:b}-\lnref{rel:e} release the lock.
+\end{lineref}
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 printf("Creating two threads using same lock:\n");
- 2 if (pthread_create(&tid1, NULL,
- 3 lock_reader, &lock_a) != 0) {
- 4 perror("pthread_create");
- 5 exit(EXIT_FAILURE);
- 6 }
- 7 if (pthread_create(&tid2, NULL,
- 8 lock_writer, &lock_a) != 0) {
- 9 perror("pthread_create");
- 10 exit(EXIT_FAILURE);
- 11 }
- 12 if (pthread_join(tid1, &vp) != 0) {
- 13 perror("pthread_join");
- 14 exit(EXIT_FAILURE);
- 15 }
- 16 if (pthread_join(tid2, &vp) != 0) {
- 17 perror("pthread_join");
- 18 exit(EXIT_FAILURE);
- 19 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/toolsoftrade/lock@same_lock.fcv}
\caption{Demonstration of Same Exclusive Lock}
\label{lst:toolsoftrade:Demonstration of Same Exclusive Lock}
\end{listing}
+\begin{lineref}[ln:toolsoftrade:lock:same_lock]
Listing~\ref{lst:toolsoftrade:Demonstration of Same Exclusive Lock}
shows a code fragment that runs \co{lock_reader()} and
\co{lock_writer()} as threads using the same lock, namely, \co{lock_a}.
-Lines~2-6 create a thread running \co{lock_reader()}, and then
-Lines~7-11 create a thread running \co{lock_writer()}.
-Lines~12-19 wait for both threads to complete.
+Lines~\lnref{cr:reader:b}-\lnref{cr:reader:e} create a thread
+running \co{lock_reader()}, and then
+Lines~\lnref{cr:writer:b}-\lnref{cr:writer:e} create a thread
+running \co{lock_writer()}.
+Lines~\lnref{wait:b}-\lnref{wait:e} wait for both threads to complete.
The output of this code fragment is as follows:
+\end{lineref}
\begin{VerbatimU}
Creating two threads using same lock:
@@ -672,32 +614,7 @@ by \co{lock_writer()} while holding the lock.
} \QuickQuizEnd
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 printf("Creating two threads w/different locks:\n");
- 2 x = 0;
- 3 if (pthread_create(&tid1, NULL,
- 4 lock_reader, &lock_a) != 0) {
- 5 perror("pthread_create");
- 6 exit(EXIT_FAILURE);
- 7 }
- 8 if (pthread_create(&tid2, NULL,
- 9 lock_writer, &lock_b) != 0) {
- 10 perror("pthread_create");
- 11 exit(EXIT_FAILURE);
- 12 }
- 13 if (pthread_join(tid1, &vp) != 0) {
- 14 perror("pthread_join");
- 15 exit(EXIT_FAILURE);
- 16 }
- 17 if (pthread_join(tid2, &vp) != 0) {
- 18 perror("pthread_join");
- 19 exit(EXIT_FAILURE);
- 20 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/toolsoftrade/lock@diff_lock.fcv}
\caption{Demonstration of Different Exclusive Locks}
\label{lst:toolsoftrade:Demonstration of Different Exclusive Locks}
\end{listing}
@@ -761,7 +678,7 @@ values of \co{x} stored by \co{lock_writer()}.
so why does it need to be initialized in
Listing~\ref{lst:toolsoftrade:Demonstration of Different Exclusive Locks}?
\QuickQuizAnswer{
- See line~3 of
+ See line~\ref{ln:toolsoftrade:lock:reader_writer:x} of
Listing~\ref{lst:toolsoftrade:Demonstration of Exclusive Locks}.
Because the code in
Listing~\ref{lst:toolsoftrade:Demonstration of Same Exclusive Lock}
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 4/7] toolsoftrade: Employ new scheme for snippet of rwlockscale.c
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
` (2 preceding siblings ...)
2018-10-26 15:26 ` [PATCH 3/7] toolsoftrade: Employ new scheme for snippets of lock.c Akira Yokosawa
@ 2018-10-26 15:27 ` Akira Yokosawa
2018-10-26 15:28 ` [PATCH 5/7] toolsoftrade: Employ new scheme for snippet of compiler barriers Akira Yokosawa
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:27 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From 5f85ee80de39323a192da10c4a25ae8ec0f4cd2c Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 18:00:26 +0900
Subject: [PATCH 4/7] toolsoftrade: Employ new scheme for snippet of rwlockscale.c
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/toolsoftrade/rwlockscale.c | 54 ++++++++++----------
toolsoftrade/toolsoftrade.tex | 93 +++++++++++-----------------------
2 files changed, 57 insertions(+), 90 deletions(-)
diff --git a/CodeSamples/toolsoftrade/rwlockscale.c b/CodeSamples/toolsoftrade/rwlockscale.c
index affb5a2..b46837e 100644
--- a/CodeSamples/toolsoftrade/rwlockscale.c
+++ b/CodeSamples/toolsoftrade/rwlockscale.c
@@ -26,50 +26,52 @@
#include <errno.h>
#include "../api.h"
-pthread_rwlock_t rwl = PTHREAD_RWLOCK_INITIALIZER;
-int holdtime = 0; /* # loops holding lock. */
-int thinktime = 0; /* # loops not holding lock. */
-long long *readcounts;
-int nreadersrunning = 0;
+//\begin{snippet}[labelbase=ln:toolsoftrade:rwlockscale:reader,commandchars=\@\^\$]
+pthread_rwlock_t rwl = PTHREAD_RWLOCK_INITIALIZER; //\lnlbl{rwlock}
+int holdtime = 0; /* # loops holding lock. */ //\lnlbl{holdtm}
+int thinktime = 0; /* # loops not holding lock. */ //\lnlbl{thinktm}
+long long *readcounts; //\lnlbl{rdcnts}
+int nreadersrunning = 0; //\lnlbl{nrdrun}
-#define GOFLAG_INIT 0
+#define GOFLAG_INIT 0 //\lnlbl{goflag:b}
#define GOFLAG_RUN 1
#define GOFLAG_STOP 2
-char goflag = GOFLAG_INIT;
+char goflag = GOFLAG_INIT; //\lnlbl{goflag:e}
-void *reader(void *arg)
+void *reader(void *arg) //\lnlbl{reader:b}
{
int en;
int i;
long long loopcnt = 0;
long me = (long)arg;
- __sync_fetch_and_add(&nreadersrunning, 1);
- while (READ_ONCE(goflag) == GOFLAG_INIT) {
+ __sync_fetch_and_add(&nreadersrunning, 1); //\lnlbl{reader:atmc_inc}
+ while (READ_ONCE(goflag) == GOFLAG_INIT) { //\lnlbl{reader:wait:b}
continue;
- }
- while (READ_ONCE(goflag) == GOFLAG_RUN) {
- if ((en = pthread_rwlock_rdlock(&rwl)) != 0) {
+ } //\lnlbl{reader:wait:e}
+ while (READ_ONCE(goflag) == GOFLAG_RUN) { //\lnlbl{reader:loop:b}
+ if ((en = pthread_rwlock_rdlock(&rwl)) != 0) { //\lnlbl{reader:acq:b}
fprintf(stderr,
- "pthread_rwlock_rdlock: %s\n", strerror(en));
+ "pthread_rwlock_rdlock: %s\n", strerror(en));
exit(EXIT_FAILURE);
- }
- for (i = 1; i < holdtime; i++) {
+ } //\lnlbl{reader:acq:e}
+ for (i = 1; i < holdtime; i++) { //\lnlbl{reader:hold:b}
barrier();
- }
- if ((en = pthread_rwlock_unlock(&rwl)) != 0) {
+ } //\lnlbl{reader:hold:e}
+ if ((en = pthread_rwlock_unlock(&rwl)) != 0) { //\lnlbl{reader:rel:b}
fprintf(stderr,
"pthread_rwlock_unlock: %s\n", strerror(en));
exit(EXIT_FAILURE);
- }
- for (i = 1; i < thinktime; i++) {
+ } //\lnlbl{reader:rel:e}
+ for (i = 1; i < thinktime; i++) { //\lnlbl{reader:think:b}
barrier();
- }
- loopcnt++;
- }
- readcounts[me] = loopcnt;
- return NULL;
-}
+ } //\lnlbl{reader:think:e}
+ loopcnt++; //\lnlbl{reader:count}
+ } //\lnlbl{reader:loop:e}
+ readcounts[me] = loopcnt; //\lnlbl{reader:mov_cnt}
+ return NULL; //\lnlbl{reader:return}
+} //\lnlbl{reader:e}
+//\end{snippet}
int main(int argc, char *argv[])
{
diff --git a/toolsoftrade/toolsoftrade.tex b/toolsoftrade/toolsoftrade.tex
index e699b6e..d808df6 100644
--- a/toolsoftrade/toolsoftrade.tex
+++ b/toolsoftrade/toolsoftrade.tex
@@ -722,87 +722,47 @@ However, in practice, we need to know how much additional scalability is
provided by reader-writer locks.
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 pthread_rwlock_t rwl = PTHREAD_RWLOCK_INITIALIZER;
- 2 int holdtime = 0;
- 3 int thinktime = 0;
- 4 long long *readcounts;
- 5 int nreadersrunning = 0;
- 6
- 7 #define GOFLAG_INIT 0
- 8 #define GOFLAG_RUN 1
- 9 #define GOFLAG_STOP 2
- 10 char goflag = GOFLAG_INIT;
- 11
- 12 void *reader(void *arg)
- 13 {
- 14 int i;
- 15 long long loopcnt = 0;
- 16 long me = (long)arg;
- 17
- 18 __sync_fetch_and_add(&nreadersrunning, 1);
- 19 while (READ_ONCE(goflag) == GOFLAG_INIT) {
- 20 continue;
- 21 }
- 22 while (READ_ONCE(goflag) == GOFLAG_RUN) {
- 23 if (pthread_rwlock_rdlock(&rwl) != 0) {
- 24 perror("pthread_rwlock_rdlock");
- 25 exit(EXIT_FAILURE);
- 26 }
- 27 for (i = 1; i < holdtime; i++) {
- 28 barrier();
- 29 }
- 30 if (pthread_rwlock_unlock(&rwl) != 0) {
- 31 perror("pthread_rwlock_unlock");
- 32 exit(EXIT_FAILURE);
- 33 }
- 34 for (i = 1; i < thinktime; i++) {
- 35 barrier();
- 36 }
- 37 loopcnt++;
- 38 }
- 39 readcounts[me] = loopcnt;
- 40 return NULL;
- 41 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/toolsoftrade/rwlockscale@reader.fcv}
\caption{Measuring Reader-Writer Lock Scalability}
\label{lst:toolsoftrade:Measuring Reader-Writer Lock Scalability}
\end{listing}
+\begin{lineref}[ln:toolsoftrade:rwlockscale:reader]
Listing~\ref{lst:toolsoftrade:Measuring Reader-Writer Lock Scalability}
(\path{rwlockscale.c})
shows one way of measuring reader-writer lock scalability.
-Line~1 shows the definition and initialization of the reader-writer
-lock, line~2 shows the \co{holdtime} argument controlling the
+Line~\lnref{rwlock} shows the definition and initialization of the reader-writer
+lock, line~\lnref{holdtm} shows the \co{holdtime} argument controlling the
time each thread holds the reader-writer lock,
-line~3 shows the \co{thinktime} argument controlling the time between
+line~\lnref{thinktm} shows the \co{thinktime} argument controlling the time between
the release of the reader-writer lock and the next acquisition,
-line~4 defines the \co{readcounts} array into which each reader thread
+line~\lnref{rdcnts} defines the \co{readcounts} array into which each reader thread
places the number of times it acquired the lock, and
-line~5 defines the \co{nreadersrunning} variable, which
+line~\lnref{nrdrun} defines the \co{nreadersrunning} variable, which
determines when all reader threads have started running.
-Lines~7-10 define \co{goflag}, which synchronizes the start and the
+Lines~\lnref{goflag:b}-\lnref{goflag:e} define \co{goflag},
+which synchronizes the start and the
end of the test.
This variable is initially set to \co{GOFLAG_INIT}, then set to
\co{GOFLAG_RUN} after all the reader threads have started, and finally
set to \co{GOFLAG_STOP} to terminate the test run.
+\end{lineref}
-Lines~12-41 define \co{reader()}, which is the reader thread.
-Line~18 atomically increments the \co{nreadersrunning} variable
+\begin{lineref}[ln:toolsoftrade:rwlockscale:reader:reader]
+Lines~\lnref{b}-\lnref{e} define \co{reader()}, which is the reader thread.
+Line~\lnref{atmc_inc} atomically increments the \co{nreadersrunning} variable
to indicate that this thread is now running, and
-lines~19-21 wait for the test to start.
+lines~\lnref{wait:b}-\lnref{wait:e} wait for the test to start.
The \co{READ_ONCE()} primitive forces the compiler to fetch \co{goflag}
on each pass through the loop---the compiler would otherwise be within its
rights to assume that the value of \co{goflag} would never change.
+\end{lineref}
\QuickQuiz{}
Instead of using \co{READ_ONCE()} everywhere, why not just
- declare \co{goflag} as \co{volatile} on line~10 of
+ declare \co{goflag} as \co{volatile} on
+ line~\ref{ln:toolsoftrade:rwlockscale:reader:goflag:e} of
Listing~\ref{lst:toolsoftrade:Measuring Reader-Writer Lock Scalability}?
\QuickQuizAnswer{
A \co{volatile} declaration is in fact a reasonable alternative in
@@ -867,16 +827,21 @@ rights to assume that the value of \co{goflag} would never change.
\co{__thread} variable in the corresponding element.
} \QuickQuizEnd
-The loop spanning lines~22-38 carries out the performance test.
-Lines~23-26 acquire the lock, lines~27-29 hold the lock for the specified
+\begin{lineref}[ln:toolsoftrade:rwlockscale:reader:reader]
+The loop spanning lines~\lnref{loop:b}-\lnref{loop:e} carries out the performance test.
+Lines~\lnref{acq:b}-\lnref{acq:e} acquire the lock,
+lines~\lnref{hold:b}-\lnref{hold:e} hold the lock for the specified
duration (and the \co{barrier()} directive prevents the compiler from
-optimizing the loop out of existence), lines~30-33 release the lock,
-and lines~34-36 wait for the specified duration before re-acquiring the
+optimizing the loop out of existence),
+lines~\lnref{rel:b}-\lnref{rel:e} release the lock,
+and lines~\lnref{think:b}-\lnref{think:e} wait for the specified
+duration before re-acquiring the
lock.
-Line~37 counts this lock acquisition.
+Line~\lnref{count} counts this lock acquisition.
-Line~39 moves the lock-acquisition count to this thread's element of the
-\co{readcounts[]} array, and line~40 returns, terminating this thread.
+Line~\lnref{mov_cnt} moves the lock-acquisition count to this thread's element of the
+\co{readcounts[]} array, and line~\lnref{return} returns, terminating this thread.
+\end{lineref}
\begin{figure}[tb]
\centering
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 5/7] toolsoftrade: Employ new scheme for snippet of compiler barriers
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
` (3 preceding siblings ...)
2018-10-26 15:27 ` [PATCH 4/7] toolsoftrade: Employ new scheme for snippet of rwlockscale.c Akira Yokosawa
@ 2018-10-26 15:28 ` Akira Yokosawa
2018-10-26 15:29 ` [PATCH 6/7] toolsoftrade: Employ new scheme for snippets of threadcreate.c Akira Yokosawa
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:28 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From 65dac5efc38d7dbb1710d727bc6b67732ce8968c Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 18:11:20 +0900
Subject: [PATCH 5/7] toolsoftrade: Employ new scheme for snippet of compiler barriers
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/api-pthreads/api-pthreads.h | 7 +++++--
toolsoftrade/toolsoftrade.tex | 12 +-----------
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/CodeSamples/api-pthreads/api-pthreads.h b/CodeSamples/api-pthreads/api-pthreads.h
index 6bde0c9..f5510f0 100644
--- a/CodeSamples/api-pthreads/api-pthreads.h
+++ b/CodeSamples/api-pthreads/api-pthreads.h
@@ -53,7 +53,6 @@
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif /* #ifndef offsetof */
-#define barrier() __asm__ __volatile__("": : :"memory")
/*
* Default machine parameters.
@@ -133,9 +132,13 @@ static __inline__ int spin_is_locked(spinlock_t *sp)
#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0)
#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0)
+//\begin{snippet}[labelbase=ln:api-pthreads:api-pthreads:compiler_barrier,commandchars=\@\[\],numbers=none]
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
-#define READ_ONCE(x) ({ typeof(x) ___x = ACCESS_ONCE(x); ___x; })
+#define READ_ONCE(x) \
+ ({ typeof(x) ___x = ACCESS_ONCE(x); ___x; })
#define WRITE_ONCE(x, val) ({ ACCESS_ONCE(x) = (val); })
+#define barrier() __asm__ __volatile__("": : :"memory")
+//\end{snippet}
#ifndef unlikely
#define unlikely(x) x
#endif /* #ifndef unlikely */
diff --git a/toolsoftrade/toolsoftrade.tex b/toolsoftrade/toolsoftrade.tex
index d808df6..f1a96ff 100644
--- a/toolsoftrade/toolsoftrade.tex
+++ b/toolsoftrade/toolsoftrade.tex
@@ -1076,17 +1076,7 @@ and all three are discussed at length in
Section~\ref{sec:toolsoftrade:Accessing Shared Variables}.
\begin{listing}[tb]
-{ \scriptsize
-\begin{verbbox}
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
-#define READ_ONCE(x) \
- ({ typeof(x) ___x = ACCESS_ONCE(x); ___x; })
-#define WRITE_ONCE(x, val) ({ ACCESS_ONCE(x) = (val); })
-#define barrier() __asm__ __volatile__("": : :"memory")
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/api-pthreads/api-pthreads@compiler_barrier.fcv}
\caption{Compiler Barrier Primitive (for \GCC)}
\label{lst:toolsoftrade:Compiler Barrier Primitive (for GCC)}
\end{listing}
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 6/7] toolsoftrade: Employ new scheme for snippets of threadcreate.c
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
` (4 preceding siblings ...)
2018-10-26 15:28 ` [PATCH 5/7] toolsoftrade: Employ new scheme for snippet of compiler barriers Akira Yokosawa
@ 2018-10-26 15:29 ` Akira Yokosawa
2018-10-26 15:30 ` [PATCH 7/7] count: Fix indent in count_lim_atomic.c Akira Yokosawa
2018-10-26 15:35 ` [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:29 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From 334b421f68729c28fac868f5d89af6d4aa6d1090 Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sun, 14 Oct 2018 20:47:07 +0900
Subject: [PATCH 6/7] toolsoftrade: Employ new scheme for snippets of threadcreate.c
Also convert snippets of thread API, locking API, and per-thread API.
As the snippet of thread API fits the column width of 2c layout,
use "listing" environment instead of "listing*".
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/intro/threadcreate.c | 20 +++++----
toolsoftrade/toolsoftrade.tex | 90 ++++++++++------------------------------
2 files changed, 34 insertions(+), 76 deletions(-)
diff --git a/CodeSamples/intro/threadcreate.c b/CodeSamples/intro/threadcreate.c
index 94cde89..381742a 100644
--- a/CodeSamples/intro/threadcreate.c
+++ b/CodeSamples/intro/threadcreate.c
@@ -20,14 +20,16 @@
#include "../api.h"
+//\begin{snippet}[labelbase=ln:intro:threadcreate:thread_test,commandchars=\@\[\]]
void *thread_test(void *arg)
{
int myarg = (intptr_t)arg;
printf("child thread %d: smp_thread_id() = %d\n",
myarg, smp_thread_id());
- return NULL;
+ return NULL; //\lnlbl{return}
}
+//\end{snippet}
void usage(char *progname)
{
@@ -36,29 +38,31 @@ void usage(char *progname)
exit(-1);
}
+//\begin{snippet}[labelbase=ln:intro:threadcreate:main,commandchars=\@\^\$]
int main(int argc, char *argv[])
{
int i;
int nkids = 1;
- smp_init();
+ smp_init(); //\lnlbl{smp_init}
- if (argc > 1) {
+ if (argc > 1) { //\lnlbl{parse:b}
nkids = strtoul(argv[1], NULL, 0);
if (nkids > NR_THREADS) {
fprintf(stderr, "nkids = %d too large, max = %d\n",
nkids, NR_THREADS);
usage(argv[0]);
}
- }
- printf("Parent thread spawning %d threads.\n", nkids);
+ } //\lnlbl{parse:e}
+ printf("Parent thread spawning %d threads.\n", nkids); //\lnlbl{announce}
- for (i = 0; i < nkids; i++)
- create_thread(thread_test, (void *)(intptr_t)i);
+ for (i = 0; i < nkids; i++) //\lnlbl{create:b}
+ create_thread(thread_test, (void *)(intptr_t)i); //\lnlbl{create:e}
- wait_all_threads();
+ wait_all_threads(); //\lnlbl{wait}
printf("All spawned threads completed.\n");
exit(0);
}
+//\end{snippet}
diff --git a/toolsoftrade/toolsoftrade.tex b/toolsoftrade/toolsoftrade.tex
index f1a96ff..12dabd0 100644
--- a/toolsoftrade/toolsoftrade.tex
+++ b/toolsoftrade/toolsoftrade.tex
@@ -1247,22 +1247,18 @@ The thread API is shown in
Listing~\ref{lst:toolsoftrade:Thread API}, and members are described in the
following sections.
-\begin{listing*}[tbp]
-{ \scriptsize
-\begin{verbbox}
+\begin{listing}[tbp]
+\begin{VerbatimL}[numbers=none,xleftmargin=2pt]
int smp_thread_id(void)
thread_id_t create_thread(void *(*func)(void *), void *arg)
for_each_thread(t)
for_each_running_thread(t)
void *wait_thread(thread_id_t tid)
void wait_all_threads(void)
-\end{verbbox}
-}
-\centering
-\theverbbox
+\end{VerbatimL}
\caption{Thread API}
\label{lst:toolsoftrade:Thread API}
-\end{listing*}
+\end{listing}
\subsubsection{\tco{create_thread()}}
@@ -1327,73 +1323,39 @@ a run, so such synchronization is normally not needed.
\subsubsection{Example Usage}
-Listing~\ref{lst:toolsoftrade:Example Child Thread}
+Listing~\ref{lst:toolsoftrade:Example Child Thread} (\path{threadcreate.c})
shows an example hello-world-like child thread.
As noted earlier, each thread is allocated its own stack, so
each thread has its own private \co{arg} argument and \co{myarg} variable.
Each child simply prints its argument and its \co{smp_thread_id()}
before exiting.
-Note that the \co{return} statement on line~7 terminates the thread,
+Note that the \co{return} statement on
+line~\ref{ln:intro:threadcreate:thread_test:return} terminates the thread,
returning a \co{NULL} to whoever invokes \co{wait_thread()} on this
thread.
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 void *thread_test(void *arg)
- 2 {
- 3 int myarg = (int)arg;
- 4
- 5 printf("child thread %d: smp_thread_id() = %d\n",
- 6 myarg, smp_thread_id());
- 7 return NULL;
- 8 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/intro/threadcreate@thread_test.fcv}
\caption{Example Child Thread}
\label{lst:toolsoftrade:Example Child Thread}
\end{listing}
+\begin{lineref}[ln:intro:threadcreate:main]
The parent program is shown in
Listing~\ref{lst:toolsoftrade:Example Parent Thread}.
It invokes \co{smp_init()} to initialize the threading system on
-line~6,
-parses arguments on lines~7-14, and announces its presence on line~15.
-It creates the specified number of child threads on lines~16-17,
-and waits for them to complete on line~18.
+line~\lnref{smp_init},
+parses arguments on lines~\lnref{parse:b}-\lnref{parse:e},
+and announces its presence on line~\lnref{announce}.
+It creates the specified number of child threads on
+lines~\lnref{create:b}-\lnref{create:e},
+and waits for them to complete on line~\lnref{wait}.
Note that \co{wait_all_threads()} discards the threads return values,
as in this case they are all \co{NULL}, which is not very interesting.
+\end{lineref}
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
- 1 int main(int argc, char *argv[])
- 2 {
- 3 int i;
- 4 int nkids = 1;
- 5
- 6 smp_init();
- 7 if (argc > 1) {
- 8 nkids = strtoul(argv[1], NULL, 0);
- 9 if (nkids > NR_THREADS) {
- 10 fprintf(stderr, "nkids=%d too big, max=%d\n",
- 11 nkids, NR_THREADS);
- 12 usage(argv[0]);
- 13 }
- 14 }
- 15 printf("Parent spawning %d threads.\n", nkids);
- 16 for (i = 0; i < nkids; i++)
- 17 create_thread(thread_test, (void *)i);
- 18 wait_all_threads();
- 19 printf("All threads completed.\n", nkids);
- 20 return EXIT_SUCCESS;
- 21 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/intro/threadcreate@main.fcv}
\caption{Example Parent Thread}
\label{lst:toolsoftrade:Example Parent Thread}
\end{listing}
@@ -1417,16 +1379,12 @@ each API element being described in the following sections.
This book's CodeSamples locking API closely follows that of the Linux kernel.
\begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
+\begin{VerbatimL}[numbers=none]
void spin_lock_init(spinlock_t *sp);
void spin_lock(spinlock_t *sp);
int spin_trylock(spinlock_t *sp);
void spin_unlock(spinlock_t *sp);
-\end{verbbox}
-}
-\centering
-\theverbbox
+\end{VerbatimL}
\caption{Locking API}
\label{lst:toolsoftrade:Locking API}
\end{listing}
@@ -2271,18 +2229,14 @@ Although this API is, strictly speaking, not necessary\footnote{
You could instead use \co{__thread} or \co{_Thread_local}.},
it can provide a good userspace analogy to Linux kernel code.
-\begin{listing}[htbp]
-{ \scriptsize
-\begin{verbbox}
+\begin{listing}[tbp]
+\begin{VerbatimL}[numbers=none]
DEFINE_PER_THREAD(type, name)
DECLARE_PER_THREAD(type, name)
per_thread(name, thread)
__get_thread_var(name)
init_per_thread(name, v)
-\end{verbbox}
-}
-\centering
-\theverbbox
+\end{VerbatimL}
\caption{Per-Thread-Variable API}
\label{lst:toolsoftrade:Per-Thread-Variable API}
\end{listing}
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH 7/7] count: Fix indent in count_lim_atomic.c
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
` (5 preceding siblings ...)
2018-10-26 15:29 ` [PATCH 6/7] toolsoftrade: Employ new scheme for snippets of threadcreate.c Akira Yokosawa
@ 2018-10-26 15:30 ` Akira Yokosawa
2018-10-26 15:35 ` [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
7 siblings, 0 replies; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:30 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
From 453bc63fd38da42f52eb88b4fed0a38b0f431cf9 Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Sat, 20 Oct 2018 07:50:26 +0900
Subject: [PATCH 7/7] count: Fix indent in count_lim_atomic.c
Commit 51e9218ac25e ("count: Employ new scheme for snippet of
count_lim_atomic") changed indent width by accident. Fix it.
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/count/count_lim_atomic.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CodeSamples/count/count_lim_atomic.c b/CodeSamples/count/count_lim_atomic.c
index 6190a9f..02f4e6d 100644
--- a/CodeSamples/count/count_lim_atomic.c
+++ b/CodeSamples/count/count_lim_atomic.c
@@ -137,7 +137,7 @@ int sub_count(unsigned long delta) //\lnlbl{sub:b}
do { //\lnlbl{sub:fast:b}
split_counterandmax(&counterandmax, &old, &c, &cm);
if (delta > c)
- goto slowpath;
+ goto slowpath;
new = merge_counterandmax(c - delta, cm);
} while (atomic_cmpxchg(&counterandmax,
old, new) != old);
--
2.7.4
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.)
2018-10-26 15:22 [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
` (6 preceding siblings ...)
2018-10-26 15:30 ` [PATCH 7/7] count: Fix indent in count_lim_atomic.c Akira Yokosawa
@ 2018-10-26 15:35 ` Akira Yokosawa
2018-10-26 20:58 ` Paul E. McKenney
7 siblings, 1 reply; 10+ messages in thread
From: Akira Yokosawa @ 2018-10-26 15:35 UTC (permalink / raw)
To: Paul E. McKenney; +Cc: perfbook, Akira Yokosawa
On 2018/10/27 00:22:37 +0900, Akira Yokosawa wrote:
> Hi Paul,
>
> This is a set of simple conversions of code snippets to the new scheme
> in count and toolsoftrade. There is no change in the code under CodeSamples,
> but there are a few visual changes in the pdf output which reflect the
> actual code samples.
I forgot to mention that Patch #3 contains minor changes in the code to
reduce width of code snippets.
Thanks, Akira
>
> Patch #7 fixes an unintended change in indent width made in the previous
> patch set.
>
> Thanks, Akira
> --
> Akira Yokosawa (7):
> count: Employ new scheme for inline code snippets
> toolsoftrade: Use 'VerbatimU' for inline snippets
> toolsoftrade: Employ new scheme for snippets of lock.c
> toolsoftrade: Employ new scheme for snippet of rwlockscale.c
> toolsoftrade: Employ new scheme for snippet of compiler barriers
> toolsoftrade: Employ new scheme for snippets of threadcreate.c
> count: Fix indent in count_lim_atomic.c
>
> CodeSamples/api-pthreads/api-pthreads.h | 7 +-
> CodeSamples/count/count_lim_atomic.c | 2 +-
> CodeSamples/intro/threadcreate.c | 20 +-
> CodeSamples/toolsoftrade/lock.c | 76 +++---
> CodeSamples/toolsoftrade/rwlockscale.c | 54 ++--
> count/count.tex | 89 +++---
> toolsoftrade/toolsoftrade.tex | 460 ++++++++------------------------
> 7 files changed, 253 insertions(+), 455 deletions(-)
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.)
2018-10-26 15:35 ` [PATCH 0/7] count, toolsoftrade: Employ new code-snippet scheme (cont.) Akira Yokosawa
@ 2018-10-26 20:58 ` Paul E. McKenney
0 siblings, 0 replies; 10+ messages in thread
From: Paul E. McKenney @ 2018-10-26 20:58 UTC (permalink / raw)
To: Akira Yokosawa; +Cc: perfbook
On Sat, Oct 27, 2018 at 12:35:10AM +0900, Akira Yokosawa wrote:
> On 2018/10/27 00:22:37 +0900, Akira Yokosawa wrote:
> > Hi Paul,
> >
> > This is a set of simple conversions of code snippets to the new scheme
> > in count and toolsoftrade. There is no change in the code under CodeSamples,
> > but there are a few visual changes in the pdf output which reflect the
> > actual code samples.
>
> I forgot to mention that Patch #3 contains minor changes in the code to
> reduce width of code snippets.
>
> Thanks, Akira
>
> >
> > Patch #7 fixes an unintended change in indent width made in the previous
> > patch set.
> >
> > Thanks, Akira
I applied and pushed this series, thank you!
Thanx, Paul
> > --
> > Akira Yokosawa (7):
> > count: Employ new scheme for inline code snippets
> > toolsoftrade: Use 'VerbatimU' for inline snippets
> > toolsoftrade: Employ new scheme for snippets of lock.c
> > toolsoftrade: Employ new scheme for snippet of rwlockscale.c
> > toolsoftrade: Employ new scheme for snippet of compiler barriers
> > toolsoftrade: Employ new scheme for snippets of threadcreate.c
> > count: Fix indent in count_lim_atomic.c
> >
> > CodeSamples/api-pthreads/api-pthreads.h | 7 +-
> > CodeSamples/count/count_lim_atomic.c | 2 +-
> > CodeSamples/intro/threadcreate.c | 20 +-
> > CodeSamples/toolsoftrade/lock.c | 76 +++---
> > CodeSamples/toolsoftrade/rwlockscale.c | 54 ++--
> > count/count.tex | 89 +++---
> > toolsoftrade/toolsoftrade.tex | 460 ++++++++------------------------
> > 7 files changed, 253 insertions(+), 455 deletions(-)
> >
>
^ permalink raw reply [flat|nested] 10+ messages in thread