perfbook_html/0000755000175000017500000000000011672746164013601 5ustar paulmckpaulmckperfbook_html/images.tex0000644000175000017500000055331511672745743015606 0ustar paulmckpaulmck\batchmode \documentclass[10pt,twocolumn]{book} \usepackage{lscape} \usepackage{epsfig} \usepackage{subfigure} \usepackage{url} \usepackage{graphics} \usepackage{enumerate} \usepackage{ifthen} \usepackage{listings} \lstset{basicstyle=\ttfamily } \usepackage[bookmarks=true,bookmarksnumbered=true]{hyperref} \newcounter{quickquizctr} \chapter{#2} \label{#1} \setcounter{quickquizctr}{0} \refstepcounter{quickquizctr} \textbf{Quick Quiz \thechapter .\arabic{quickquizctr}:} \chapter{Answers to Quick Quizzes} \label{chp:Answers to Quick Quizzes} ~ \\ % % \renewcommand{\QuickQuizAnswerChapter}{\ref{#1}} \setcounter{quickquizctr}{0} \section{#2} \refstepcounter{quickquizctr} ~ \\~ \\ \textbf{Quick Quiz \ref{#1}.\arabic{quickquizctr}:} #1 ~ \\ \begin{enumerate} % \item Section~\ref{sec:intro:What Makes Parallel Programming Hard?} (``What Makes Parallel Programming Hard?'') on page~\pageref{sec:intro:What Makes Parallel Programming Hard?} originally appeared in a Portland State University Technical Report~\cite{PaulEMcKenney2009ProgrammingHard}. \item Section~\ref{sec:defer:RCU Fundamentals} (``RCU Fundamentals'') on page~\pageref{sec:defer:RCU Fundamentals} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2007WhatIsRCUFundamentally}. \item Section~\ref{sec:defer:RCU Usage} (``RCU Usage'') on page~\pageref{sec:defer:RCU Usage} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2008WhatIsRCUUsage}. \item Section~\ref{sec:defer:RCU Linux-Kernel API} (``RCU Linux-Kernel API'') on page~\pageref{sec:defer:RCU Linux-Kernel API} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2008WhatIsRCUAPI}. \item Section~\ref{sec:app:whymb:Memory-Barrier Instructions For Specific CPUs} (``Memory-Barrier Instructions For Specific CPUs'') on page~\pageref{sec:app:whymb:Memory-Barrier Instructions For Specific CPUs} originally appeared in Linux Journal~\cite{PaulMcKenney2005i,PaulMcKenney2005j}. \item Section~\ref{app:rcuimpl:Sleepable RCU Implementation} (``Sleepable RCU Implementation'') on page~\pageref{app:rcuimpl:Sleepable RCU Implementation} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2006c}. \item Section~\ref{app:rcuimpl:rcutree:Hierarchical RCU Overview} (``Hierarchical RCU Overview'') on page~\pageref{app:rcuimpl:rcutree:Hierarchical RCU Overview} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2008HierarchicalRCU}. \item Section~\ref{app:rcuimpl:Preemptible RCU} (``Preemptible RCU'') on page~\pageref{app:rcuimpl:Preemptible RCU} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2007PreemptibleRCU}. \item Appendix~\ref{app:formal:Formal Verification} (``Formal Verification'') on page~\pageref{app:formal:Formal Verification} originally appeared in Linux Weekly News~\cite{PaulEMcKenney2007QRCUspin,PaulEMcKenney2008dynticksRCU}. \end{enumerate} \begin{enumerate} % \item Figure~\ref{fig:cpu:CPU Performance at its Best} (p~\pageref{fig:cpu:CPU Performance at its Best}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPUs Old and New} (p~\pageref{fig:cpu:CPUs Old and New}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Meets a Pipeline Flush} (p~\pageref{fig:cpu:CPU Meets a Pipeline Flush}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Meets a Memory Reference} (p~\pageref{fig:cpu:CPU Meets a Memory Reference}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Meets an Atomic Operation} (p~\pageref{fig:cpu:CPU Meets an Atomic Operation}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Meets a Memory Barrier} (p~\pageref{fig:cpu:CPU Meets a Memory Barrier}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Meets a Cache Miss} (p~\pageref{fig:cpu:CPU Meets a Cache Miss}) by Melissa McKenney. \item Figure~\ref{fig:cpu:CPU Waits for I/O Completion} (p~\pageref{fig:cpu:CPU Waits for I/O Completion}) by Melissa McKenney. \item Figure~\ref{fig:SMPdesign:Dining Philosophers Problem} (p~\pageref{fig:SMPdesign:Dining Philosophers Problem}) by Kornilios Kourtis. \item Figure~\ref{fig:SMPdesign:Dining Philosophers Problem, Textbook Solution} (p~\pageref{fig:SMPdesign:Dining Philosophers Problem, Textbook Solution}) by Kornilios Kourtis. \item Figure~\ref{fig:SMPdesign:Dining Philosophers Problem, Partitioned} (p~\pageref{fig:SMPdesign:Dining Philosophers Problem, Partitioned}) by Kornilios Kourtis. \item Figure~\ref{fig:SMPdesign:Lock Contention} (p~\pageref{fig:SMPdesign:Lock Contention}) by Melissa McKenney. \item Figure~\ref{fig:SMPdesign:Data Locking} (p~\pageref{fig:SMPdesign:Data Locking}) by Melissa McKenney. \item Figure~\ref{fig:SMPdesign:Data and Skew} (p~\pageref{fig:SMPdesign:Data and Skew}) by Melissa McKenney. \item Figure~\ref{fig:advsync:CPUs Can Do Things Out of Order} (p~\pageref{fig:advsync:CPUs Can Do Things Out of Order}) by Melissa McKenney. \item Figure~\ref{fig:advsync:Abstract Memory Access Model} (p~\pageref{fig:advsync:Abstract Memory Access Model}) by David Howells. \item Figure~\ref{fig:advsync:Write Barrier Ordering Semantics} (p~\pageref{fig:advsync:Write Barrier Ordering Semantics}) by David Howells. \item Figure~\ref{fig:advsync:Data Dependency Barrier Omitted} (p~\pageref{fig:advsync:Data Dependency Barrier Omitted}) by David Howells. \item Figure~\ref{fig:advsync:Data Dependency Barrier Supplied} (p~\pageref{fig:advsync:Data Dependency Barrier Supplied}) by David Howells. \item Figure~\ref{fig:advsync:Read Barrier Needed} (p~\pageref{fig:advsync:Read Barrier Needed}) by David Howells. \item Figure~\ref{fig:advsync:Read Barrier Supplied} (p~\pageref{fig:advsync:Read Barrier Supplied}) by David Howells. \item Figure~\ref{fig:advsync:Read Barrier Supplied, Double Load} (p~\pageref{fig:advsync:Read Barrier Supplied, Double Load}) by David Howells. \item Figure~\ref{fig:advsync:Read Barrier Supplied, Take Two} (p~\pageref{fig:advsync:Read Barrier Supplied, Take Two}) by David Howells. \item Figure~\ref{fig:advsync:Speculative Load} (p~\pageref{fig:advsync:Speculative Load}) by David Howells. \item Figure~\ref{fig:advsync:Speculative Loads and Barrier} (p~\pageref{fig:advsync:Speculative Loads and Barrier}) by David Howells. \item Figure~\ref{fig:advsync:Speculative Loads Cancelled by Barrier} (p~\pageref{fig:advsync:Speculative Loads Cancelled by Barrier}) by David Howells. \item Figure~\ref{fig:advsync:Memory Architecture} (p~\pageref{fig:advsync:Memory Architecture}) by David Howells. \item Figure~\ref{fig:advsync:Split Caches} (p~\pageref{fig:advsync:Split Caches}) by David Howells. \item Figure~\ref{fig:easy:Shaving the Mandelbrot Set} (p~\pageref{fig:easy:Shaving the Mandelbrot Set}) by Melissa McKenney. \item Figure~\ref{fig:app:whymb:Half Memory Barrier} (p~\pageref{fig:app:whymb:Half Memory Barrier}) by Melissa McKenney. \item Figure~\ref{fig:app:rcuimpl:srcu:Sleeping While RCU Reading Considered Harmful} (p~\pageref{fig:app:rcuimpl:srcu:Sleeping While RCU Reading Considered Harmful}) by Melissa McKenney. \item Figure~\ref{fig:SMPdesign:Dining Philosophers Problem, Fully Partitioned} (p~\pageref{fig:SMPdesign:Dining Philosophers Problem, Fully Partitioned}) by Kornilios Kourtis. \end{enumerate} \item #1~\ref{#2} (``#3'') on page~\pageref{#2} originally appeared in #4~\cite{#5}. \item #1~\ref{#2}--\ref{#3} (``#4'') on pages~\pageref{#2}--\pageref{#2} originally appeared in #5~\cite{#6}. \item #1~\ref{#2} (p~\pageref{#2}) by #3. \usepackage[dvips]{color} \pagecolor[gray]{.7} \usepackage[]{inputenc} \makeatletter \makeatletter \count@=\the\catcode`\_ \catcode`\_=8 \newenvironment{tex2html_wrap}{}{}% \catcode`\<=12\catcode`\_=\count@ \newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}% \newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}% \expandafter\renewcommand\csname #1\endcsname}% \newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}% \let\newedcommand\renewedcommand \let\renewedenvironment\newedenvironment \makeatother \let\mathon=$ \let\mathoff=$ \ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi \newbox\sizebox \setlength{\hoffset}{0pt}\setlength{\voffset}{0pt} \addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt} \addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt} \addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt} \addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt} \setlength{\textwidth}{349pt} \newwrite\lthtmlwrite \makeatletter \let\realnormalsize=\normalsize \global\topskip=2sp \def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float \def\@float{\let\@savefreelist\@freelist\real@float} \def\liih@math{\ifmmode$\else\bad@math\fi} \def\end@float{\realend@float\global\let\@freelist\@savefreelist} \let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float \let\@largefloatcheck=\relax \let\if@boxedmulticols=\iftrue \def\@dbflt{\let\@savefreelist\@freelist\real@dbflt} \def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}% \def\phantompar{\csname par\endcsname}\normalsize}% \def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}% \newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }% \newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }% \newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup % \let\ifinner=\iffalse \let\)\liih@math }% \newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}% \expandafter\box\next\egroup}% \newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}% \newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox \ifdim\dimen0>.95\vsize \lthtmltypeout{% *** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}% \ht\sizebox.95\vsize \dp\sizebox\z@ \fi \lthtmltypeout{l2hSize % :\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}% \newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist \lthtmlmathtype{#1}\lthtmlvboxmathA}% \newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}% \newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup \let\@savefreelist\@freelist \lthtmlhboxmathB}% \newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}% \newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox \global\let\@freelist\@savefreelist}% \newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}% \newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}% \newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}% \lthtmldisplayA{#1}\let\@eqnnum\relax}% \newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}% \newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB} \newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA \vrule height1.5ex width0pt }% \newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}% \newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}% \newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt % \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline} \newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt % \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath} \newcommand\lthtmlindisplaymathZ{\egroup % \centerinlinemath\lthtmllogmath\lthtmlsetmath} \def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{% \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}} \def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{% \kern.1em\kern0.8 pt\hbox{\hglue.17em\copy\sizebox\hglue0.8 pt}}\kern.3pt% \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.8 pt% \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}} \def\centerinlinemath{% \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax} \def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill \else\expandafter\vss\fi}% \providecommand{\selectlanguage}[1]{}% \makeatletter \tracingstats = 1 \begin{document} \pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}% \lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}% \makeatletter \if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}% \else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi% \lthtmltypeout{}% \makeatother \setcounter{page}{1} \onecolumn % !!! IMAGES START HERE !!! \setcounter{quickquizctr}{0} \refstepcounter{quickquizctr} \setcounter{quickquizctr}{0} \refstepcounter{quickquizctr} \stepcounter{chapter} \stepcounter{chapter} \stepcounter{section} \setcounter{topnumber}{3} \setcounter{bottomnumber}{2} \setcounter{totalnumber}{5} \setcounter{dbltopnumber}{3} \setlength{\textheight}{8.25in}% \setlength{\textheight}{8.25in} \setlength{\textwidth}{6.5in}% \setlength{\textwidth}{6.5in} \setlength{\columnsep}{0.25in}% \setlength{\columnsep}{0.25in} \newboolean{inbook}% \setcounter{secnumdepth}{3} \setboolean{inbook}{true} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap549}% \resizebox{3in}{!}{\includegraphics{SMPdesign/clockfreq}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap577}% \resizebox{3in}{!}{\includegraphics{SMPdesign/mipsperbuck}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap601}% \resizebox{3in}{!}{\includegraphics{intro/PPGrelation}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap609}% \resizebox{3in}{!}{\includegraphics{intro/Generality}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap675}% \resizebox{3in}{!}{\includegraphics{intro/FourTaskCategories}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap723}% \resizebox{3in}{!}{\includegraphics{intro/FourTaskOrder}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap900}% \resizebox{3in}{!}{\includegraphics{cartoons/trackmeet}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap910}% \resizebox{3in}{!}{\includegraphics{cartoons/whippersnapper}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap920}% \resizebox{3in}{!}{\includegraphics{cartoons/pipeline}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap936}% \resizebox{3in}{!}{\includegraphics{cartoons/ref}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap950}% \resizebox{3in}{!}{\includegraphics{cartoons/atomic}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap972}% \resizebox{3in}{!}{\includegraphics{cartoons/barrier}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap982}% \resizebox{3in}{!}{\includegraphics{cartoons/tollbooth}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap992}% \resizebox{3in}{!}{\includegraphics{cartoons/PhoneBooth}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap1051}% \resizebox{3in}{!}{\includegraphics{cpu/SystemArch}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap1146}% \resizebox{3in}{!}{\includegraphics{cpu/3DI}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap1702}% \resizebox{3in}{!}{\includegraphics{toolsoftrade/shellparallel}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure1258}% \begin{figure}{ \scriptsize \begin{verbatim} 1 pid = fork(); 2 if (pid == 0) { 3 /* child */ 4 } else if (pid < 0) { 5 /* parent, upon error */ 6 perror("fork"); 7 exit(-1); 8 } else { 9 /* parent, pid == child ID */ 10 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure1275}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void waitall(void) 2 { 3 int pid; 4 int status; 5 6 for (;;) { 7 pid = wait(&status); 8 if (pid == -1) { 9 if (errno == ECHILD) 10 break; 11 perror("wait"); 12 exit(-1); 13 } 14 } 15 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure1296}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int x = 0; 2 int pid; 3 4 pid = fork(); 5 if (pid == 0) { /* child */ 6 x = 1; 7 printf("Child process set x=1\n"); 8 exit(0); 9 } 10 if (pid < 0) { /* parent, upon error */ 11 perror("fork"); 12 exit(-1); 13 } 14 waitall(); 15 printf("Parent process sees x=%d\n", x); \end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure1321}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int x = 0; 2 3 void *mythread(void *arg) 4 { 5 x = 1; 6 printf("Child process set x=1\n"); 7 return NULL; 8 } 9 10 int main(int argc, char *argv[]) 11 { 12 pthread_t tid; 13 void *vp; 14 15 if (pthread_create(&tid, NULL, mythread, NULL) != 0) { 16 perror("pthread_create"); 17 exit(-1); 18 } 19 if (pthread_join(tid, &vp) != 0) { 20 perror("pthread_join"); 21 exit(-1); 22 } 23 printf("Parent process sees x=%d\n", x); 24 return 0; 25 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure1371}% \begin{figure}{ \scriptsize \begin{verbatim} 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(-1); 15 } 16 for (i = 0; i < 100; i++) { 17 newx = ACCESS_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(-1); 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_reader:pthread_mutex_lock"); 38 exit(-1); 39 } 40 for (i = 0; i < 3; i++) { 41 ACCESS_ONCE(x)++; 42 poll(NULL, 0, 5); 43 } 44 if (pthread_mutex_unlock(pmlp) != 0) { 45 perror("lock_reader:pthread_mutex_unlock"); 46 exit(-1); 47 } 48 return NULL; 49 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure1410}% \begin{figure}{ \scriptsize \begin{verbatim} 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(-1); 6 } 7 if (pthread_create(&tid2, NULL, 8 lock_writer, &lock_a) != 0) { 9 perror("pthread_create"); 10 exit(-1); 11 } 12 if (pthread_join(tid1, &vp) != 0) { 13 perror("pthread_join"); 14 exit(-1); 15 } 16 if (pthread_join(tid2, &vp) != 0) { 17 perror("pthread_join"); 18 exit(-1); 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure1435}% \begin{figure}{ \scriptsize \begin{verbatim} 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(-1); 7 } 8 if (pthread_create(&tid2, NULL, 9 lock_writer, &lock_b) != 0) { 10 perror("pthread_create"); 11 exit(-1); 12 } 13 if (pthread_join(tid1, &vp) != 0) { 14 perror("pthread_join"); 15 exit(-1); 16 } 17 if (pthread_join(tid2, &vp) != 0) { 18 perror("pthread_join"); 19 exit(-1); 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure1481}% \begin{figure}{ \scriptsize \begin{verbatim} 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 (ACCESS_ONCE(goflag) == GOFLAG_INIT) { 20 continue; 21 } 22 while (ACCESS_ONCE(goflag) == GOFLAG_RUN) { 23 if (pthread_rwlock_rdlock(&rwl) != 0) { 24 perror("pthread_rwlock_rdlock"); 25 exit(-1); 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(-1); 33 } 34 for (i = 1; i < thinktime; i++) { 35 barrier(); 36 } 37 loopcnt++; 38 } 39 readcounts[me] = loopcnt; 40 return NULL; 41 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap1896}% \resizebox{3in}{!}{\includegraphics{CodeSamples/toolsoftrade/rwlockscale}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath1516}% \begin{displaymath} \frac{L_N}{N L_1} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline1680}% $N$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline1682}% $L_N$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline1686}% $L_1$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure1984}% \begin{figure}{ \scriptsize \begin{verbatim} 1 long counter = 0; 2 3 void inc_count(void) 4 { 5 counter++; 6 } 7 8 long read_count(void) 9 { 10 return counter; 11 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure1998}% \begin{figure}{ \scriptsize \begin{verbatim} 1 atomic_t counter = ATOMIC_INIT(0); 2 3 void inc_count(void) 4 { 5 atomic_inc(&counter); 6 } 7 8 long read_count(void) 9 { 10 return atomic_read(&counter); 11 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap2889}% \resizebox{3in}{!}{\includegraphics{CodeSamples/count/atomic}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline2819}% $y=1$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap2909}% \resizebox{3in}{!}{\includegraphics{count/GlobalInc}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2046}% \begin{figure}{ \scriptsize \begin{verbatim} 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{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap2969}% \resizebox{3in}{!}{\includegraphics{count/PerThreadInc}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2089}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_PER_THREAD(atomic_t, counter); 2 atomic_t global_count; 3 int stopflag; 4 5 void inc_count(void) 6 { 7 atomic_inc(&__get_thread_var(counter)); 8 } 9 10 unsigned long read_count(void) 11 { 12 return atomic_read(&global_count); 13 } 14 15 void *eventual(void *arg) 16 { 17 int t; 18 int sum; 19 20 while (stopflag < 3) { 21 sum = 0; 22 for_each_thread(t) 23 sum += atomic_xchg(&per_thread(counter, t), 0); 24 atomic_add(sum, &global_count); 25 poll(NULL, 0, 1); 26 if (stopflag) { 27 smp_mb(); 28 stopflag++; 29 } 30 } 31 return NULL; 32 } 33 34 void count_init(void) 35 { 36 thread_id_t tid; 37 38 if (pthread_create(&tid, NULL, eventual, NULL) != 0) { 39 perror("count_init:pthread_create"); 40 exit(-1); 41 } 42 } 43 44 void count_cleanup(void) 45 { 46 stopflag = 1; 47 while (stopflag < 3) 48 poll(NULL, 0, 1); 49 smp_mb(); 50 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2124}% \begin{figure}{ \scriptsize \begin{verbatim} 1 long __thread counter = 0; 2 long *counterp[NR_THREADS] = { NULL }; 3 long finalcount = 0; 4 DEFINE_SPINLOCK(final_mutex); 5 6 void inc_count(void) 7 { 8 counter++; 9 } 10 11 long read_count(void) 12 { 13 int t; 14 long sum; 15 16 spin_lock(&final_mutex); 17 sum = finalcount; 18 for_each_thread(t) 19 if (counterp[t] != NULL) 20 sum += *counterp[t]; 21 spin_unlock(&final_mutex); 22 return sum; 23 } 24 25 void count_register_thread(void) 26 { 27 int idx = smp_thread_id(); 28 29 spin_lock(&final_mutex); 30 counterp[idx] = 31 spin_unlock(&final_mutex); 32 } 33 34 void count_unregister_thread(int nthreadsexpected) 35 { 36 int idx = smp_thread_id(); 37 38 spin_lock(&final_mutex); 39 finalcount += counter; 40 counterp[idx] = NULL; 41 spin_unlock(&final_mutex); 42 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2185}% \begin{figure}{ \scriptsize \begin{verbatim} 1 unsigned long __thread counter = 0; 2 unsigned long __thread countermax = 0; 3 unsigned long globalcountmax = 10000; 4 unsigned long globalcount = 0; 5 unsigned long globalreserve = 0; 6 unsigned long *counterp[NR_THREADS] = { NULL }; 7 DEFINE_SPINLOCK(gblcnt_mutex);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3085}% \resizebox{3in}{!}{\includegraphics{count/count_lim}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2223}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int add_count(unsigned long delta) 2 { 3 if (countermax - counter >= delta) { 4 counter += delta; 5 return 1; 6 } 7 spin_lock(&gblcnt_mutex); 8 globalize_count(); 9 if (globalcountmax - 10 globalcount - globalreserve < delta) { 11 spin_unlock(&gblcnt_mutex); 12 return 0; 13 } 14 globalcount += delta; 15 balance_count(); 16 spin_unlock(&gblcnt_mutex); 17 return 1; 18 } 19 20 int sub_count(unsigned long delta) 21 { 22 if (counter >= delta) { 23 counter -= delta; 24 return 1; 25 } 26 spin_lock(&gblcnt_mutex); 27 globalize_count(); 28 if (globalcount < delta) { 29 spin_unlock(&gblcnt_mutex); 30 return 0; 31 } 32 globalcount -= delta; 33 balance_count(); 34 spin_unlock(&gblcnt_mutex); 35 return 1; 36 } 37 38 unsigned long read_count(void) 39 { 40 int t; 41 unsigned long sum; 42 43 spin_lock(&gblcnt_mutex); 44 sum = globalcount; 45 for_each_thread(t) 46 if (counterp[t] != NULL) 47 sum += *counterp[t]; 48 spin_unlock(&gblcnt_mutex); 49 return sum; 50 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2302}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void globalize_count(void) 2 { 3 globalcount += counter; 4 counter = 0; 5 globalreserve -= countermax; 6 countermax = 0; 7 } 8 9 static void balance_count(void) 10 { 11 countermax = globalcountmax - 12 globalcount - globalreserve; 13 countermax /= num_online_threads(); 14 globalreserve += countermax; 15 counter = countermax / 2; 16 if (counter > globalcount) 17 counter = globalcount; 18 globalcount -= counter; 19 } 20 21 void count_register_thread(void) 22 { 23 int idx = smp_thread_id(); 24 25 spin_lock(&gblcnt_mutex); 26 counterp[idx] = 27 spin_unlock(&gblcnt_mutex); 28 } 29 30 void count_unregister_thread(int nthreadsexpected) 31 { 32 int idx = smp_thread_id(); 33 34 spin_lock(&gblcnt_mutex); 35 globalize_count(); 36 counterp[idx] = NULL; 37 spin_unlock(&gblcnt_mutex); 38 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2362}% \begin{figure}{ \scriptsize \begin{verbatim} 1 unsigned long __thread counter = 0; 2 unsigned long __thread countermax = 0; 3 unsigned long globalcountmax = 10000; 4 unsigned long globalcount = 0; 5 unsigned long globalreserve = 0; 6 unsigned long *counterp[NR_THREADS] = { NULL }; 7 DEFINE_SPINLOCK(gblcnt_mutex); 8 #define MAX_COUNTERMAX 100\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2368}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void balance_count(void) 2 { 3 countermax = globalcountmax - globalcount - globalreserve; 4 countermax /= num_online_threads(); 5 if (countermax > MAX_COUNTERMAX) 6 countermax = MAX_COUNTERMAX; 7 globalreserve += countermax; 8 counter = countermax / 2; 9 if (counter > globalcount) 10 counter = globalcount; 11 globalcount -= counter; 12 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2398}% \begin{figure}{ \scriptsize \begin{verbatim} 1 atomic_t __thread counterandmax = ATOMIC_INIT(0); 2 unsigned long globalcountmax = 10000; 3 unsigned long globalcount = 0; 4 unsigned long globalreserve = 0; 5 atomic_t *counterp[NR_THREADS] = { NULL }; 6 DEFINE_SPINLOCK(gblcnt_mutex); 7 #define CM_BITS (sizeof(atomic_t) * 4) 8 #define MAX_COUNTERMAX ((1 << CM_BITS) - 1) 9 10 static void 11 split_counterandmax_int(int cami, int *c, int *cm) 12 { 13 *c = (cami >> CM_BITS) & MAX_COUNTERMAX; 14 *cm = cami & MAX_COUNTERMAX; 15 } 16 17 static void 18 split_counterandmax(atomic_t *cam, int *old, 19 int *c, int *cm) 20 { 21 unsigned int cami = atomic_read(cam); 22 23 *old = cami; 24 split_counterandmax_int(cami, c, cm); 25 } 26 27 static int merge_counterandmax(int c, int cm) 28 { 29 unsigned int cami; 30 31 cami = (c << CM_BITS) | cm; 32 return ((int)cami); 33 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2453}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int add_count(unsigned long delta) 2 { 3 int c; 4 int cm; 5 int old; 6 int new; 7 8 do { 9 split_counterandmax(&counterandmax, &old, &c, &cm); 10 if (delta > MAX_COUNTERMAX || c + delta > cm) 11 goto slowpath; 12 new = merge_counterandmax(c + delta, cm); 13 } while (atomic_cmpxchg(&counterandmax, 14 old, new) != old); 15 return 1; 16 slowpath: 17 spin_lock(&gblcnt_mutex); 18 globalize_count(); 19 if (globalcountmax - globalcount - 20 globalreserve < delta) { 21 flush_local_count(); 22 if (globalcountmax - globalcount - 23 globalreserve < delta) { 24 spin_unlock(&gblcnt_mutex); 25 return 0; 26 } 27 } 28 globalcount += delta; 29 balance_count(); 30 spin_unlock(&gblcnt_mutex); 31 return 1; 32 } 33 34 int sub_count(unsigned long delta) 35 { 36 int c; 37 int cm; 38 int old; 39 int new; 40 41 do { 42 split_counterandmax(&counterandmax, &old, &c, &cm); 43 if (delta > c) 44 goto slowpath; 45 new = merge_counterandmax(c - delta, cm); 46 } while (atomic_cmpxchg(&counterandmax, 47 old, new) != old); 48 return 1; 49 slowpath: 50 spin_lock(&gblcnt_mutex); 51 globalize_count(); 52 if (globalcount < delta) { 53 flush_local_count(); 54 if (globalcount < delta) { 55 spin_unlock(&gblcnt_mutex); 56 return 0; 57 } 58 } 59 globalcount -= delta; 60 balance_count(); 61 spin_unlock(&gblcnt_mutex); 62 return 1; 63 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2503}% \begin{figure}{ \scriptsize \begin{verbatim} 1 unsigned long read_count(void) 2 { 3 int c; 4 int cm; 5 int old; 6 int t; 7 unsigned long sum; 8 9 spin_lock(&gblcnt_mutex); 10 sum = globalcount; 11 for_each_thread(t) 12 if (counterp[t] != NULL) { 13 split_counterandmax(counterp[t], &old, &c, &cm); 14 sum += c; 15 } 16 spin_unlock(&gblcnt_mutex); 17 return sum; 18 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2515}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void globalize_count(void) 2 { 3 int c; 4 int cm; 5 int old; 6 7 split_counterandmax(&counterandmax, &old, &c, &cm); 8 globalcount += c; 9 globalreserve -= cm; 10 old = merge_counterandmax(0, 0); 11 atomic_set(&counterandmax, old); 12 } 13 14 static void flush_local_count(void) 15 { 16 int c; 17 int cm; 18 int old; 19 int t; 20 int zero; 21 22 if (globalreserve == 0) 23 return; 24 zero = merge_counterandmax(0, 0); 25 for_each_thread(t) 26 if (counterp[t] != NULL) { 27 old = atomic_xchg(counterp[t], zero); 28 split_counterandmax_int(old, &c, &cm); 29 globalcount += c; 30 globalreserve -= cm; 31 } 32 } 33 34 static void balance_count(void) 35 { 36 int c; 37 int cm; 38 int old; 39 unsigned long limit; 40 41 limit = globalcountmax - globalcount - globalreserve; 42 limit /= num_online_threads(); 43 if (limit > MAX_COUNTERMAX) 44 cm = MAX_COUNTERMAX; 45 else 46 cm = limit; 47 globalreserve += cm; 48 c = cm / 2; 49 if (c > globalcount) 50 c = globalcount; 51 globalcount -= c; 52 old = merge_counterandmax(c, cm); 53 atomic_set(&counterandmax, old); 54 } 55 56 void count_register_thread(void) 57 { 58 int idx = smp_thread_id(); 59 60 spin_lock(&gblcnt_mutex); 61 counterp[idx] = 62 spin_unlock(&gblcnt_mutex); 63 } 64 65 void count_unregister_thread(int nthreadsexpected) 66 { 67 int idx = smp_thread_id(); 68 69 spin_lock(&gblcnt_mutex); 70 globalize_count(); 71 counterp[idx] = NULL; 72 spin_unlock(&gblcnt_mutex); 73 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3289}% \resizebox{2in}{!}{\includegraphics{count/sig-theft}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure2606}% \begin{figure}{ \scriptsize \begin{verbatim} 1 #define THEFT_IDLE 0 2 #define THEFT_REQ 1 3 #define THEFT_ACK 2 4 #define THEFT_READY 3 5 6 int __thread theft = THEFT_IDLE; 7 int __thread counting = 0; 8 unsigned long __thread counter = 0; 9 unsigned long __thread countermax = 0; 10 unsigned long globalcountmax = 10000; 11 unsigned long globalcount = 0; 12 unsigned long globalreserve = 0; 13 unsigned long *counterp[NR_THREADS] = { NULL }; 14 unsigned long *countermaxp[NR_THREADS] = { NULL }; 15 int *theftp[NR_THREADS] = { NULL }; 16 DEFINE_SPINLOCK(gblcnt_mutex); 17 #define MAX_COUNTERMAX 100\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2616}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void globalize_count(void) 2 { 3 globalcount += counter; 4 counter = 0; 5 globalreserve -= countermax; 6 countermax = 0; 7 } 8 9 static void flush_local_count_sig(int unused) 10 { 11 if (ACCESS_ONCE(theft) != THEFT_REQ) 12 return; 13 smp_mb(); 14 ACCESS_ONCE(theft) = THEFT_ACK; 15 if (!counting) { 16 ACCESS_ONCE(theft) = THEFT_READY; 17 } 18 smp_mb(); 19 } 20 21 static void flush_local_count(void) 22 { 23 int t; 24 thread_id_t tid; 25 26 for_each_tid(t, tid) 27 if (theftp[t] != NULL) { 28 if (*countermaxp[t] == 0) { 29 ACCESS_ONCE(*theftp[t]) = THEFT_READY; 30 continue; 31 } 32 ACCESS_ONCE(*theftp[t]) = THEFT_REQ; 33 pthread_kill(tid, SIGUSR1); 34 } 35 for_each_tid(t, tid) { 36 if (theftp[t] == NULL) 37 continue; 38 while (ACCESS_ONCE(*theftp[t]) != THEFT_READY) { 39 poll(NULL, 0, 1); 40 if (ACCESS_ONCE(*theftp[t]) == THEFT_REQ) 41 pthread_kill(tid, SIGUSR1); 42 } 43 globalcount += *counterp[t]; 44 *counterp[t] = 0; 45 globalreserve -= *countermaxp[t]; 46 *countermaxp[t] = 0; 47 ACCESS_ONCE(*theftp[t]) = THEFT_IDLE; 48 } 49 } 50 51 static void balance_count(void) 52 { 53 countermax = globalcountmax - 54 globalcount - globalreserve; 55 countermax /= num_online_threads(); 56 if (countermax > MAX_COUNTERMAX) 57 countermax = MAX_COUNTERMAX; 58 globalreserve += countermax; 59 counter = countermax / 2; 60 if (counter > globalcount) 61 counter = globalcount; 62 globalcount -= counter; 63 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2655}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int add_count(unsigned long delta) 2 { 3 int fastpath = 0; 4 5 counting = 1; 6 barrier(); 7 if (countermax - counter >= delta && 8 ACCESS_ONCE(theft) <= THEFT_REQ) { 9 counter += delta; 10 fastpath = 1; 11 } 12 barrier(); 13 counting = 0; 14 barrier(); 15 if (ACCESS_ONCE(theft) == THEFT_ACK) { 16 smp_mb(); 17 ACCESS_ONCE(theft) = THEFT_READY; 18 } 19 if (fastpath) 20 return 1; 21 spin_lock(&gblcnt_mutex); 22 globalize_count(); 23 if (globalcountmax - globalcount - 24 globalreserve < delta) { 25 flush_local_count(); 26 if (globalcountmax - globalcount - 27 globalreserve < delta) { 28 spin_unlock(&gblcnt_mutex); 29 return 0; 30 } 31 } 32 globalcount += delta; 33 balance_count(); 34 spin_unlock(&gblcnt_mutex); 35 return 1; 36 } 37 38 int sub_count(unsigned long delta) 39 { 40 int fastpath = 0; 41 42 counting = 1; 43 barrier(); 44 if (counter >= delta && 45 ACCESS_ONCE(theft) <= THEFT_REQ) { 46 counter -= delta; 47 fastpath = 1; 48 } 49 barrier(); 50 counting = 0; 51 barrier(); 52 if (ACCESS_ONCE(theft) == THEFT_ACK) { 53 smp_mb(); 54 ACCESS_ONCE(theft) = THEFT_READY; 55 } 56 if (fastpath) 57 return 1; 58 spin_lock(&gblcnt_mutex); 59 globalize_count(); 60 if (globalcount < delta) { 61 flush_local_count(); 62 if (globalcount < delta) { 63 spin_unlock(&gblcnt_mutex); 64 return 0; 65 } 66 } 67 globalcount -= delta; 68 balance_count(); 69 spin_unlock(&gblcnt_mutex); 70 return 1; 71 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2668}% \begin{figure}{ \scriptsize \begin{verbatim} 1 unsigned long read_count(void) 2 { 3 int t; 4 unsigned long sum; 5 6 spin_lock(&gblcnt_mutex); 7 sum = globalcount; 8 for_each_thread(t) 9 if (counterp[t] != NULL) 10 sum += *counterp[t]; 11 spin_unlock(&gblcnt_mutex); 12 return sum; 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure2679}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void count_init(void) 2 { 3 struct sigaction sa; 4 5 sa.sa_handler = flush_local_count_sig; 6 sigemptyset(&sa.sa_mask); 7 sa.sa_flags = 0; 8 if (sigaction(SIGUSR1, &sa, NULL) != 0) { 9 perror("sigaction"); 10 exit(-1); 11 } 12 } 13 14 void count_register_thread(void) 15 { 16 int idx = smp_thread_id(); 17 18 spin_lock(&gblcnt_mutex); 19 counterp[idx] = 20 countermaxp[idx] = 21 theftp[idx] = 22 spin_unlock(&gblcnt_mutex); 23 } 24 25 void count_unregister_thread(int nthreadsexpected) 26 { 27 int idx = smp_thread_id(); 28 29 spin_lock(&gblcnt_mutex); 30 globalize_count(); 31 counterp[idx] = NULL; 32 countermaxp[idx] = NULL; 33 theftp[idx] = NULL; 34 spin_unlock(&gblcnt_mutex); 35 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap23440}% \includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap23444}% \includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5TB}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap23448}% \includegraphics[scale=.7]{SMPdesign/DiningPhilosopher4part-b}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3721}% \resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeq}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3731}% \resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqpair}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3751}% \resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3759}% \resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash1R}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap3769}% \resizebox{1.5in}{!}{\includegraphics{SMPdesign/lockdeqhashlots}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure3600}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct pdeq { 2 spinlock_t llock; 3 int lidx; 4 spinlock_t rlock; 5 int ridx; 6 struct deq bkt[DEQ_N_BKTS]; 7 };\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure3608}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct element *pdeq_dequeue_l(struct pdeq *d) 2 { 3 struct element *e; 4 int i; 5 6 spin_lock(&d->llock); 7 i = moveright(d->lidx); 8 e = deq_dequeue_l(&d->bkt[i]); 9 if (e != NULL) 10 d->lidx = i; 11 spin_unlock(&d->llock); 12 return e; 13 } 14 15 void pdeq_enqueue_l(struct element *e, struct pdeq *d) 16 { 17 int i; 18 19 spin_lock(&d->llock); 20 i = d->lidx; 21 deq_enqueue_l(e, &d->bkt[i]); 22 d->lidx = moveleft(d->lidx); 23 spin_unlock(&d->llock); 24 } 25 26 struct element *pdeq_dequeue_r(struct pdeq *d) 27 { 28 struct element *e; 29 int i; 30 31 spin_lock(&d->rlock); 32 i = moveleft(d->ridx); 33 e = deq_dequeue_r(&d->bkt[i]); 34 if (e != NULL) 35 d->ridx = i; 36 spin_unlock(&d->rlock); 37 return e; 38 } 39 40 void pdeq_enqueue_r(struct element *e, struct pdeq *d) 41 { 42 int i; 43 44 spin_lock(&d->rlock); 45 i = d->ridx; 46 deq_enqueue_r(e, &d->bkt[i]); 47 d->ridx = moveright(d->lidx); 48 spin_unlock(&d->rlock); 49 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure3628}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct list_head *pdeq_dequeue_l(struct pdeq *d) 2 { 3 struct list_head *e; 4 int i; 5 6 spin_lock(&d->llock); 7 e = deq_dequeue_l(&d->ldeq); 8 if (e == NULL) { 9 spin_lock(&d->rlock); 10 e = deq_dequeue_l(&d->rdeq); 11 list_splice_init(&d->rdeq.chain, &d->ldeq.chain); 12 spin_unlock(&d->rlock); 13 } 14 spin_unlock(&d->llock); 15 return e; 16 } 17 18 struct list_head *pdeq_dequeue_r(struct pdeq *d) 19 { 20 struct list_head *e; 21 int i; 22 23 spin_lock(&d->rlock); 24 e = deq_dequeue_r(&d->rdeq); 25 if (e == NULL) { 26 spin_unlock(&d->rlock); 27 spin_lock(&d->llock); 28 spin_lock(&d->rlock); 29 e = deq_dequeue_r(&d->rdeq); 30 if (e == NULL) { 31 e = deq_dequeue_r(&d->ldeq); 32 list_splice_init(&d->ldeq.chain, &d->rdeq.chain); 33 } 34 spin_unlock(&d->llock); 35 } 36 spin_unlock(&d->rlock); 37 return e; 38 } 39 40 void pdeq_enqueue_l(struct list_head *e, struct pdeq *d) 41 { 42 int i; 43 44 spin_lock(&d->llock); 45 deq_enqueue_l(e, &d->ldeq); 46 spin_unlock(&d->llock); 47 } 48 49 void pdeq_enqueue_r(struct list_head *e, struct pdeq *d) 50 { 51 int i; 52 53 spin_lock(&d->rlock); 54 deq_enqueue_r(e, &d->rdeq); 55 spin_unlock(&d->rlock); 56 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap23501}% \includegraphics{SMPdesign/LockGranularity}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4295}% \resizebox{3in}{!}{\includegraphics{SMPdesign/CPUvsEnet}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure3911}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct hash_table 2 { 3 long nbuckets; 4 struct node **buckets; 5 }; 6 7 typedef struct node { 8 unsigned long key; 9 struct node *next; 10 } node_t; 11 12 int hash_search(struct hash_table *h, long key) 13 { 14 struct node *cur; 15 16 cur = h->buckets[key % h->nbuckets]; 17 while (cur != NULL) { 18 if (cur->key >= key) { 19 return (cur->key == key); 20 } 21 cur = cur->next; 22 } 23 return 0; 24 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure3923}% \begin{figure}{ \scriptsize \begin{verbatim} 1 spinlock_t hash_lock; 2 3 struct hash_table 4 { 5 long nbuckets; 6 struct node **buckets; 7 }; 8 9 typedef struct node { 10 unsigned long key; 11 struct node *next; 12 } node_t; 13 14 int hash_search(struct hash_table *h, long key) 15 { 16 struct node *cur; 17 int retval; 18 19 spin_lock(&hash_lock); 20 cur = h->buckets[key % h->nbuckets]; 21 while (cur != NULL) { 22 if (cur->key >= key) { 23 retval = (cur->key == key); 24 spin_unlock(&hash_lock); 25 return retval; 26 } 27 cur = cur->next; 28 } 29 spin_unlock(&hash_lock); 30 return 0; 31 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4331}% \resizebox{3in}{!}{\includegraphics{cartoons/OneFighting}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure3942}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct hash_table 2 { 3 long nbuckets; 4 struct bucket **buckets; 5 }; 6 7 struct bucket { 8 spinlock_t bucket_lock; 9 node_t *list_head; 10 }; 11 12 typedef struct node { 13 unsigned long key; 14 struct node *next; 15 } node_t; 16 17 int hash_search(struct hash_table *h, long key) 18 { 19 struct bucket *bp; 20 struct node *cur; 21 int retval; 22 23 bp = h->buckets[key % h->nbuckets]; 24 spin_lock(&bp->bucket_lock); 25 cur = bp->list_head; 26 while (cur != NULL) { 27 if (cur->key >= key) { 28 retval = (cur->key == key); 29 spin_unlock(&bp->hash_lock); 30 return retval; 31 } 32 cur = cur->next; 33 } 34 spin_unlock(&bp->hash_lock); 35 return 0; 36 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4349}% \resizebox{3in}{!}{\includegraphics{cartoons/ManyHappy}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4357}% \resizebox{3in}{!}{\includegraphics{cartoons/ManyFighting}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4213}% $\lambda$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4215}% $\mu$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath3985}% \begin{displaymath} \lambda = n \lambda_0 \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4231}% $n$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4233}% $\lambda_0$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4235}% $1 / \lambda_0$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath3987}% \begin{displaymath} T = \frac{1}{\mu - \lambda} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath3991}% \begin{displaymath} T = \frac{1}{\mu - n \lambda_0} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath3995}% \begin{displaymath} e = \frac{1 / \lambda_0}{T + 1 / \lambda_0} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4239}% $T$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath3999}% \begin{displaymath} e = \frac{\frac{\mu}{\lambda_0} - n}{\frac{\mu}{\lambda_0} - (n - 1)} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4241}% $\mu / \lambda_0$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4243}% $f$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmldisplayA{displaymath4005}% \begin{displaymath} e = \frac{f - n}{f - (n - 1)} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4419}% \resizebox{3in}{!}{\includegraphics{SMPdesign/synceff}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4245}% $e$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4251}% $f=10$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline4253}% $f=100$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4429}% \resizebox{3in}{!}{\includegraphics{SMPdesign/matmuleff}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap23583}% \includegraphics{SMPdesign/ParallelFastpath}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure4061}% \begin{figure}{ \scriptsize \begin{verbatim} 1 rwlock_t hash_lock; 2 3 struct hash_table 4 { 5 long nbuckets; 6 struct node **buckets; 7 }; 8 9 typedef struct node { 10 unsigned long key; 11 struct node *next; 12 } node_t; 13 14 int hash_search(struct hash_table *h, long key) 15 { 16 struct node *cur; 17 int retval; 18 19 read_lock(&hash_lock); 20 cur = h->buckets[key % h->nbuckets]; 21 while (cur != NULL) { 22 if (cur->key >= key) { 23 retval = (cur->key == key); 24 read_unlock(&hash_lock); 25 return retval; 26 } 27 cur = cur->next; 28 } 29 read_unlock(&hash_lock); 30 return 0; 31 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure4072}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct hash_table 2 { 3 long nbuckets; 4 struct bucket **buckets; 5 }; 6 7 struct bucket { 8 spinlock_t bucket_lock; 9 node_t *list_head; 10 }; 11 12 typedef struct node { 13 spinlock_t node_lock; 14 unsigned long key; 15 struct node *next; 16 } node_t; 17 18 int hash_search(struct hash_table *h, long key) 19 { 20 struct bucket *bp; 21 struct node *cur; 22 int retval; 23 24 bp = h->buckets[key % h->nbuckets]; 25 spin_lock(&bp->bucket_lock); 26 cur = bp->list_head; 27 while (cur != NULL) { 28 if (cur->key >= key) { 29 spin_lock(&cur->node_lock); 30 spin_unlock(&bp->bucket_lock); 31 retval = (cur->key == key); 32 spin_unlock(&cur->node_lock); 33 return retval; 34 } 35 cur = cur->next; 36 } 37 spin_unlock(&bp->bucket_lock); 38 return 0; 39 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4503}% \resizebox{3in}{!}{\includegraphics{SMPdesign/allocatorcache}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4113}% \begin{figure}{ \scriptsize \begin{verbatim} 1 #define TARGET_POOL_SIZE 3 2 #define GLOBAL_POOL_SIZE 40 3 4 struct globalmempool { 5 spinlock_t mutex; 6 int cur; 7 struct memblock *pool[GLOBAL_POOL_SIZE]; 8 } globalmem; 9 10 struct percpumempool { 11 int cur; 12 struct memblock *pool[2 * TARGET_POOL_SIZE]; 13 }; 14 15 DEFINE_PER_THREAD(struct percpumempool, percpumem);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4523}% \resizebox{3in}{!}{\includegraphics{SMPdesign/AllocatorPool}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4138}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct memblock *memblock_alloc(void) 2 { 3 int i; 4 struct memblock *p; 5 struct percpumempool *pcpp; 6 7 pcpp = &__get_thread_var(percpumem); 8 if (pcpp->cur < 0) { 9 spin_lock(&globalmem.mutex); 10 for (i = 0; i < TARGET_POOL_SIZE && 11 globalmem.cur >= 0; i++) { 12 pcpp->pool[i] = globalmem.pool[globalmem.cur]; 13 globalmem.pool[globalmem.cur--] = NULL; 14 } 15 pcpp->cur = i - 1; 16 spin_unlock(&globalmem.mutex); 17 } 18 if (pcpp->cur >= 0) { 19 p = pcpp->pool[pcpp->cur]; 20 pcpp->pool[pcpp->cur--] = NULL; 21 return p; 22 } 23 return NULL; 24 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4146}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void memblock_free(struct memblock *p) 2 { 3 int i; 4 struct percpumempool *pcpp; 5 6 pcpp = &__get_thread_var(percpumem); 7 if (pcpp->cur >= 2 * TARGET_POOL_SIZE - 1) { 8 spin_lock(&globalmem.mutex); 9 for (i = pcpp->cur; i >= TARGET_POOL_SIZE; i--) { 10 globalmem.pool[++globalmem.cur] = pcpp->pool[i]; 11 pcpp->pool[i] = NULL; 12 } 13 pcpp->cur = i; 14 spin_unlock(&globalmem.mutex); 15 } 16 pcpp->pool[++pcpp->cur] = p; 17 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4563}% \resizebox{3in}{!}{\includegraphics{SMPdesign/smpalloc}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{section} \stepcounter{chapter} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4728}% \resizebox{3in}{!}{\includegraphics{locking/LockingTheSlob}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4734}% \resizebox{3in}{!}{\includegraphics{locking/LockingTheHero}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap4750}% \resizebox{3in}{!}{\includegraphics{locking/DeadlockCycle}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure4646}% \begin{figure}{ \scriptsize \begin{verbatim} 1 spin_lock(&lock2); 2 layer_2_processing(pkt); 3 nextlayer = layer_1(pkt); 4 spin_lock(&nextlayer->lock1); 5 layer_1_processing(pkt); 6 spin_unlock(&lock2); 7 spin_unlock(&nextlayer->lock1);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure4653}% \begin{figure}{ \scriptsize \begin{verbatim} 1 retry: 2 spin_lock(&lock2); 3 layer_2_processing(pkt); 4 nextlayer = layer_1(pkt); 5 if (!spin_trylock(&nextlayer->lock1)) { 6 spin_unlock(&lock2); 7 spin_lock(&nextlayer->lock1); 8 spin_lock((&lock2); 9 if (layer_1(pkt) != nextlayer) { 10 spin_unlock(&nextlayer->lock1); 11 spin_unlock((&lock2); 12 goto retry; 13 } 14 } 15 layer_1_processing(pkt); 16 spin_unlock(&lock2); 17 spin_unlock(&nextlayer->lock1);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure4675}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void thread1(void) 2 { 3 retry: 4 spin_lock(&lock1); 5 do_one_thing(); 6 if (!spin_trylock(&lock2)) { 7 spin_unlock(&lock1); 8 goto retry; 9 } 10 do_another_thing(); 11 spin_unlock(&lock2); 12 spin_unlock(&lock1); 13 } 14 15 void thread2(void) 16 { 17 retry: 18 spin_lock(&lock2); 19 do_a_third_thing(); 20 if (!spin_trylock(&lock1)) { 21 spin_unlock(&lock2); 22 goto retry; 23 } 24 do_a_fourth_thing(); 25 spin_unlock(&lock1); 26 spin_unlock(&lock2); 27 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure4838}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int delete(int key) 2 { 3 int b; 4 struct element *p; 5 6 b = hashfunction(key); 7 p = hashtable[b]; 8 if (p == NULL || p->key != key) 9 return 0; 10 spin_lock(&p->lock); 11 hashtable[b] = NULL; 12 spin_unlock(&p->lock); 13 kfree(p); 14 return 1; 15 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure4853}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int delete(int key) 2 { 3 int b; 4 struct element *p; 5 spinlock_t *sp; 6 7 b = hashfunction(key); 8 sp = &locktable[b]; 9 spin_lock(sp); 10 p = hashtable[b]; 11 if (p == NULL || p->key != key) { 12 spin_unlock(sp); 13 return 0; 14 } 15 hashtable[b] = NULL; 16 spin_unlock(sp); 17 kfree(p); 18 return 1; 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{chapter} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4953}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct sref { 2 int refcount; 3 }; 4 5 void sref_init(struct sref *sref) 6 { 7 sref->refcount = 1; 8 } 9 10 void sref_get(struct sref *sref) 11 { 12 sref->refcount++; 13 } 14 15 int sref_put(struct sref *sref, 16 void (*release)(struct sref *sref)) 17 { 18 WARN_ON(release == NULL); 19 WARN_ON(release == (void (*)(struct sref *))kfree); 20 21 if (--sref->refcount == 0) { 22 release(sref); 23 return 1; 24 } 25 return 0; 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4966}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct kref { 2 atomic_t refcount; 3 }; 4 5 void kref_init(struct kref *kref) 6 { 7 atomic_set(&kref->refcount,1); 8 } 9 10 void kref_get(struct kref *kref) 11 { 12 WARN_ON(!atomic_read(&kref->refcount)); 13 atomic_inc(&kref->refcount); 14 } 15 16 int kref_put(struct kref *kref, 17 void (*release)(struct kref *kref)) 18 { 19 WARN_ON(release == NULL); 20 WARN_ON(release == (void (*)(struct kref *))kfree); 21 22 if ((atomic_read(&kref->refcount) == 1) || 23 (atomic_dec_and_test(&kref->refcount))) { 24 release(kref); 25 return 1; 26 } 27 return 0; 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure4996}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static inline 2 struct dst_entry * dst_clone(struct dst_entry * dst) 3 { 4 if (dst) 5 atomic_inc(&dst->__refcnt); 6 return dst; 7 } 8 9 static inline 10 void dst_release(struct dst_entry * dst) 11 { 12 if (dst) { 13 WARN_ON(atomic_read(&dst->__refcnt) < 1); 14 smp_mb__before_atomic_dec(); 15 atomic_dec(&dst->__refcnt); 16 } 17 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure5020}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct file *fget(unsigned int fd) 2 { 3 struct file *file; 4 struct files_struct *files = current->files; 5 6 rcu_read_lock(); 7 file = fcheck_files(files, fd); 8 if (file) { 9 if (!atomic_inc_not_zero(&file->f_count)) { 10 rcu_read_unlock(); 11 return NULL; 12 } 13 } 14 rcu_read_unlock(); 15 return file; 16 } 17 18 struct file * 19 fcheck_files(struct files_struct *files, unsigned int fd) 20 { 21 struct file * file = NULL; 22 struct fdtable *fdt = rcu_dereference((files)->fdt); 23 24 if (fd < fdt->max_fds) 25 file = rcu_dereference(fdt->fd[fd]); 26 return file; 27 } 28 29 void fput(struct file *file) 30 { 31 if (atomic_dec_and_test(&file->f_count)) 32 call_rcu(&file->f_u.fu_rcuhead, file_free_rcu); 33 } 34 35 static void file_free_rcu(struct rcu_head *head) 36 { 37 struct file *f; 38 39 f = container_of(head, struct file, f_u.fu_rcuhead); 40 kmem_cache_free(filp_cachep, f); 41 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure5249}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct foo { 2 int a; 3 int b; 4 int c; 5 }; 6 struct foo *gp = NULL; 7 8 /* . . . */ 9 10 p = kmalloc(sizeof(*p), GFP_KERNEL); 11 p->a = 1; 12 p->b = 2; 13 p->c = 3; 14 gp = p;\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5623}% \resizebox{3in}{!}{\includegraphics{defer/Linux_list}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5629}% \resizebox{3in}{!}{\includegraphics{defer/Linux_list_abbr}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure5333}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct foo { 2 struct list_head *list; 3 int a; 4 int b; 5 int c; 6 }; 7 LIST_HEAD(head); 8 9 /* . . . */ 10 11 p = kmalloc(sizeof(*p), GFP_KERNEL); 12 p->a = 1; 13 p->b = 2; 14 p->c = 3; 15 list_add_rcu(&p->list, &head);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5669}% \resizebox{3in}{!}{\includegraphics{defer/Linux_hlist}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure5366}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct foo { 2 struct hlist_node *list; 3 int a; 4 int b; 5 int c; 6 }; 7 HLIST_HEAD(head); 8 9 /* . . . */ 10 11 p = kmalloc(sizeof(*p), GFP_KERNEL); 12 p->a = 1; 13 p->b = 2; 14 p->c = 3; 15 hlist_add_head_rcu(&p->list, &head);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5725}% \resizebox{3in}{!}{\includegraphics{defer/GracePeriodGood}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure5435}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct foo { 2 struct list_head *list; 3 int a; 4 int b; 5 int c; 6 }; 7 LIST_HEAD(head); 8 9 /* . . . */ 10 11 p = search(head, key); 12 if (p == NULL) { 13 /* Take appropriate action, unlock, and return. */ 14 } 15 q = kmalloc(sizeof(*p), GFP_KERNEL); 16 *q = *p; 17 q->b = 2; 18 q->c = 3; 19 list_replace_rcu(&p->list, &q->list); 20 synchronize_rcu(); 21 kfree(p);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5771}% \resizebox{3in}{!}{\includegraphics{defer/RCUDeletion}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap5791}% \resizebox{2.7in}{!}{\includegraphics{defer/RCUReplacement}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6134}% \resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperf}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6148}% \resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfPREEMPT}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6156}% \resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfwtPREEMPT}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6200}% \resizebox{3in}{!}{\includegraphics{defer/rwlockRCUupdate}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} {\newpage\clearpage \lthtmlfigureA{figurestar5961}% \begin{figure*}{ \scriptsize\centering \begin{verbatim} 1 struct el { 1 struct el { 2 struct list_head lp; 2 struct list_head lp; 3 long key; 3 long key; 4 spinlock_t mutex; 4 spinlock_t mutex; 5 int data; 5 int data; 6 /* Other data fields */ 6 /* Other data fields */ 7 }; 7 }; 8 DEFINE_RWLOCK(listmutex); 8 DEFINE_SPINLOCK(listmutex); 9 LIST_HEAD(head); 9 LIST_HEAD(head);\end{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figurestar5967}% \begin{figure*}{ \scriptsize\centering \begin{verbatim} 1 int search(long key, int *result) 1 int search(long key, int *result) 2 { 2 { 3 struct el *p; 3 struct el *p; 4 4 5 read_lock(&listmutex); 5 rcu_read_lock(); 6 list_for_each_entry(p, &head, lp) { 6 list_for_each_entry_rcu(p, &head, lp) { 7 if (p->key == key) { 7 if (p->key == key) { 8 *result = p->data; 8 *result = p->data; 9 read_unlock(&listmutex); 9 rcu_read_unlock(); 10 return 1; 10 return 1; 11 } 11 } 12 } 12 } 13 read_unlock(&listmutex); 13 rcu_read_unlock(); 14 return 0; 14 return 0; 15 } 15 }\end{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figurestar5973}% \begin{figure*}{ \scriptsize\centering \begin{verbatim} 1 int delete(long key) 1 int delete(long key) 2 { 2 { 3 struct el *p; 3 struct el *p; 4 4 5 write_lock(&listmutex); 5 spin_lock(&listmutex); 6 list_for_each_entry(p, &head, lp) { 6 list_for_each_entry(p, &head, lp) { 7 if (p->key == key) { 7 if (p->key == key) { 8 list_del(&p->lp); 8 list_del_rcu(&p->lp); 9 write_unlock(&listmutex); 9 spin_unlock(&listmutex); 10 synchronize_rcu(); 10 kfree(p); 11 kfree(p); 11 return 1; 12 return 1; 12 } 13 } 13 } 14 } 14 write_unlock(&listmutex); 15 spin_unlock(&listmutex); 15 return 0; 16 return 0; 16 } 17 }\end{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6278}% \resizebox{3in}{!}{\includegraphics{defer/refRCUperfPREEMPT}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6290}% \resizebox{3in}{!}{\includegraphics{defer/refRCUperfwtPREEMPT}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6041}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int delete(int key) 2 { 3 struct element *p; 4 int b; 5 5 6 b = hashfunction(key); 7 rcu_read_lock(); 8 p = rcu_dereference(hashtable[b]); 9 if (p == NULL || p->key != key) { 10 rcu_read_unlock(); 11 return 0; 12 } 13 spin_lock(&p->lock); 14 if (hashtable[b] == p && p->key == key) { 15 rcu_read_unlock(); 16 hashtable[b] = NULL; 17 spin_unlock(&p->lock); 18 synchronize_rcu(); 19 kfree(p); 20 return 1; 21 } 22 spin_unlock(&p->lock); 23 rcu_read_unlock(); 24 return 0; 25 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6078}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct profile_buffer { 2 long size; 3 atomic_t entry[0]; 4 }; 5 static struct profile_buffer *buf = NULL; 6 7 void nmi_profile(unsigned long pcvalue) 8 { 9 struct profile_buffer *p = rcu_dereference(buf); 10 11 if (p == NULL) 12 return; 13 if (pcvalue >= p->size) 14 return; 15 atomic_inc(&p->entry[pcvalue]); 16 } 17 18 void nmi_stop(void) 19 { 20 struct profile_buffer *p = buf; 21 22 if (p == NULL) 23 return; 24 rcu_assign_pointer(buf, NULL); 25 synchronize_sched(); 26 kfree(p); 27 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap6783}% \resizebox{3in}{!}{\includegraphics{defer/RCUenvAPI}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6812}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 spin_lock(&rcu_gp_lock); 4 } 5 6 static void rcu_read_unlock(void) 7 { 8 spin_unlock(&rcu_gp_lock); 9 } 10 11 void synchronize_rcu(void) 12 { 13 spin_lock(&rcu_gp_lock); 14 spin_unlock(&rcu_gp_lock); 15 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6837}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 spin_lock(&__get_thread_var(rcu_gp_lock)); 4 } 5 6 static void rcu_read_unlock(void) 7 { 8 spin_unlock(&__get_thread_var(rcu_gp_lock)); 9 } 10 11 void synchronize_rcu(void) 12 { 13 int t; 14 15 for_each_running_thread(t) { 16 spin_lock(&per_thread(rcu_gp_lock, t)); 17 spin_unlock(&per_thread(rcu_gp_lock, t)); 18 } 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6864}% \begin{figure}{ \scriptsize \begin{verbatim} 1 atomic_t rcu_refcnt; 2 3 static void rcu_read_lock(void) 4 { 5 atomic_inc(&rcu_refcnt); 6 smp_mb(); 7 } 8 9 static void rcu_read_unlock(void) 10 { 11 smp_mb(); 12 atomic_dec(&rcu_refcnt); 13 } 14 15 void synchronize_rcu(void) 16 { 17 smp_mb(); 18 while (atomic_read(&rcu_refcnt) != 0) { 19 poll(NULL, 0, 10); 20 } 21 smp_mb(); 22 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6904}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 atomic_t rcu_refcnt[2]; 3 atomic_t rcu_idx; 4 DEFINE_PER_THREAD(int, rcu_nesting); 5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure6910}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 int i; 4 int n; 5 6 n = __get_thread_var(rcu_nesting); 7 if (n == 0) { 8 i = atomic_read(&rcu_idx); 9 __get_thread_var(rcu_read_idx) = i; 10 atomic_inc(&rcu_refcnt[i]); 11 } 12 __get_thread_var(rcu_nesting) = n + 1; 13 smp_mb(); 14 } 15 16 static void rcu_read_unlock(void) 17 { 18 int i; 19 int n; 20 21 smp_mb(); 22 n = __get_thread_var(rcu_nesting); 23 if (n == 1) { 24 i = __get_thread_var(rcu_read_idx); 25 atomic_dec(&rcu_refcnt[i]); 26 } 27 __get_thread_var(rcu_nesting) = n - 1; 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure6949}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void synchronize_rcu(void) 2 { 3 int i; 4 5 smp_mb(); 6 spin_lock(&rcu_gp_lock); 7 i = atomic_read(&rcu_idx); 8 atomic_set(&rcu_idx, !i); 9 smp_mb(); 10 while (atomic_read(&rcu_refcnt[i]) != 0) { 11 poll(NULL, 0, 10); 12 } 13 smp_mb(); 14 atomic_set(&rcu_idx, i); 15 smp_mb(); 16 while (atomic_read(&rcu_refcnt[!i]) != 0) { 17 poll(NULL, 0, 10); 18 } 19 spin_unlock(&rcu_gp_lock); 20 smp_mb(); 21 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure6990}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 DEFINE_PER_THREAD(int [2], rcu_refcnt); 3 atomic_t rcu_idx; 4 DEFINE_PER_THREAD(int, rcu_nesting); 5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure6996}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 int i; 4 int n; 5 6 n = __get_thread_var(rcu_nesting); 7 if (n == 0) { 8 i = atomic_read(&rcu_idx); 9 __get_thread_var(rcu_read_idx) = i; 10 __get_thread_var(rcu_refcnt)[i]++; 11 } 12 __get_thread_var(rcu_nesting) = n + 1; 13 smp_mb(); 14 } 15 16 static void rcu_read_unlock(void) 17 { 18 int i; 19 int n; 20 21 smp_mb(); 22 n = __get_thread_var(rcu_nesting); 23 if (n == 1) { 24 i = __get_thread_var(rcu_read_idx); 25 __get_thread_var(rcu_refcnt)[i]--; 26 } 27 __get_thread_var(rcu_nesting) = n - 1; 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7014}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void flip_counter_and_wait(int i) 2 { 3 int t; 4 5 atomic_set(&rcu_idx, !i); 6 smp_mb(); 7 for_each_thread(t) { 8 while (per_thread(rcu_refcnt, t)[i] != 0) { 9 poll(NULL, 0, 10); 10 } 11 } 12 smp_mb(); 13 } 14 15 void synchronize_rcu(void) 16 { 17 int i; 18 19 smp_mb(); 20 spin_lock(&rcu_gp_lock); 21 i = atomic_read(&rcu_idx); 22 flip_counter_and_wait(i); 23 flip_counter_and_wait(!i); 24 spin_unlock(&rcu_gp_lock); 25 smp_mb(); 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline7334}% $2N$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure7039}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 DEFINE_PER_THREAD(int [2], rcu_refcnt); 3 long rcu_idx; 4 DEFINE_PER_THREAD(int, rcu_nesting); 5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7045}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 int i; 4 int n; 5 6 n = __get_thread_var(rcu_nesting); 7 if (n == 0) { 8 i = ACCESS_ONCE(rcu_idx) & 0x1; 9 __get_thread_var(rcu_read_idx) = i; 10 __get_thread_var(rcu_refcnt)[i]++; 11 } 12 __get_thread_var(rcu_nesting) = n + 1; 13 smp_mb(); 14 } 15 16 static void rcu_read_unlock(void) 17 { 18 int i; 19 int n; 20 21 smp_mb(); 22 n = __get_thread_var(rcu_nesting); 23 if (n == 1) { 24 i = __get_thread_var(rcu_read_idx); 25 __get_thread_var(rcu_refcnt)[i]--; 26 } 27 __get_thread_var(rcu_nesting) = n - 1; 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7064}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void flip_counter_and_wait(int ctr) 2 { 3 int i; 4 int t; 5 6 ACCESS_ONCE(rcu_idx) = ctr + 1; 7 i = ctr & 0x1; 8 smp_mb(); 9 for_each_thread(t) { 10 while (per_thread(rcu_refcnt, t)[i] != 0) { 11 poll(NULL, 0, 10); 12 } 13 } 14 smp_mb(); 15 } 16 17 void synchronize_rcu(void) 18 { 19 int ctr; 20 int oldctr; 21 22 smp_mb(); 23 oldctr = ACCESS_ONCE(rcu_idx); 24 smp_mb(); 25 spin_lock(&rcu_gp_lock); 26 ctr = ACCESS_ONCE(rcu_idx); 27 if (ctr - oldctr >= 3) { 28 spin_unlock(&rcu_gp_lock); 29 smp_mb(); 30 return; 31 } 32 flip_counter_and_wait(ctr); 33 if (ctr - oldctr < 2) 34 flip_counter_and_wait(ctr + 1); 35 spin_unlock(&rcu_gp_lock); 36 smp_mb(); 37 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline7336}% $O\left(1\right)$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure7106}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 long rcu_gp_ctr = 0; 3 DEFINE_PER_THREAD(long, rcu_reader_gp); 4 DEFINE_PER_THREAD(long, rcu_reader_gp_snap);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7112}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 __get_thread_var(rcu_reader_gp) = rcu_gp_ctr + 1; 4 smp_mb(); 5 } 6 7 static void rcu_read_unlock(void) 8 { 9 smp_mb(); 10 __get_thread_var(rcu_reader_gp) = rcu_gp_ctr; 11 } 12 13 void synchronize_rcu(void) 14 { 15 int t; 16 17 smp_mb(); 18 spin_lock(&rcu_gp_lock); 19 rcu_gp_ctr += 2; 20 smp_mb(); 21 for_each_thread(t) { 22 while ((per_thread(rcu_reader_gp, t) & 0x1) && 23 ((per_thread(rcu_reader_gp, t) - 24 rcu_gp_ctr) < 0)) { 25 poll(NULL, 0, 10); 26 } 27 } 28 spin_unlock(&rcu_gp_lock); 29 smp_mb(); 30 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure7164}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 #define RCU_GP_CTR_SHIFT 7 3 #define RCU_GP_CTR_BOTTOM_BIT (1 << RCU_GP_CTR_SHIFT) 4 #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BOTTOM_BIT - 1) 5 long rcu_gp_ctr = 0; 6 DEFINE_PER_THREAD(long, rcu_reader_gp);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7170}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 long tmp; 4 long *rrgp; 5 6 rrgp = &__get_thread_var(rcu_reader_gp); 7 tmp = *rrgp; 8 if ((tmp & RCU_GP_CTR_NEST_MASK) == 0) 9 tmp = rcu_gp_ctr; 10 tmp++; 11 *rrgp = tmp; 12 smp_mb(); 13 } 14 15 static void rcu_read_unlock(void) 16 { 17 long tmp; 18 19 smp_mb(); 20 __get_thread_var(rcu_reader_gp)--; 21 } 22 23 void synchronize_rcu(void) 24 { 25 int t; 26 27 smp_mb(); 28 spin_lock(&rcu_gp_lock); 29 rcu_gp_ctr += RCU_GP_CTR_BOTTOM_BIT; 30 smp_mb(); 31 for_each_thread(t) { 32 while (rcu_gp_ongoing(t) && 33 ((per_thread(rcu_reader_gp, t) - 34 rcu_gp_ctr) < 0)) { 35 poll(NULL, 0, 10); 36 } 37 } 38 spin_unlock(&rcu_gp_lock); 39 smp_mb(); 40 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure7228}% \begin{figure}{ \scriptsize \begin{verbatim} 1 DEFINE_SPINLOCK(rcu_gp_lock); 2 long rcu_gp_ctr = 0; 3 DEFINE_PER_THREAD(long, rcu_reader_qs_gp);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7234}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_read_lock(void) 2 { 3 } 4 5 static void rcu_read_unlock(void) 6 { 7 } 8 9 rcu_quiescent_state(void) 10 { 11 smp_mb(); 12 __get_thread_var(rcu_reader_qs_gp) = 13 ACCESS_ONCE(rcu_gp_ctr) + 1; 14 smp_mb(); 15 } 16 17 static void rcu_thread_offline(void) 18 { 19 smp_mb(); 20 __get_thread_var(rcu_reader_qs_gp) = 21 ACCESS_ONCE(rcu_gp_ctr); 22 smp_mb(); 23 } 24 25 static void rcu_thread_online(void) 26 { 27 rcu_quiescent_state(); 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure7277}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void synchronize_rcu(void) 2 { 3 int t; 4 5 smp_mb(); 6 spin_lock(&rcu_gp_lock); 7 rcu_gp_ctr += 2; 8 smp_mb(); 9 for_each_thread(t) { 10 while (rcu_gp_ongoing(t) && 11 ((per_thread(rcu_reader_qs_gp, t) - 12 rcu_gp_ctr) < 0)) { 13 poll(NULL, 0, 10); 14 } 15 } 16 spin_unlock(&rcu_gp_lock); 17 smp_mb(); 18 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{chapter} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure7817}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct countarray { 2 unsigned long total; 3 unsigned long *counterp[NR_THREADS]; 4 }; 5 6 long __thread counter = 0; 7 struct countarray *countarrayp = NULL; 8 DEFINE_SPINLOCK(final_mutex); 9 10 void inc_count(void) 11 { 12 counter++; 13 } 14 15 long read_count(void) 16 { 17 struct countarray *cap; 18 unsigned long sum; 19 int t; 20 21 rcu_read_lock(); 22 cap = rcu_dereference(countarrayp); 23 sum = cap->total; 24 for_each_thread(t) 25 if (cap->counterp[t] != NULL) 26 sum += *cap->counterp[t]; 27 rcu_read_unlock(); 28 return sum; 29 } 30 31 void count_init(void) 32 { 33 countarrayp = malloc(sizeof(*countarrayp)); 34 if (countarrayp == NULL) { 35 fprintf(stderr, "Out of memory\n"); 36 exit(-1); 37 } 38 memset(countarrayp, '\0', sizeof(*countarrayp)); 39 } 40 41 void count_register_thread(void) 42 { 43 int idx = smp_thread_id(); 44 45 spin_lock(&final_mutex); 46 countarrayp->counterp[idx] = 47 spin_unlock(&final_mutex); 48 } 49 50 void count_unregister_thread(int nthreadsexpected) 51 { 52 struct countarray *cap; 53 struct countarray *capold; 54 int idx = smp_thread_id(); 55 56 cap = malloc(sizeof(*countarrayp)); 57 if (cap == NULL) { 58 fprintf(stderr, "Out of memory\n"); 59 exit(-1); 60 } 61 spin_lock(&final_mutex); 62 *cap = *countarrayp; 63 cap->total += counter; 64 cap->counterp[idx] = NULL; 65 capold = countarrayp; 66 rcu_assign_pointer(countarrayp, cap); 67 spin_unlock(&final_mutex); 68 synchronize_rcu(); 69 free(capold); 70 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap9088}% \resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSC}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap9096}% \resizebox{3in}{2in}{\includegraphics{cartoons/CPU_toon_outoforder_colored}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure8120}% \begin{figure}{ \centering \begin{verbatim} 1 thread0(void) 2 { 3 A = 1; 4 smp_wmb(); 5 B = 1; 6 } 7 8 thread1(void) 9 { 10 while (B != 1) 11 continue; 12 barrier(); 13 C = 1; 14 } 15 16 thread2(void) 17 { 18 while (C != 1) 19 continue; 20 smp_mb(); 21 assert(A != 0); 22 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure8147}% \begin{figure}{ \centering \begin{verbatim} 1 state.variable = mycpu; 2 lasttb = oldtb = firsttb = gettb(); 3 while (state.variable == mycpu) { 4 lasttb = oldtb; 5 oldtb = gettb(); 6 if (lasttb - firsttb > 1000) 7 break; 8 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap9152}% \resizebox{3in}{!}{\includegraphics{advsync/MoreThanOneValue}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24401}% \includegraphics{advsync/AbstractMemoryAccessModel}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline9032}% $\rightarrow$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{paragraph} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline9060}% $\dagger$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24606}% \includegraphics{advsync/MemoryBarrierPairing}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24615}% \includegraphics{advsync/WriteBarrierOrdering}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24634}% \includegraphics{advsync/DataDependencyNeeded}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24655}% \includegraphics{advsync/DataDependencySupplied}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24672}% \includegraphics{advsync/ReadBarrierNeeded}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24691}% \includegraphics{advsync/ReadBarrierSupplied}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24712}% \includegraphics{advsync/ReadBarrierSupplied1}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24716}% \includegraphics{advsync/ReadBarrierSupplied2}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24732}% \includegraphics{advsync/SpeculativeLoad}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24749}% \includegraphics{advsync/SpeculativeLoadBarrier}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24753}% \includegraphics{advsync/SpeculativeLoadBarrierCancel}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24826}% \includegraphics{advsync/MemoryArchitecture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24831}% \includegraphics{advsync/SplitCache}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap10030}% \resizebox{3in}{!}{\includegraphics{easy/Mandel_zoom_00_mandelbrot_set}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline10002}% $N-1$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap10082}% \resizebox{3in}{!}{\includegraphics{cartoons/ShavingTheMandelbrotSet}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{chapter} \stepcounter{chapter} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{section} \appendix \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure10510}% \begin{figure}{ \scriptsize \begin{verbatim} 1 /* WARNING: BUGGY CODE. */ 2 void *producer(void *ignored) 3 { 4 int i = 0; 5 6 producer_ready = 1; 7 while (!goflag) 8 sched_yield(); 9 while (goflag) { 10 ss.t = dgettimeofday(); 11 ss.a = ss.c + 1; 12 ss.b = ss.a + 1; 13 ss.c = ss.b + 1; 14 i++; 15 } 16 printf("producer exiting: %d samples\n", i); 17 producer_done = 1; 18 return (NULL); 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure10516}% \begin{figure}{ \scriptsize \begin{verbatim} 1 /* WARNING: BUGGY CODE. */ 2 void *consumer(void *ignored) 3 { 4 struct snapshot_consumer curssc; 5 int i = 0; 6 int j = 0; 7 8 consumer_ready = 1; 9 while (ss.t == 0.0) { 10 sched_yield(); 11 } 12 while (goflag) { 13 curssc.tc = dgettimeofday(); 14 curssc.t = ss.t; 15 curssc.a = ss.a; 16 curssc.b = ss.b; 17 curssc.c = ss.c; 18 curssc.sequence = curseq; 19 curssc.iserror = 0; 20 if ((curssc.t > curssc.tc) || 21 modgreater(ssc[i].a, curssc.a) || 22 modgreater(ssc[i].b, curssc.b) || 23 modgreater(ssc[i].c, curssc.c) || 24 modgreater(curssc.a, ssc[i].a + maxdelta) || 25 modgreater(curssc.b, ssc[i].b + maxdelta) || 26 modgreater(curssc.c, ssc[i].c + maxdelta)) { 27 i++; 28 curssc.iserror = 1; 29 } else if (ssc[i].iserror) 30 i++; 31 ssc[i] = curssc; 32 curseq++; 33 if (i + 1 >= NSNAPS) 34 break; 35 } 36 printf("consumer exited, collected %d items of %d\n", 37 i, curseq); 38 if (ssc[0].iserror) 39 printf("0/%d: %.6f %.6f (%.3f) %d %d %d\n", 40 ssc[0].sequence, ssc[j].t, ssc[j].tc, 41 (ssc[j].tc - ssc[j].t) * 1000000, 42 ssc[j].a, ssc[j].b, ssc[j].c); 43 for (j = 0; j <= i; j++) 44 if (ssc[j].iserror) 45 printf("%d: %.6f (%.3f) %d %d %d\n", 46 ssc[j].sequence, 47 ssc[j].t, (ssc[j].tc - ssc[j].t) * 1000000, 48 ssc[j].a - ssc[j - 1].a, 49 ssc[j].b - ssc[j - 1].b, 50 ssc[j].c - ssc[j - 1].c); 51 consumer_done = 1; 52 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap24953}% \includegraphics{appendix/questions/after}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{chapter} \stepcounter{section} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figurestar10660}% \begin{figure*}{ \scriptsize \begin{verbatim} 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{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure10700}% \begin{figure}{ \scriptsize \begin{verbatim} 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{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure10710}% \begin{figure}{ \scriptsize \begin{verbatim} 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 exit(0); 21 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure10719}% \begin{figure}{ \scriptsize \begin{verbatim} 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{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure10757}% \begin{figure}{ \scriptsize \begin{verbatim} DEFINE_PER_THREAD(type, name) DECLARE_PER_THREAD(type, name) per_thread(name, thread) __get_thread_var(name) init_per_thread(name, v)\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure11046}% \begin{figure}\begin{center} \small \begin{picture}(170,170)(0,0) \par % Addresses \par \put(0,0){\makebox(20,10){\tt0xF}} \put(0,10){\makebox(20,10){\tt0xE}} \put(0,20){\makebox(20,10){\tt0xD}} \put(0,30){\makebox(20,10){\tt0xC}} \put(0,40){\makebox(20,10){\tt0xB}} \put(0,50){\makebox(20,10){\tt0xA}} \put(0,60){\makebox(20,10){\tt0x9}} \put(0,70){\makebox(20,10){\tt0x8}} \put(0,80){\makebox(20,10){\tt0x7}} \put(0,90){\makebox(20,10){\tt0x6}} \put(0,100){\makebox(20,10){\tt0x5}} \put(0,110){\makebox(20,10){\tt0x4}} \put(0,120){\makebox(20,10){\tt0x3}} \put(0,130){\makebox(20,10){\tt0x2}} \put(0,140){\makebox(20,10){\tt0x1}} \put(0,150){\makebox(20,10){\tt0x0}} \par % Way 0 \par \put(20,163){\makebox(80,10){Way 0}} \put(20,0){\framebox{(}80,10){\tt }} \put(20,10){\framebox{(}80,10){\tt0x12345E00}} \put(20,20){\framebox{(}80,10){\tt0x12345D00}} \put(20,30){\framebox{(}80,10){\tt0x12345C00}} \put(20,40){\framebox{(}80,10){\tt0x12345B00}} \put(20,50){\framebox{(}80,10){\tt0x12345A00}} \put(20,60){\framebox{(}80,10){\tt0x12345900}} \put(20,70){\framebox{(}80,10){\tt0x12345800}} \put(20,80){\framebox{(}80,10){\tt0x12345700}} \put(20,90){\framebox{(}80,10){\tt0x12345600}} \put(20,100){\framebox{(}80,10){\tt0x12345500}} \put(20,110){\framebox{(}80,10){\tt0x12345400}} \put(20,120){\framebox{(}80,10){\tt0x12345300}} \put(20,130){\framebox{(}80,10){\tt0x12345200}} \put(20,140){\framebox{(}80,10){\tt0x12345100}} \put(20,150){\framebox{(}80,10){\tt0x12345000}} \par % Way 1 \par \put(100,163){\makebox(80,10){Way 1}} \put(100,0){\framebox{(}80,10){\tt }} \put(100,10){\framebox{(}80,10){\tt0x43210E00}} \put(100,20){\framebox{(}80,10){\tt }} \put(100,30){\framebox{(}80,10){\tt }} \put(100,40){\framebox{(}80,10){\tt }} \put(100,50){\framebox{(}80,10){\tt }} \put(100,60){\framebox{(}80,10){\tt }} \put(100,70){\framebox{(}80,10){\tt }} \put(100,80){\framebox{(}80,10){\tt }} \put(100,90){\framebox{(}80,10){\tt }} \put(100,100){\framebox{(}80,10){\tt }} \put(100,110){\framebox{(}80,10){\tt }} \put(100,120){\framebox{(}80,10){\tt }} \put(100,130){\framebox{(}80,10){\tt }} \put(100,140){\framebox{(}80,10){\tt }} \put(100,150){\framebox{(}80,10){\tt }} \end{picture} \end{center} \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap25044}% \includegraphics{appendix/whymb/MESI}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap25139}% \includegraphics{appendix/whymb/cacheSCwrite}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap12142}% \resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSB}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap12164}% \resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBf}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap12214}% \resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBfIQ}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap12290}% \resizebox{3in}{!}{\includegraphics{appendix/whymb/hostileordering}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{picture11457}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Loads Reordered After Loads?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11461}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Loads Reordered After Stores?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11465}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Stores Reordered After Stores?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11469}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Stores Reordered After Loads?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11473}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Atomic Instructions Reordered With Loads?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11477}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Atomic Instructions Reordered With Stores?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11481}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Dependent Loads Reordered?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{picture11485}% \begin{picture}(6,185)(0,0) \rotatebox{90}{Incoherent Instruction Cache/Pipeline?} \end{picture}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlineA{tex2html_nomath_inline12382}% \textregistered% \lthtmlinlineZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure11518}% \begin{figure}{\tt\scriptsize \begin{verbatim} 1 struct el *insert(long key, long data) 2 { 3 struct el *p; 4 p = kmalloc(sizeof(*p), GFP_ATOMIC); 5 spin_lock(&mutex); 6 p->next = head.next; 7 p->key = key; 8 p->data = data; 9 smp_wmb(); 10 head.next = p; 11 spin_unlock(&mutex); 12 } 13 14 struct el *search(long key) 15 { 16 struct el *p; 17 p = head.next; 18 while (p != &head) { 19 /* BUG ON ALPHA!!! */ 20 if (p->key == key) { 21 return (p); 22 } 23 p = p->next; 24 }; 25 return (NULL); 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure11530}% \begin{figure}\begin{center} \begin{picture}(213,160)(0,25) \par % First CPU \par \put(0,50){\framebox{(}90,20)[c]{(w)mb Sequencing}} \put(0,70){\framebox{(}45,50)[l]{}} \put(0,102){\makebox(45,1)[c]{Cache}} \put(0,90){\makebox(45,1)[c]{Bank 0}} \put(45,70){\framebox{(}45,50)[l]{}} \put(45,102){\makebox(45,1)[c]{Cache}} \put(45,90){\makebox(45,1)[c]{Bank 1}} \put(0,120){\framebox{(}90,20)[c]{(r)mb Sequencing}} \put(0,140){\framebox{(}90,20)[c]{Writing CPU Core}} \par % Second CPU \par \put(120,50){\framebox{(}90,20)[c]{(w)mb Sequencing}} \put(120,70){\framebox{(}45,50)[l]{}} \put(120,102){\makebox(45,1)[c]{Cache}} \put(120,90){\makebox(45,1)[c]{Bank 0}} \put(165,70){\framebox{(}45,50)[l]{}} \put(165,102){\makebox(45,1)[c]{Cache}} \put(165,90){\makebox(45,1)[c]{Bank 1}} \put(120,120){\framebox{(}90,20)[c]{(r)mb Sequencing}} \put(120,140){\framebox{(}90,20)[c]{Reading CPU Core}} \par % Interconnection "network" \par \put(45,50){\line(0,-1){25}} \put(45,25){\line(1,0){120}} \put(165,25){\vector(0,1){25}} \put(45,25){\makebox(120,20)[c]{Interconnect}} \end{picture} \end{center} \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure11565}% \begin{figure}{\tt\scriptsize \begin{verbatim} 1 struct el *insert(long key, long data) 2 { 3 struct el *p; 4 p = kmalloc(sizeof(*p), GFP_ATOMIC); 5 spin_lock(&mutex); 6 p->next = head.next; 7 p->key = key; 8 p->data = data; 9 smp_wmb(); 10 head.next = p; 11 spin_unlock(&mutex); 12 } 13 14 struct el *search(long key) 15 { 16 struct el *p; 17 p = head.next; 18 while (p != &head) { 19 smp_read_barrier_depends(); 20 if (p->key == key) { 21 return (p); 22 } 23 p = p->next; 24 }; 25 return (NULL); 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap12588}% \resizebox{3in}{2in}{\includegraphics{cartoons/LD,ACQ}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13178}% \resizebox{3in}{!}{\includegraphics{cartoons/RCUCallbacks}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure12922}% \begin{figure}{ \scriptsize \begin{verbatim} int init_srcu_struct(struct srcu_struct *sp); void cleanup_srcu_struct(struct srcu_struct *sp); int srcu_read_lock(struct srcu_struct *sp); void srcu_read_unlock(struct srcu_struct *sp, int idx); void synchronize_srcu(struct srcu_struct *sp); long srcu_batches_completed(struct srcu_struct *sp);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure13015}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int readside(void) 2 { 3 int idx; 4 5 rcu_read_lock(); 6 if (nomoresrcu) { 7 rcu_read_unlock(); 8 return -EINVAL; 9 } 10 idx = srcu_read_lock(&ss); 11 rcu_read_unlock(); 12 /* SRCU read-side critical section. */ 13 srcu_read_unlock(&ss, idx); 14 return 0; 15 } 16 17 void cleanup(void) 18 { 19 nomoresrcu = 1; 20 synchronize_rcu(); 21 synchronize_srcu(&ss); 22 cleanup_srcu_struct(&ss); 23 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure13049}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct srcu_struct_array { 2 int c[2]; 3 }; 4 struct srcu_struct { 5 int completed; 6 struct srcu_struct_array *per_cpu_ref; 7 struct mutex mutex; 8 };\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap25484}% \includegraphics{appendix/rcuimpl/srcuds}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure13069}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int init_srcu_struct(struct srcu_struct *sp) 2 { 3 sp->completed = 0; 4 mutex_init(&sp->mutex); 5 sp->per_cpu_ref = 6 alloc_percpu(struct srcu_struct_array); 7 return (sp->per_cpu_ref ? 0 : -ENOMEM); 8 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure13089}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int srcu_readers_active_idx(struct srcu_struct *sp, 2 int idx) 3 { 4 int cpu; 5 int sum; 6 7 sum = 0; 8 for_each_possible_cpu(cpu) 9 sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]; 10 return sum; 11 } 12 13 int srcu_readers_active(struct srcu_struct *sp) 14 { 15 return srcu_readers_active_idx(sp, 0) + 16 srcu_readers_active_idx(sp, 1); 17 } 18 19 void cleanup_srcu_struct(struct srcu_struct *sp) 20 { 21 int sum; 22 23 sum = srcu_readers_active(sp); 24 WARN_ON(sum); 25 if (sum != 0) 26 return; 27 free_percpu(sp->per_cpu_ref); 28 sp->per_cpu_ref = NULL; 29 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure13109}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int srcu_read_lock(struct srcu_struct *sp) 2 { 3 int idx; 4 5 preempt_disable(); 6 idx = sp->completed & 0x1; 7 barrier(); 8 per_cpu_ptr(sp->per_cpu_ref, 9 smp_processor_id())->c[idx]++; 10 srcu_barrier(); 11 preempt_enable(); 12 return idx; 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure13122}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void srcu_read_unlock(struct srcu_struct *sp, int idx) 2 { 3 preempt_disable(); 4 srcu_barrier(); 5 per_cpu_ptr(sp->per_cpu_ref, 6 smp_processor_id())->c[idx]--; 7 preempt_enable(); 8 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure13147}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void synchronize_srcu(struct srcu_struct *sp) 2 { 3 int idx; 4 5 idx = sp->completed; 6 mutex_lock(&sp->mutex); 7 if ((sp->completed - idx) >= 2) { 8 mutex_unlock(&sp->mutex); 9 return; 10 } 11 synchronize_sched(); 12 idx = sp->completed & 0x1; 13 sp->completed++; 14 synchronize_sched(); 15 while (srcu_readers_active_idx(sp, idx)) 16 schedule_timeout_interruptible(1); 17 synchronize_sched(); 18 mutex_unlock(&sp->mutex); 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13916}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/FlatClassicRCU}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13940}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCU}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13950}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeMapping}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13958}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCUGP}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13966}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCU}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap13988}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBH}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap14010}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBHdyntick}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap14022}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GenericRCUStateMachine}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap14034}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeRCUStateMachine}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figurestar14631}% \begin{figure*}{ \begin{verbatim} 1 #define MAX_RCU_LVLS 3 2 #define RCU_FANOUT (CONFIG_RCU_FANOUT) 3 #define RCU_FANOUT_SQ (RCU_FANOUT * RCU_FANOUT) 4 #define RCU_FANOUT_CUBE (RCU_FANOUT_SQ * RCU_FANOUT) 5 6 #if NR_CPUS <= RCU_FANOUT 7 # define NUM_RCU_LVLS 1 8 # define NUM_RCU_LVL_0 1 9 # define NUM_RCU_LVL_1 (NR_CPUS) 10 # define NUM_RCU_LVL_2 0 11 # define NUM_RCU_LVL_3 0 12 #elif NR_CPUS <= RCU_FANOUT_SQ 13 # define NUM_RCU_LVLS 2 14 # define NUM_RCU_LVL_0 1 15 # define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT) 16 # define NUM_RCU_LVL_2 (NR_CPUS) 17 # define NUM_RCU_LVL_3 0 18 #elif NR_CPUS <= RCU_FANOUT_CUBE 19 # define NUM_RCU_LVLS 3 20 # define NUM_RCU_LVL_0 1 21 # define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ) 22 # define NUM_RCU_LVL_2 (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT)) 23 # define NUM_RCU_LVL_3 NR_CPUS 24 #else 25 # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" 26 #endif /* #if (NR_CPUS) <= RCU_FANOUT */ 27 28 #define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) 29 #define NUM_RCU_NODES (RCU_SUM - NR_CPUS)\end{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14685}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void __rcu_read_lock(void) 2 { 3 preempt_disable(); 4 __acquire(RCU); 5 rcu_read_acquire(); 6 } 7 8 void __rcu_read_unlock(void) 9 { 10 rcu_read_release(); 11 __release(RCU); 12 preempt_enable(); 13 } 14 15 void __rcu_read_lock_bh(void) 16 { 17 local_bh_disable(); 18 __acquire(RCU_BH); 19 rcu_read_acquire(); 20 } 21 22 void __rcu_read_unlock_bh(void) 23 { 24 rcu_read_release(); 25 __release(RCU_BH); 26 local_bh_enable(); 27 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14704}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 __call_rcu(struct rcu_head *head, 3 void (*func)(struct rcu_head *rcu), 4 struct rcu_state *rsp) 5 { 6 unsigned long flags; 7 struct rcu_data *rdp; 8 9 head->func = func; 10 head->next = NULL; 11 smp_mb(); 12 local_irq_save(flags); 13 rdp = rsp->rda[smp_processor_id()]; 14 rcu_process_gp_end(rsp, rdp); 15 check_for_new_grace_period(rsp, rdp); 16 *rdp->nxttail[RCU_NEXT_TAIL] = head; 17 rdp->nxttail[RCU_NEXT_TAIL] = &head->next; 18 if (ACCESS_ONCE(rsp->completed) == 19 ACCESS_ONCE(rsp->gpnum)) { 20 unsigned long nestflag; 21 struct rcu_node *rnp_root = rcu_get_root(rsp); 22 23 spin_lock_irqsave(&rnp_root->lock, nestflag); 24 rcu_start_gp(rsp, nestflag); 25 } 26 if (unlikely(++rdp->qlen > qhimark)) { 27 rdp->blimit = LONG_MAX; 28 force_quiescent_state(rsp, 0); 29 } else if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - 30 jiffies) < 0 || 31 (rdp->n_rcu_pending_force_qs - 32 rdp->n_rcu_pending) < 0) 33 force_quiescent_state(rsp, 1); 34 local_irq_restore(flags); 35 } 36 37 void call_rcu(struct rcu_head *head, 38 void (*func)(struct rcu_head *rcu)) 39 { 40 __call_rcu(head, func, &rcu_state); 41 } 42 43 void call_rcu_bh(struct rcu_head *head, 44 void (*func)(struct rcu_head *rcu)) 45 { 46 __call_rcu(head, func, &rcu_bh_state); 47 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14737}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int __rcu_pending(struct rcu_state *rsp, 2 struct rcu_data *rdp) 3 { 4 rdp->n_rcu_pending++; 5 6 check_cpu_stall(rsp, rdp); 7 if (rdp->qs_pending) 8 return 1; 9 if (cpu_has_callbacks_ready_to_invoke(rdp)) 10 return 1; 11 if (cpu_needs_another_gp(rsp, rdp)) 12 return 1; 13 if (ACCESS_ONCE(rsp->completed) != rdp->completed) 14 return 1; 15 if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) 16 return 1; 17 if (ACCESS_ONCE(rsp->completed) != 18 ACCESS_ONCE(rsp->gpnum) && 19 ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - 20 jiffies) < 0 || 21 (rdp->n_rcu_pending_force_qs - 22 rdp->n_rcu_pending) < 0)) 23 return 1; 24 return 0; 25 } 26 27 int rcu_pending(int cpu) 28 { 29 return __rcu_pending(&rcu_state, 30 &per_cpu(rcu_data, cpu)) || 31 __rcu_pending(&rcu_bh_state, 32 &per_cpu(rcu_bh_data, cpu)); 33 } 34 35 void rcu_check_callbacks(int cpu, int user) 36 { 37 if (user || 38 (idle_cpu(cpu) && !in_softirq() && 39 hardirq_count() <= (1 << HARDIRQ_SHIFT))) { 40 rcu_qsctr_inc(cpu); 41 rcu_bh_qsctr_inc(cpu); 42 } else if (!in_softirq()) { 43 rcu_bh_qsctr_inc(cpu); 44 } 45 raise_softirq(RCU_SOFTIRQ); 46 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14774}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 __rcu_process_callbacks(struct rcu_state *rsp, 3 struct rcu_data *rdp) 4 { 5 unsigned long flags; 6 7 if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - 8 jiffies) < 0 || 9 (rdp->n_rcu_pending_force_qs - 10 rdp->n_rcu_pending) < 0) 11 force_quiescent_state(rsp, 1); 12 rcu_process_gp_end(rsp, rdp); 13 rcu_check_quiescent_state(rsp, rdp); 14 if (cpu_needs_another_gp(rsp, rdp)) { 15 spin_lock_irqsave(&rcu_get_root(rsp)->lock, flags); 16 rcu_start_gp(rsp, flags); 17 } 18 rcu_do_batch(rdp); 19 } 20 21 static void 22 rcu_process_callbacks(struct softirq_action *unused) 23 { 24 smp_mb(); 25 __rcu_process_callbacks(&rcu_state, 26 &__get_cpu_var(rcu_data)); 27 __rcu_process_callbacks(&rcu_bh_state, 28 &__get_cpu_var(rcu_bh_data)); 29 smp_mb(); 30 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14806}% \begin{figure}{ \scriptsize \begin{verbatim} 1 int rcu_needs_cpu(int cpu) 2 { 3 return per_cpu(rcu_data, cpu).nxtlist || 4 per_cpu(rcu_bh_data, cpu).nxtlist; 5 } 6 7 static int __cpuinit 8 rcu_cpu_notify(struct notifier_block *self, 9 unsigned long action, void *hcpu) 10 { 11 long cpu = (long)hcpu; 12 13 switch (action) { 14 case CPU_UP_PREPARE: 15 case CPU_UP_PREPARE_FROZEN: 16 rcu_online_cpu(cpu); 17 break; 18 case CPU_DEAD: 19 case CPU_DEAD_FROZEN: 20 case CPU_UP_CANCELED: 21 case CPU_UP_CANCELED_FROZEN: 22 rcu_offline_cpu(cpu); 23 break; 24 default: 25 break; 26 } 27 return NOTIFY_OK; 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap16031}% \resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeInit}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14860}% \begin{figure}{ \scriptsize \begin{verbatim} 1 #ifdef CONFIG_RCU_FANOUT_EXACT 2 static void __init 3 rcu_init_levelspread(struct rcu_state *rsp) 4 { 5 int i; 6 7 for (i = NUM_RCU_LVLS - 1; i >= 0; i--) 8 rsp->levelspread[i] = CONFIG_RCU_FANOUT; 9 } 10 #else 11 static void __init 12 rcu_init_levelspread(struct rcu_state *rsp) 13 { 14 int ccur; 15 int cprv; 16 int i; 17 18 cprv = NR_CPUS; 19 for (i = NUM_RCU_LVLS - 1; i >= 0; i--) { 20 ccur = rsp->levelcnt[i]; 21 rsp->levelspread[i] = (cprv + ccur - 1) / ccur; 22 cprv = ccur; 23 } 24 } 25 #endif\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14891}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void __init rcu_init_one(struct rcu_state *rsp) 2 { 3 int cpustride = 1; 4 int i; 5 int j; 6 struct rcu_node *rnp; 7 8 for (i = 1; i < NUM_RCU_LVLS; i++) 9 rsp->level[i] = rsp->level[i - 1] + 10 rsp->levelcnt[i - 1]; 11 rcu_init_levelspread(rsp); 12 for (i = NUM_RCU_LVLS - 1; i >= 0; i--) { 13 cpustride *= rsp->levelspread[i]; 14 rnp = rsp->level[i]; 15 for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) { 16 spin_lock_init(&rnp->lock); 17 rnp->qsmask = 0; 18 rnp->qsmaskinit = 0; 19 rnp->grplo = j * cpustride; 20 rnp->grphi = (j + 1) * cpustride - 1; 21 if (rnp->grphi >= NR_CPUS) 22 rnp->grphi = NR_CPUS - 1; 23 if (i == 0) { 24 rnp->grpnum = 0; 25 rnp->grpmask = 0; 26 rnp->parent = NULL; 27 } else { 28 rnp->grpnum = j % rsp->levelspread[i - 1]; 29 rnp->grpmask = 1UL << rnp->grpnum; 30 rnp->parent = rsp->level[i - 1] + 31 j / rsp->levelspread[i - 1]; 32 } 33 rnp->level = i; 34 } 35 } 36 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14939}% \begin{figure}{ \scriptsize \begin{verbatim} 1 #define RCU_DATA_PTR_INIT(rsp, rcu_data) \ 2 do { \ 3 rnp = (rsp)->level[NUM_RCU_LVLS - 1]; \ 4 j = 0; \ 5 for_each_possible_cpu(i) { \ 6 if (i > rnp[j].grphi) \ 7 j++; \ 8 per_cpu(rcu_data, i).mynode = &rnp[j]; \ 9 (rsp)->rda[i] = &per_cpu(rcu_data, i); \ 10 } \ 11 } while (0) 12 13 void __init __rcu_init(void) 14 { 15 int i; 16 int j; 17 struct rcu_node *rnp; 18 19 rcu_init_one(&rcu_state); 20 RCU_DATA_PTR_INIT(&rcu_state, rcu_data); 21 rcu_init_one(&rcu_bh_state); 22 RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); 23 24 for_each_online_cpu(i) 25 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, 26 (void *)(long)i); 27 register_cpu_notifier(&rcu_nb); 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure14996}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 rcu_init_percpu_data(int cpu, struct rcu_state *rsp) 3 { 4 unsigned long flags; 5 int i; 6 long lastcomp; 7 unsigned long mask; 8 struct rcu_data *rdp = rsp->rda[cpu]; 9 struct rcu_node *rnp = rcu_get_root(rsp); 10 11 spin_lock_irqsave(&rnp->lock, flags); 12 lastcomp = rsp->completed; 13 rdp->completed = lastcomp; 14 rdp->gpnum = lastcomp; 15 rdp->passed_quiesc = 0; 16 rdp->qs_pending = 1; 17 rdp->beenonline = 1; 18 rdp->passed_quiesc_completed = lastcomp - 1; 19 rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); 20 rdp->nxtlist = NULL; 21 for (i = 0; i < RCU_NEXT_SIZE; i++) 22 rdp->nxttail[i] = &rdp->nxtlist; 23 rdp->qlen = 0; 24 rdp->blimit = blimit; 25 #ifdef CONFIG_NO_HZ 26 rdp->dynticks = &per_cpu(rcu_dynticks, cpu); 27 #endif /* #ifdef CONFIG_NO_HZ */ 28 rdp->cpu = cpu; 29 spin_unlock(&rnp->lock); 30 spin_lock(&rsp->onofflock); 31 rnp = rdp->mynode; 32 mask = rdp->grpmask; 33 do { 34 spin_lock(&rnp->lock); 35 rnp->qsmaskinit |= mask; 36 mask = rnp->grpmask; 37 spin_unlock(&rnp->lock); 38 rnp = rnp->parent; 39 } while (rnp != NULL && !(rnp->qsmaskinit & mask)); 40 spin_unlock(&rsp->onofflock); 41 cpu_quiet(cpu, rsp, rdp, lastcomp); 42 local_irq_restore(flags); 43 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15031}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void __cpuinit rcu_online_cpu(int cpu) 2 { 3 #ifdef CONFIG_NO_HZ 4 struct rcu_dynticks *rdtp; 5 6 rdtp = &per_cpu(rcu_dynticks, cpu); 7 rdtp->dynticks_nesting = 1; 8 rdtp->dynticks |= 1; 9 rdtp->dynticks_nmi = (rdtp->dynticks_nmi + 1) & ~0x1; 10 #endif /* #ifdef CONFIG_NO_HZ */ 11 rcu_init_percpu_data(cpu, &rcu_state); 12 rcu_init_percpu_data(cpu, &rcu_bh_state); 13 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 14 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15051}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 __rcu_offline_cpu(int cpu, struct rcu_state *rsp) 3 { 4 int i; 5 unsigned long flags; 6 long lastcomp; 7 unsigned long mask; 8 struct rcu_data *rdp = rsp->rda[cpu]; 9 struct rcu_data *rdp_me; 10 struct rcu_node *rnp; 11 12 spin_lock_irqsave(&rsp->onofflock, flags); 13 rnp = rdp->mynode; 14 mask = rdp->grpmask; 15 do { 16 spin_lock(&rnp->lock); 17 rnp->qsmaskinit &= ~mask; 18 if (rnp->qsmaskinit != 0) { 19 spin_unlock(&rnp->lock); 20 break; 21 } 22 mask = rnp->grpmask; 23 spin_unlock(&rnp->lock); 24 rnp = rnp->parent; 25 } while (rnp != NULL); 26 lastcomp = rsp->completed; 27 spin_unlock(&rsp->onofflock); 28 cpu_quiet(cpu, rsp, rdp, lastcomp); 29 rdp_me = rsp->rda[smp_processor_id()]; 30 if (rdp->nxtlist != NULL) { 31 *rdp_me->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist; 32 rdp_me->nxttail[RCU_NEXT_TAIL] = 33 rdp->nxttail[RCU_NEXT_TAIL]; 34 rdp->nxtlist = NULL; 35 for (i = 0; i < RCU_NEXT_SIZE; i++) 36 rdp->nxttail[i] = &rdp->nxtlist; 37 rdp_me->qlen += rdp->qlen; 38 rdp->qlen = 0; 39 } 40 local_irq_restore(flags); 41 } 42 43 static void rcu_offline_cpu(int cpu) 44 { 45 __rcu_offline_cpu(cpu, &rcu_state); 46 __rcu_offline_cpu(cpu, &rcu_bh_state); 47 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure15120}% \begin{figure}{ \scriptsize \begin{verbatim} 1 long rcu_batches_completed(void) 2 { 3 return rcu_state.completed; 4 } 5 6 long rcu_batches_completed_bh(void) 7 { 8 return rcu_bh_state.completed; 9 } 10 11 static int 12 cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) 13 { 14 return &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]; 15 } 16 17 static int 18 cpu_needs_another_gp(struct rcu_state *rsp, 19 struct rcu_data *rdp) 20 { 21 return *rdp->nxttail[RCU_DONE_TAIL] && 22 ACCESS_ONCE(rsp->completed) == 23 ACCESS_ONCE(rsp->gpnum); 24 } 25 26 static struct rcu_node 27 *rcu_get_root(struct rcu_state *rsp) 28 { 29 return &rsp->node[0]; 30 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15147}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void note_new_gpnum(struct rcu_state *rsp, 2 struct rcu_data *rdp) 3 { 4 rdp->qs_pending = 1; 5 rdp->passed_quiesc = 0; 6 rdp->gpnum = rsp->gpnum; 7 rdp->n_rcu_pending_force_qs = rdp->n_rcu_pending + 8 RCU_JIFFIES_TILL_FORCE_QS; 9 } 10 11 static int 12 check_for_new_grace_period(struct rcu_state *rsp, 13 struct rcu_data *rdp) 14 { 15 unsigned long flags; 16 int ret = 0; 17 18 local_irq_save(flags); 19 if (rdp->gpnum != rsp->gpnum) { 20 note_new_gpnum(rsp, rdp); 21 ret = 1; 22 } 23 local_irq_restore(flags); 24 return ret; 25 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15172}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 rcu_process_gp_end(struct rcu_state *rsp, 3 struct rcu_data *rdp) 4 { 5 long completed_snap; 6 unsigned long flags; 7 8 local_irq_save(flags); 9 completed_snap = ACCESS_ONCE(rsp->completed); 10 if (rdp->completed != completed_snap) { 11 rdp->nxttail[RCU_DONE_TAIL] = 12 rdp->nxttail[RCU_WAIT_TAIL]; 13 rdp->nxttail[RCU_WAIT_TAIL] = 14 rdp->nxttail[RCU_NEXT_READY_TAIL]; 15 rdp->nxttail[RCU_NEXT_READY_TAIL] = 16 rdp->nxttail[RCU_NEXT_TAIL]; 17 rdp->completed = completed_snap; 18 } 19 local_irq_restore(flags); 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap16247}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/AdvanceRCUCallbacks}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15201}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 rcu_start_gp(struct rcu_state *rsp, unsigned long flags) 3 __releases(rcu_get_root(rsp)->lock) 4 { 5 struct rcu_data *rdp = rsp->rda[smp_processor_id()]; 6 struct rcu_node *rnp = rcu_get_root(rsp); 7 struct rcu_node *rnp_cur; 8 struct rcu_node *rnp_end; 9 10 if (!cpu_needs_another_gp(rsp, rdp)) { 11 spin_unlock_irqrestore(&rnp->lock, flags); 12 return; 13 } 14 rsp->gpnum++; 15 rsp->signaled = RCU_GP_INIT; 16 rsp->jiffies_force_qs = jiffies + 17 RCU_JIFFIES_TILL_FORCE_QS; 18 rdp->n_rcu_pending_force_qs = rdp->n_rcu_pending + 19 RCU_JIFFIES_TILL_FORCE_QS; 20 record_gp_stall_check_time(rsp); 21 dyntick_record_completed(rsp, rsp->completed - 1); 22 note_new_gpnum(rsp, rdp); 23 rdp->nxttail[RCU_NEXT_READY_TAIL] = 24 rdp->nxttail[RCU_NEXT_TAIL]; 25 rdp->nxttail[RCU_WAIT_TAIL] = 26 rdp->nxttail[RCU_NEXT_TAIL]; 27 if (NUM_RCU_NODES == 1) { 28 rnp->qsmask = rnp->qsmaskinit; 29 spin_unlock_irqrestore(&rnp->lock, flags); 30 return; 31 } 32 spin_unlock(&rnp->lock); 33 spin_lock(&rsp->onofflock); 34 rnp_end = rsp->level[NUM_RCU_LVLS - 1]; 35 rnp_cur = &rsp->node[0]; 36 for (; rnp_cur < rnp_end; rnp_cur++) 37 rnp_cur->qsmask = rnp_cur->qsmaskinit; 38 rnp_end = &rsp->node[NUM_RCU_NODES]; 39 rnp_cur = rsp->level[NUM_RCU_LVLS - 1]; 40 for (; rnp_cur < rnp_end; rnp_cur++) { 41 spin_lock(&rnp_cur->lock); 42 rnp_cur->qsmask = rnp_cur->qsmaskinit; 43 spin_unlock(&rnp_cur->lock); 44 } 45 rsp->signaled = RCU_SIGNAL_INIT; 46 spin_unlock_irqrestore(&rsp->onofflock, flags); 47 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15281}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_qsctr_inc(int cpu) 2 { 3 struct rcu_data *rdp = &per_cpu(rcu_data, cpu); 4 rdp->passed_quiesc = 1; 5 rdp->passed_quiesc_completed = rdp->completed; 6 } 7 8 void rcu_bh_qsctr_inc(int cpu) 9 { 10 struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); 11 rdp->passed_quiesc = 1; 12 rdp->passed_quiesc_completed = rdp->completed; 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15300}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 rcu_check_quiescent_state(struct rcu_state *rsp, 3 struct rcu_data *rdp) 4 { 5 if (check_for_new_grace_period(rsp, rdp)) 6 return; 7 if (!rdp->qs_pending) 8 return; 9 if (!rdp->passed_quiesc) 10 return; 11 cpu_quiet(rdp->cpu, rsp, rdp, 12 rdp->passed_quiesc_completed); 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15317}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 cpu_quiet(int cpu, struct rcu_state *rsp, 3 struct rcu_data *rdp, long lastcomp) 4 { 5 unsigned long flags; 6 unsigned long mask; 7 struct rcu_node *rnp; 8 9 rnp = rdp->mynode; 10 spin_lock_irqsave(&rnp->lock, flags); 11 if (lastcomp != ACCESS_ONCE(rsp->completed)) { 12 rdp->passed_quiesc = 0; 13 spin_unlock_irqrestore(&rnp->lock, flags); 14 return; 15 } 16 mask = rdp->grpmask; 17 if ((rnp->qsmask & mask) == 0) { 18 spin_unlock_irqrestore(&rnp->lock, flags); 19 } else { 20 rdp->qs_pending = 0; 21 rdp = rsp->rda[smp_processor_id()]; 22 rdp->nxttail[RCU_NEXT_READY_TAIL] = 23 rdp->nxttail[RCU_NEXT_TAIL]; 24 cpu_quiet_msk(mask, rsp, rnp, flags); 25 } 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15336}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, 3 struct rcu_node *rnp, unsigned long flags) 4 __releases(rnp->lock) 5 { 6 for (;;) { 7 if (!(rnp->qsmask & mask)) { 8 spin_unlock_irqrestore(&rnp->lock, flags); 9 return; 10 } 11 rnp->qsmask &= ~mask; 12 if (rnp->qsmask != 0) { 13 spin_unlock_irqrestore(&rnp->lock, flags); 14 return; 15 } 16 mask = rnp->grpmask; 17 if (rnp->parent == NULL) { 18 break; 19 } 20 spin_unlock_irqrestore(&rnp->lock, flags); 21 rnp = rnp->parent; 22 spin_lock_irqsave(&rnp->lock, flags); 23 } 24 rsp->completed = rsp->gpnum; 25 rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]); 26 rcu_start_gp(rsp, flags); 27 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap16365}% \resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeQSScan}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15384}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_do_batch(struct rcu_data *rdp) 2 { 3 unsigned long flags; 4 struct rcu_head *next, *list, **tail; 5 int count; 6 7 if (!cpu_has_callbacks_ready_to_invoke(rdp)) 8 return; 9 local_irq_save(flags); 10 list = rdp->nxtlist; 11 rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL]; 12 *rdp->nxttail[RCU_DONE_TAIL] = NULL; 13 tail = rdp->nxttail[RCU_DONE_TAIL]; 14 for (count = RCU_NEXT_SIZE - 1; count >= 0; count--) 15 if (rdp->nxttail[count] == 16 rdp->nxttail[RCU_DONE_TAIL]) 17 rdp->nxttail[count] = &rdp->nxtlist; 18 local_irq_restore(flags); 19 count = 0; 20 while (list) { 21 next = list->next; 22 prefetch(next); 23 list->func(list); 24 list = next; 25 if (++count >= rdp->blimit) 26 break; 27 } 28 local_irq_save(flags); 29 rdp->qlen -= count; 30 if (list != NULL) { 31 *tail = rdp->nxtlist; 32 rdp->nxtlist = list; 33 for (count = 0; count < RCU_NEXT_SIZE; count++) 34 if (&rdp->nxtlist == rdp->nxttail[count]) 35 rdp->nxttail[count] = tail; 36 else 37 break; 38 } 39 if (rdp->blimit == LONG_MAX && rdp->qlen <= qlowmark) 40 rdp->blimit = blimit; 41 local_irq_restore(flags); 42 if (cpu_has_callbacks_ready_to_invoke(rdp)) 43 raise_softirq(RCU_SOFTIRQ); 44 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15412}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_enter_nohz(void) 2 { 3 unsigned long flags; 4 struct rcu_dynticks *rdtp; 5 6 smp_mb(); 7 local_irq_save(flags); 8 rdtp = &__get_cpu_var(rcu_dynticks); 9 rdtp->dynticks++; 10 rdtp->dynticks_nesting--; 11 local_irq_restore(flags); 12 } 13 14 void rcu_exit_nohz(void) 15 { 16 unsigned long flags; 17 struct rcu_dynticks *rdtp; 18 19 local_irq_save(flags); 20 rdtp = &__get_cpu_var(rcu_dynticks); 21 rdtp->dynticks++; 22 rdtp->dynticks_nesting++; 23 local_irq_restore(flags); 24 smp_mb(); 25 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15433}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_nmi_enter(void) 2 { 3 struct rcu_dynticks *rdtp; 4 5 rdtp = &__get_cpu_var(rcu_dynticks); 6 if (rdtp->dynticks & 0x1) 7 return; 8 rdtp->dynticks_nmi++; 9 smp_mb(); 10 } 11 12 void rcu_nmi_exit(void) 13 { 14 struct rcu_dynticks *rdtp; 15 16 rdtp = &__get_cpu_var(rcu_dynticks); 17 if (rdtp->dynticks & 0x1) 18 return; 19 smp_mb(); 20 rdtp->dynticks_nmi++;\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15454}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_irq_enter(void) 2 { 3 struct rcu_dynticks *rdtp; 4 5 rdtp = &__get_cpu_var(rcu_dynticks); 6 if (rdtp->dynticks_nesting++) 7 return; 8 rdtp->dynticks++; 9 smp_mb(); 10 } 11 12 void rcu_irq_exit(void) 13 { 14 struct rcu_dynticks *rdtp; 15 16 rdtp = &__get_cpu_var(rcu_dynticks); 17 if (--rdtp->dynticks_nesting) 18 return; 19 smp_mb(); 20 rdtp->dynticks++; 21 if (__get_cpu_var(rcu_data).nxtlist || 22 __get_cpu_var(rcu_bh_data).nxtlist) 23 set_need_resched(); 24 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15479}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int 2 dyntick_save_progress_counter(struct rcu_data *rdp) 3 { 4 int ret; 5 int snap; 6 int snap_nmi; 7 8 snap = rdp->dynticks->dynticks; 9 snap_nmi = rdp->dynticks->dynticks_nmi; 10 smp_mb(); 11 rdp->dynticks_snap = snap; 12 rdp->dynticks_nmi_snap = snap_nmi; 13 ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); 14 if (ret) 15 rdp->dynticks_fqs++; 16 return ret; 17 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15505}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int 2 rcu_implicit_dynticks_qs(struct rcu_data *rdp) 3 { 4 long curr; 5 long curr_nmi; 6 long snap; 7 long snap_nmi; 8 9 curr = rdp->dynticks->dynticks; 10 snap = rdp->dynticks_snap; 11 curr_nmi = rdp->dynticks->dynticks_nmi; 12 snap_nmi = rdp->dynticks_nmi_snap; 13 smp_mb(); 14 if ((curr != snap || (curr & 0x1) == 0) && 15 (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { 16 rdp->dynticks_fqs++; 17 return 1; 18 } 19 return rcu_implicit_offline_qs(rdp); 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15545}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 dyntick_record_completed(struct rcu_state *rsp, 3 long comp) 4 { 5 rsp->dynticks_completed = comp; 6 } 7 8 static long 9 dyntick_recall_completed(struct rcu_state *rsp) 10 { 11 return rsp->dynticks_completed; 12 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15564}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int rcu_implicit_offline_qs(struct rcu_data *rdp) 2 { 3 if (cpu_is_offline(rdp->cpu)) { 4 rdp->offline_fqs++; 5 return 1; 6 } 7 if (rdp->cpu != smp_processor_id()) 8 smp_send_reschedule(rdp->cpu); 9 else 10 set_need_resched(); 11 rdp->resched_ipi++; 12 return 0; 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15577}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int 2 rcu_process_dyntick(struct rcu_state *rsp, 3 long lastcomp, 4 int (*f)(struct rcu_data *)) 5 { 6 unsigned long bit; 7 int cpu; 8 unsigned long flags; 9 unsigned long mask; 10 struct rcu_node *rnp_cur; 11 struct rcu_node *rnp_end; 12 13 rnp_cur = rsp->level[NUM_RCU_LVLS - 1]; 14 rnp_end = &rsp->node[NUM_RCU_NODES]; 15 for (; rnp_cur < rnp_end; rnp_cur++) { 16 mask = 0; 17 spin_lock_irqsave(&rnp_cur->lock, flags); 18 if (rsp->completed != lastcomp) { 19 spin_unlock_irqrestore(&rnp_cur->lock, flags); 20 return 1; 21 } 22 if (rnp_cur->qsmask == 0) { 23 spin_unlock_irqrestore(&rnp_cur->lock, flags); 24 continue; 25 } 26 cpu = rnp_cur->grplo; 27 bit = 1; 28 for (; cpu <= rnp_cur->grphi; cpu++, bit <<= 1) { 29 if ((rnp_cur->qsmask & bit) != 0 && 30 f(rsp->rda[cpu])) 31 mask |= bit; 32 } 33 if (mask != 0 && rsp->completed == lastcomp) { 34 cpu_quiet_msk(mask, rsp, rnp_cur, flags); 35 continue; 36 } 37 spin_unlock_irqrestore(&rnp_cur->lock, flags); 38 } 39 return 0; 40 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap16521}% \resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeLeafScan}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlfigureA{figure15622}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 force_quiescent_state(struct rcu_state *rsp, int relaxed) 3 { 4 unsigned long flags; 5 long lastcomp; 6 struct rcu_data *rdp = rsp->rda[smp_processor_id()]; 7 struct rcu_node *rnp = rcu_get_root(rsp); 8 u8 signaled; 9 10 if (ACCESS_ONCE(rsp->completed) == 11 ACCESS_ONCE(rsp->gpnum)) 12 return; 13 if (!spin_trylock_irqsave(&rsp->fqslock, flags)) { 14 rsp->n_force_qs_lh++; 15 return; 16 } 17 if (relaxed && 18 (long)(rsp->jiffies_force_qs - jiffies) >= 0 && 19 (rdp->n_rcu_pending_force_qs - 20 rdp->n_rcu_pending) >= 0) 21 goto unlock_ret; 22 rsp->n_force_qs++; 23 spin_lock(&rnp->lock); 24 lastcomp = rsp->completed; 25 signaled = rsp->signaled; 26 rsp->jiffies_force_qs = 27 jiffies + RCU_JIFFIES_TILL_FORCE_QS; 28 rdp->n_rcu_pending_force_qs = 29 rdp->n_rcu_pending + 30 RCU_JIFFIES_TILL_FORCE_QS; 31 if (lastcomp == rsp->gpnum) { 32 rsp->n_force_qs_ngp++; 33 spin_unlock(&rnp->lock); 34 goto unlock_ret; 35 } 36 spin_unlock(&rnp->lock); 37 switch (signaled) { 38 case RCU_GP_INIT: 39 break; 40 case RCU_SAVE_DYNTICK: 41 if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK) 42 break; 43 if (rcu_process_dyntick(rsp, lastcomp, 44 dyntick_save_progress_counter)) 45 goto unlock_ret; 46 spin_lock(&rnp->lock); 47 if (lastcomp == rsp->completed) { 48 rsp->signaled = RCU_FORCE_QS; 49 dyntick_record_completed(rsp, lastcomp); 50 } 51 spin_unlock(&rnp->lock); 52 break; 53 case RCU_FORCE_QS: 54 if (rcu_process_dyntick(rsp, 55 dyntick_recall_completed(rsp), 56 rcu_implicit_dynticks_qs)) 57 goto unlock_ret; 58 break; 59 } 60 unlock_ret: 61 spin_unlock_irqrestore(&rsp->fqslock, flags); 62 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure15680}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 record_gp_stall_check_time(struct rcu_state *rsp) 3 { 4 rsp->gp_start = jiffies; 5 rsp->jiffies_stall = 6 jiffies + RCU_SECONDS_TILL_STALL_CHECK; 7 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15688}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void 2 check_cpu_stall(struct rcu_state *rsp, 3 struct rcu_data *rdp) 4 { 5 long delta; 6 struct rcu_node *rnp; 7 8 delta = jiffies - rsp->jiffies_stall; 9 rnp = rdp->mynode; 10 if ((rnp->qsmask & rdp->grpmask) && delta >= 0) { 11 print_cpu_stall(rsp); 12 } else if (rsp->gpnum != rsp->completed && 13 delta >= RCU_STALL_RAT_DELAY) { 14 print_other_cpu_stall(rsp); 15 } 16 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15704}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void print_cpu_stall(struct rcu_state *rsp) 2 { 3 unsigned long flags; 4 struct rcu_node *rnp = rcu_get_root(rsp); 5 6 printk(KERN_ERR 7 "INFO: RCU detected CPU %d stall " 8 "(t=%lu jiffies)\n", 9 smp_processor_id(), 10 jiffies - rsp->gp_start); 11 dump_stack(); 12 spin_lock_irqsave(&rnp->lock, flags); 13 if ((long)(jiffies - rsp->jiffies_stall) >= 0) 14 rsp->jiffies_stall = 15 jiffies + RCU_SECONDS_TILL_STALL_RECHECK; 16 spin_unlock_irqrestore(&rnp->lock, flags); 17 set_need_resched(); 18 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure15715}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void print_other_cpu_stall(struct rcu_state *rsp) 2 { 3 int cpu; 4 long delta; 5 unsigned long flags; 6 struct rcu_node *rnp = rcu_get_root(rsp); 7 struct rcu_node *rnp_cur; 8 struct rcu_node *rnp_end; 9 10 rnp_cur = rsp->level[NUM_RCU_LVLS - 1]; 11 rnp_end = &rsp->node[NUM_RCU_NODES]; 12 spin_lock_irqsave(&rnp->lock, flags); 13 delta = jiffies - rsp->jiffies_stall; 14 if (delta < RCU_STALL_RAT_DELAY || 15 rsp->gpnum == rsp->completed) { 16 spin_unlock_irqrestore(&rnp->lock, flags); 17 return; 18 } 19 rsp->jiffies_stall = jiffies + 20 RCU_SECONDS_TILL_STALL_RECHECK; 21 spin_unlock_irqrestore(&rnp->lock, flags); 22 printk(KERN_ERR "INFO: RCU detected CPU stalls:"); 23 for (; rnp_cur < rnp_end; rnp_cur++) { 24 if (rnp_cur->qsmask == 0) 25 continue; 26 cpu = 0; 27 for (; cpu <= rnp_cur->grphi - rnp_cur->grplo; cpu++) 28 if (rnp_cur->qsmask & (1UL << cpu)) 29 printk(" %d", rnp_cur->grplo + cpu); 30 } 31 printk(" (detected by %d, t=%ld jiffies)\n", 32 smp_processor_id(), 33 (long)(jiffies - rsp->gp_start)); 34 force_quiescent_state(rsp, 0); 35 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17165}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodBad}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17175}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodGood}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17189}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptListsCompare}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17199}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptCounterFlip}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{paragraph} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17239}% \resizebox{1.5in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptLists}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{paragraph} \stepcounter{subsubsection} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17281}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptStates}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17289}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptTimeline}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} {\newpage\clearpage \lthtmlfigureA{figure16854}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_check_callbacks(int cpu, int user) 2 { 3 unsigned long flags; 4 struct rcu_data *rdp = RCU_DATA_CPU(cpu); 5 6 rcu_check_mb(cpu); 7 if (rcu_ctrlblk.completed == rdp->completed) 8 rcu_try_flip(); 9 spin_lock_irqsave(&rdp->lock, flags); 10 RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); 11 __rcu_advance_callbacks(rdp); 12 spin_unlock_irqrestore(&rdp->lock, flags); 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16866}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_check_mb(int cpu) 2 { 3 if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) { 4 smp_mb(); 5 per_cpu(rcu_mb_flag, cpu) = rcu_mb_done; 6 } 7 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16875}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void rcu_try_flip(void) 2 { 3 unsigned long flags; 4 5 RCU_TRACE_ME(rcupreempt_trace_try_flip_1); 6 if (!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, flags)) { 7 RCU_TRACE_ME(rcupreempt_trace_try_flip_e1); 8 return; 9 } 10 switch (rcu_try_flip_state) { 11 case rcu_try_flip_idle_state: 12 if (rcu_try_flip_idle()) 13 rcu_try_flip_state = rcu_try_flip_waitack_state; 14 break; 15 case rcu_try_flip_waitack_state: 16 if (rcu_try_flip_waitack()) 17 rcu_try_flip_state = rcu_try_flip_waitzero_state; 18 break; 19 case rcu_try_flip_waitzero_state: 20 if (rcu_try_flip_waitzero()) 21 rcu_try_flip_state = rcu_try_flip_waitmb_state; 22 break; 23 case rcu_try_flip_waitmb_state: 24 if (rcu_try_flip_waitmb()) 25 rcu_try_flip_state = rcu_try_flip_idle_state; 26 } 27 spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); 28 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16884}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int rcu_try_flip_idle(void) 2 { 3 int cpu; 4 5 RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); 6 if (!rcu_pending(smp_processor_id())) { 7 RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); 8 return 0; 9 } 10 RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); 11 rcu_ctrlblk.completed++; 12 smp_mb(); 13 for_each_cpu_mask(cpu, rcu_cpu_online_map) 14 per_cpu(rcu_flip_flag, cpu) = rcu_flipped; 15 return 1; 16 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16893}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int rcu_try_flip_waitack(void) 2 { 3 int cpu; 4 5 RCU_TRACE_ME(rcupreempt_trace_try_flip_a1); 6 for_each_cpu_mask(cpu, rcu_cpu_online_map) 7 if (per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) { 8 RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1); 9 return 0; 10 } 11 smp_mb(); 12 RCU_TRACE_ME(rcupreempt_trace_try_flip_a2); 13 return 1; 14 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16904}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int rcu_try_flip_waitzero(void) 2 { 3 int cpu; 4 int lastidx = !(rcu_ctrlblk.completed & 0x1); 5 int sum = 0; 6 7 RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); 8 for_each_possible_cpu(cpu) 9 sum += per_cpu(rcu_flipctr, cpu)[lastidx]; 10 if (sum != 0) { 11 RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); 12 return 0; 13 } 14 smp_mb(); 15 for_each_cpu_mask(cpu, rcu_cpu_online_map) 16 per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed; 17 RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); 18 return 1; 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16913}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int rcu_try_flip_waitmb(void) 2 { 3 int cpu; 4 5 RCU_TRACE_ME(rcupreempt_trace_try_flip_m1); 6 for_each_cpu_mask(cpu, rcu_cpu_online_map) 7 if (per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) { 8 RCU_TRACE_ME(rcupreempt_trace_try_flip_me1); 9 return 0; 10 } 11 smp_mb(); 12 RCU_TRACE_ME(rcupreempt_trace_try_flip_m2); 13 return 1; 14 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure16921}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static void __rcu_advance_callbacks(struct rcu_data *rdp) 2 { 3 int cpu; 4 int i; 5 int wlc = 0; 6 7 if (rdp->completed != rcu_ctrlblk.completed) { 8 if (rdp->waitlist[GP_STAGES - 1] != NULL) { 9 *rdp->donetail = rdp->waitlist[GP_STAGES - 1]; 10 rdp->donetail = rdp->waittail[GP_STAGES - 1]; 11 RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp); 12 } 13 for (i = GP_STAGES - 2; i >= 0; i--) { 14 if (rdp->waitlist[i] != NULL) { 15 rdp->waitlist[i + 1] = rdp->waitlist[i]; 16 rdp->waittail[i + 1] = rdp->waittail[i]; 17 wlc++; 18 } else { 19 rdp->waitlist[i + 1] = NULL; 20 rdp->waittail[i + 1] = 21 &rdp->waitlist[i + 1]; 22 } 23 } 24 if (rdp->nextlist != NULL) { 25 rdp->waitlist[0] = rdp->nextlist; 26 rdp->waittail[0] = rdp->nexttail; 27 wlc++; 28 rdp->nextlist = NULL; 29 rdp->nexttail = &rdp->nextlist; 30 RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp); 31 } else { 32 rdp->waitlist[0] = NULL; 33 rdp->waittail[0] = &rdp->waitlist[0]; 34 } 35 rdp->waitlistcount = wlc; 36 rdp->completed = rcu_ctrlblk.completed; 37 } 38 cpu = raw_smp_processor_id(); 39 if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { 40 smp_mb(); 41 per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; 42 smp_mb(); 43 } 44 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{paragraph} {\newpage\clearpage \lthtmlfigureA{figure16940}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void __rcu_read_lock(void) 2 { 3 int idx; 4 struct task_struct *t = current; 5 int nesting; 6 7 nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); 8 if (nesting != 0) { 9 t->rcu_read_lock_nesting = nesting + 1; 10 } else { 11 unsigned long flags; 12 13 local_irq_save(flags); 14 idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1; 15 ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])++; 16 ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting + 1; 17 ACCESS_ONCE(t->rcu_flipctr_idx) = idx; 18 local_irq_restore(flags); 19 } 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} {\newpage\clearpage \lthtmlfigureA{figure16989}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void __rcu_read_unlock(void) 2 { 3 int idx; 4 struct task_struct *t = current; 5 int nesting; 6 7 nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); 8 if (nesting > 1) { 9 t->rcu_read_lock_nesting = nesting - 1; 10 } else { 11 unsigned long flags; 12 13 local_irq_save(flags); 14 idx = ACCESS_ONCE(t->rcu_flipctr_idx); 15 ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1; 16 ACCESS_ONCE(__get_cpu_var(rcu_flipctr)[idx])--; 17 local_irq_restore(flags); 18 } 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{paragraph} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17433}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBwaste}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17441}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBnowaste}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap17463}% \resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptValidation}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsubsection} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure17517}% \begin{figure}{ \scriptsize \begin{verbatim} 1 #define NUMPROCS 2 2 3 byte counter = 0; 4 byte progress[NUMPROCS]; 5 6 proctype incrementer(byte me) 7 { 8 int temp; 9 10 temp = counter; 11 counter = temp + 1; 12 progress[me] = 1; 13 } 14 15 init { 16 int i = 0; 17 int sum = 0; 18 19 atomic { 20 i = 0; 21 do 22 :: i < NUMPROCS -> 23 progress[i] = 0; 24 run incrementer(i); 25 i++ 26 :: i >= NUMPROCS -> break 27 od; 28 } 29 atomic { 30 i = 0; 31 sum = 0; 32 do 33 :: i < NUMPROCS -> 34 sum = sum + progress[i]; 35 i++ 36 :: i >= NUMPROCS -> break 37 od; 38 assert(sum < NUMPROCS || counter == NUMPROCS) 39 } 40 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17537}% \begin{figure}{ \scriptsize \begin{verbatim} pan: assertion violated ((sum<2)||(counter==2)) (at depth 20) pan: wrote increment.spin.trail (Spin Version 4.2.5 -- 2 April 2005) Warning: Search not completed + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + cycle checks - (disabled by -DSAFETY) invalid end states + State-vector 40 byte, depth reached 22, errors: 1 45 states, stored 13 states, matched 58 transitions (= stored+matched) 51 atomic steps hash conflicts: 0 (resolved) 2.622 memory usage (Mbyte)\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figurestar17553}% \begin{figure*}{ \scriptsize \begin{verbatim} Starting :init: with pid 0 1: proc 0 (:init:) line 20 "increment.spin" (state 1) [i = 0] 2: proc 0 (:init:) line 22 "increment.spin" (state 2) [((i<2))] 2: proc 0 (:init:) line 23 "increment.spin" (state 3) [progress[i] = 0] Starting incrementer with pid 1 3: proc 0 (:init:) line 24 "increment.spin" (state 4) [(run incrementer(i))] 3: proc 0 (:init:) line 25 "increment.spin" (state 5) [i = (i+1)] 4: proc 0 (:init:) line 22 "increment.spin" (state 2) [((i<2))] 4: proc 0 (:init:) line 23 "increment.spin" (state 3) [progress[i] = 0] Starting incrementer with pid 2 5: proc 0 (:init:) line 24 "increment.spin" (state 4) [(run incrementer(i))] 5: proc 0 (:init:) line 25 "increment.spin" (state 5) [i = (i+1)] 6: proc 0 (:init:) line 26 "increment.spin" (state 6) [((i>=2))] 7: proc 0 (:init:) line 21 "increment.spin" (state 10) [break] 8: proc 2 (incrementer) line 10 "increment.spin" (state 1) [temp = counter] 9: proc 1 (incrementer) line 10 "increment.spin" (state 1) [temp = counter] 10: proc 2 (incrementer) line 11 "increment.spin" (state 2) [counter = (temp+1)] 11: proc 2 (incrementer) line 12 "increment.spin" (state 3) [progress[me] = 1] 12: proc 2 terminates 13: proc 1 (incrementer) line 11 "increment.spin" (state 2) [counter = (temp+1)] 14: proc 1 (incrementer) line 12 "increment.spin" (state 3) [progress[me] = 1] 15: proc 1 terminates 16: proc 0 (:init:) line 30 "increment.spin" (state 12) [i = 0] 16: proc 0 (:init:) line 31 "increment.spin" (state 13) [sum = 0] 17: proc 0 (:init:) line 33 "increment.spin" (state 14) [((i<2))] 17: proc 0 (:init:) line 34 "increment.spin" (state 15) [sum = (sum+progress[i])] 17: proc 0 (:init:) line 35 "increment.spin" (state 16) [i = (i+1)] 18: proc 0 (:init:) line 33 "increment.spin" (state 14) [((i<2))] 18: proc 0 (:init:) line 34 "increment.spin" (state 15) [sum = (sum+progress[i])] 18: proc 0 (:init:) line 35 "increment.spin" (state 16) [i = (i+1)] 19: proc 0 (:init:) line 36 "increment.spin" (state 17) [((i>=2))] 20: proc 0 (:init:) line 32 "increment.spin" (state 21) [break] spin: line 38 "increment.spin", Error: assertion violated spin: text of failed assertion: assert(((sum<2)||(counter==2))) 21: proc 0 (:init:) line 38 "increment.spin" (state 22) [assert(((sum<2)||(counter==2)))] spin: trail ends after 21 steps #processes: 1 counter = 1 progress[0] = 1 progress[1] = 1 21: proc 0 (:init:) line 40 "increment.spin" (state 24) 3 processes created\end{verbatim} } \end{figure*}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure17562}% \begin{figure}{ \scriptsize \begin{verbatim} 1 proctype incrementer(byte me) 2 { 3 int temp; 4 5 atomic { 6 temp = counter; 7 counter = temp + 1; 8 } 9 progress[me] = 1; 10 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17568}% \begin{figure}{ \scriptsize \begin{verbatim} (Spin Version 4.2.5 -- 2 April 2005) + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + cycle checks - (disabled by -DSAFETY) invalid end states + State-vector 40 byte, depth reached 20, errors: 0 52 states, stored 21 states, matched 73 transitions (= stored+matched) 66 atomic steps hash conflicts: 0 (resolved) 2.622 memory usage (Mbyte) unreached in proctype incrementer (0 of 5 states) unreached in proctype :init: (0 of 24 states)\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure17642}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 i = 0; 2 sum = 0; 3 do 4 :: i < N_QRCU_READERS -> 5 sum = sum + (readerstart[i] == 1 && 6 readerprogress[i] == 1); 7 i++ 8 :: i >= N_QRCU_READERS -> 9 assert(sum == 0); 10 break 11 od\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17648}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 atomic { 2 i = 0; 3 sum = 0; 4 do 5 :: i < N_QRCU_READERS -> 6 sum = sum + (readerstart[i] == 1 && 7 readerprogress[i] == 1); 8 i++ 9 :: i >= N_QRCU_READERS -> 10 assert(sum == 0); 11 break 12 od 13 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure17661}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 #define spin_lock(mutex) \ 2 do \ 3 :: 1 -> atomic { \ 4 if \ 5 :: mutex == 0 -> \ 6 mutex = 1; \ 7 break \ 8 :: else -> skip \ 9 fi \ 10 } \ 11 od 12 13 #define spin_unlock(mutex) \ 14 mutex = 0\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17674}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 #include "lock.h" 2 3 #define N_LOCKERS 3 4 5 bit mutex = 0; 6 bit havelock[N_LOCKERS]; 7 int sum; 8 9 proctype locker(byte me) 10 { 11 do 12 :: 1 -> 13 spin_lock(mutex); 14 havelock[me] = 1; 15 havelock[me] = 0; 16 spin_unlock(mutex) 17 od 18 } 19 20 init { 21 int i = 0; 22 int j; 23 24 end: do 25 :: i < N_LOCKERS -> 26 havelock[i] = 0; 27 run locker(i); 28 i++ 29 :: i >= N_LOCKERS -> 30 sum = 0; 31 j = 0; 32 atomic { 33 do 34 :: j < N_LOCKERS -> 35 sum = sum + havelock[j]; 36 j = j + 1 37 :: j >= N_LOCKERS -> 38 break 39 od 40 } 41 assert(sum <= 1); 42 break 43 od 44 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17691}% \begin{figure}{ \scriptsize \begin{verbatim} (Spin Version 4.2.5 -- 2 April 2005) + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + cycle checks - (disabled by -DSAFETY) invalid end states + State-vector 40 byte, depth reached 357, errors: 0 564 states, stored 929 states, matched 1493 transitions (= stored+matched) 368 atomic steps hash conflicts: 0 (resolved) 2.622 memory usage (Mbyte) unreached in proctype locker line 18, state 20, "-end-" (1 of 20 states) unreached in proctype :init: (0 of 22 states)\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure17734}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 #include "lock.h" 2 3 #define N_QRCU_READERS 2 4 #define N_QRCU_UPDATERS 2 5 6 bit idx = 0; 7 byte ctr[2]; 8 byte readerprogress[N_QRCU_READERS]; 9 bit mutex = 0;\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17749}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 proctype qrcu_reader(byte me) 2 { 3 int myidx; 4 5 do 6 :: 1 -> 7 myidx = idx; 8 atomic { 9 if 10 :: ctr[myidx] > 0 -> 11 ctr[myidx]++; 12 break 13 :: else -> skip 14 fi 15 } 16 od; 17 readerprogress[me] = 1; 18 readerprogress[me] = 2; 19 atomic { ctr[myidx]-- } 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17759}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 #define sum_unordered \ 2 atomic { \ 3 do \ 4 :: 1 -> \ 5 sum = ctr[0]; \ 6 i = 1; \ 7 break \ 8 :: 1 -> \ 9 sum = ctr[1]; \ 10 i = 0; \ 11 break \ 12 od; \ 13 } \ 14 sum = sum + ctr[i]\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17770}% \begin{figure}{ \scriptsize \begin{verbatim} 1 proctype qrcu_updater(byte me) 2 { 3 int i; 4 byte readerstart[N_QRCU_READERS]; 5 int sum; 6 7 do 8 :: 1 -> 9 10 /* Snapshot reader state. */ 11 12 atomic { 13 i = 0; 14 do 15 :: i < N_QRCU_READERS -> 16 readerstart[i] = readerprogress[i]; 17 i++ 18 :: i >= N_QRCU_READERS -> 19 break 20 od 21 } 22 23 sum_unordered; 24 if 25 :: sum <= 1 -> sum_unordered 26 :: else -> skip 27 fi; 28 if 29 :: sum > 1 -> 30 spin_lock(mutex); 31 atomic { ctr[!idx]++ } 32 idx = !idx; 33 atomic { ctr[!idx]-- } 34 do 35 :: ctr[!idx] > 0 -> skip 36 :: ctr[!idx] == 0 -> break 37 od; 38 spin_unlock(mutex); 39 :: else -> skip 40 fi; 41 42 /* Verify reader progress. */ 43 44 atomic { 45 i = 0; 46 sum = 0; 47 do 48 :: i < N_QRCU_READERS -> 49 sum = sum + (readerstart[i] == 1 && 50 readerprogress[i] == 1); 51 i++ 52 :: i >= N_QRCU_READERS -> 53 assert(sum == 0); 54 break 55 od 56 } 57 od 58 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure17788}% \begin{figure}{ % \scriptsize \begin{verbatim} 1 init { 2 int i; 3 4 atomic { 5 ctr[idx] = 1; 6 ctr[!idx] = 0; 7 i = 0; 8 do 9 :: i < N_QRCU_READERS -> 10 readerprogress[i] = 0; 11 run qrcu_reader(i); 12 i++ 13 :: i >= N_QRCU_READERS -> break 14 od; 15 i = 0; 16 do 17 :: i < N_QRCU_UPDATERS -> 18 run qrcu_updater(i); 19 i++ 20 :: i >= N_QRCU_UPDATERS -> break 21 od 22 } 23 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{subsection} \stepcounter{section} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsubsection} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18533}% \begin{figure}{ \scriptsize \begin{verbatim} static inline void rcu_enter_nohz(void) { + mb(); __get_cpu_var(dynticks_progress_counter)++; - mb(); } static inline void rcu_exit_nohz(void) { - mb(); __get_cpu_var(dynticks_progress_counter)++; + mb(); }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure18539}% \begin{figure}{ \scriptsize \begin{verbatim} - if ((curr - snap) > 2 || (snap & 0x1) == 0) + if ((curr - snap) > 2 || (curr & 0x1) == 0)\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18565}% \begin{figure}{ \scriptsize \begin{verbatim} 1 struct rcu_dynticks { 2 int dynticks_nesting; 3 int dynticks; 4 int dynticks_nmi; 5 }; 6 7 struct rcu_data { 8 ... 9 int dynticks_snap; 10 int dynticks_nmi_snap; 11 ... 12 };\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18595}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_enter_nohz(void) 2 { 3 unsigned long flags; 4 struct rcu_dynticks *rdtp; 5 6 smp_mb(); 7 local_irq_save(flags); 8 rdtp = &__get_cpu_var(rcu_dynticks); 9 rdtp->dynticks++; 10 rdtp->dynticks_nesting--; 11 WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs); 12 local_irq_restore(flags); 13 } 14 15 void rcu_exit_nohz(void) 16 { 17 unsigned long flags; 18 struct rcu_dynticks *rdtp; 19 20 local_irq_save(flags); 21 rdtp = &__get_cpu_var(rcu_dynticks); 22 rdtp->dynticks++; 23 rdtp->dynticks_nesting++; 24 WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs); 25 local_irq_restore(flags); 26 smp_mb(); 27 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18612}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_nmi_enter(void) 2 { 3 struct rcu_dynticks *rdtp; 4 5 rdtp = &__get_cpu_var(rcu_dynticks); 6 if (rdtp->dynticks & 0x1) 7 return; 8 rdtp->dynticks_nmi++; 9 WARN_ON_RATELIMIT(!(rdtp->dynticks_nmi & 0x1), 10 &rcu_rs); 11 smp_mb(); 12 } 13 14 void rcu_nmi_exit(void) 15 { 16 struct rcu_dynticks *rdtp; 17 18 rdtp = &__get_cpu_var(rcu_dynticks); 19 if (rdtp->dynticks & 0x1) 20 return; 21 smp_mb(); 22 rdtp->dynticks_nmi++; 23 WARN_ON_RATELIMIT(rdtp->dynticks_nmi & 0x1, &rcu_rs); 24 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18629}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void rcu_irq_enter(void) 2 { 3 struct rcu_dynticks *rdtp; 4 5 rdtp = &__get_cpu_var(rcu_dynticks); 6 if (rdtp->dynticks_nesting++) 7 return; 8 rdtp->dynticks++; 9 WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs); 10 smp_mb(); 11 } 12 13 void rcu_irq_exit(void) 14 { 15 struct rcu_dynticks *rdtp; 16 17 rdtp = &__get_cpu_var(rcu_dynticks); 18 if (--rdtp->dynticks_nesting) 19 return; 20 smp_mb(); 21 rdtp->dynticks++; 22 WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs); 23 if (__get_cpu_var(rcu_data).nxtlist || 24 __get_cpu_var(rcu_bh_data).nxtlist) 25 set_need_resched(); 26 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} {\newpage\clearpage \lthtmlfigureA{figure18648}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int 2 dyntick_save_progress_counter(struct rcu_data *rdp) 3 { 4 int ret; 5 int snap; 6 int snap_nmi; 7 8 snap = rdp->dynticks->dynticks; 9 snap_nmi = rdp->dynticks->dynticks_nmi; 10 smp_mb(); 11 rdp->dynticks_snap = snap; 12 rdp->dynticks_nmi_snap = snap_nmi; 13 ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); 14 if (ret) 15 rdp->dynticks_fqs++; 16 return ret; 17 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure18662}% \begin{figure}{ \scriptsize \begin{verbatim} 1 static int 2 rcu_implicit_dynticks_qs(struct rcu_data *rdp) 3 { 4 long curr; 5 long curr_nmi; 6 long snap; 7 long snap_nmi; 8 9 curr = rdp->dynticks->dynticks; 10 snap = rdp->dynticks_snap; 11 curr_nmi = rdp->dynticks->dynticks_nmi; 12 snap_nmi = rdp->dynticks_nmi_snap; 13 smp_mb(); 14 if ((curr != snap || (curr & 0x1) == 0) && 15 (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { 16 rdp->dynticks_fqs++; 17 return 1; 18 } 19 return rcu_implicit_offline_qs(rdp); 20 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{subsection} \stepcounter{section} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap21734}% \resizebox{3in}{!}{\includegraphics{count/GlobalTreeInc}}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21484}% $O(log N)$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21488}% $O(N)$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure19582}% \begin{figure}{ \scriptsize \begin{verbatim} 1 long __thread counter = 0; 2 long *counterp[NR_THREADS] = { NULL }; 3 int finalthreadcount = 0; 4 DEFINE_SPINLOCK(final_mutex); 5 6 void inc_count(void) 7 { 8 counter++; 9 } 10 11 long read_count(void) 12 { 13 int t; 14 long sum = 0; 15 16 for_each_thread(t) 17 if (counterp[t] != NULL) 18 sum += *counterp[t]; 19 return sum; 20 } 21 22 void count_init(void) 23 { 24 } 25 26 void count_register_thread(void) 27 { 28 counterp[smp_thread_id()] = 29 } 30 31 void count_unregister_thread(int nthreadsexpected) 32 { 33 spin_lock(&final_mutex); 34 finalthreadcount++; 35 spin_unlock(&final_mutex); 36 while (finalthreadcount < nthreadsexpected) 37 poll(NULL, 0, 1); 38 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmlpictureA{tex2html_wrap26086}% \includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5PEM}% \lthtmlpictureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21490}% $m+2sn$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlfigureA{figure19943}% \begin{figure}{ \centering \begin{verbatim} 1 spin_lock(&mylock); 2 p = search(head, key); 3 if (p == NULL) 4 spin_unlock(&mylock); 5 else { 6 list_del_rcu(&p->list); 7 spin_unlock(&mylock); 8 synchronize_rcu(); 9 kfree(p); 10 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure20035}% \begin{figure}{ \tt\scriptsize \begin{verbatim} 1 struct profile_buffer { 2 long size; 3 atomic_t entry[0]; 4 }; 5 static struct profile_buffer *buf = NULL; 6 7 void nmi_profile(unsigned long pcvalue) 8 { 9 struct profile_buffer *p; 10 11 rcu_read_lock(); 12 p = rcu_dereference(buf); 13 if (p == NULL) { 14 rcu_read_unlock(); 15 return; 16 } 17 if (pcvalue >= p->size) { 18 rcu_read_unlock(); 19 return; 20 } 21 atomic_inc(&p->entry[pcvalue]); 22 rcu_read_unlock(); 23 } 24 25 void nmi_stop(void) 26 { 27 struct profile_buffer *p = buf; 28 29 if (p == NULL) 30 return; 31 rcu_assign_pointer(buf, NULL); 32 synchronize_rcu(); 33 kfree(p); 34 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure20100}% \begin{figure}{ \centering \begin{verbatim} 1 idx = srcu_read_lock(&ssa); 2 synchronize_srcu(&ssb); 3 srcu_read_unlock(&ssa, idx); 4 5 /* . . . */ 6 7 idx = srcu_read_lock(&ssb); 8 synchronize_srcu(&ssa); 9 srcu_read_unlock(&ssb, idx);\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure20126}% \begin{figure}{ \centering \begin{verbatim} 1 rcu_read_lock(); 2 preempt_disable(); 3 p = rcu_dereference(global_pointer); 4 5 /* . . . */ 6 7 preempt_enable(); 8 rcu_read_unlock();\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlfigureA{figure20136}% \begin{figure}{ \scriptsize \begin{verbatim} 1 void foo(void) 2 { 3 spin_lock(&my_lock); 4 rcu_read_lock(); 5 do_something(); 6 rcu_read_unlock(); 7 do_something_else(); 8 spin_unlock(&my_lock); 9 } 10 11 void bar(void) 12 { 13 rcu_read_lock(); 14 spin_lock(&my_lock); 15 do_some_other_thing(); 16 spin_unlock(&my_lock); 17 do_whatever(); 18 rcu_read_unlock(); 19 }\end{verbatim} } \end{figure}% \lthtmlfigureZ \lthtmlcheckvsize\clearpage} \stepcounter{section} {\newpage\clearpage \lthtmldisplayA{displaymath20404}% \begin{displaymath} \epsilon = \frac{T_r R_i}{2} \end{displaymath}% \lthtmldisplayZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21500}% $\epsilon$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21502}% $T_r$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21504}% $R_i$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{section} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21512}% $2N+1$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} {\newpage\clearpage \lthtmlinlinemathA{tex2html_wrap_inline21514}% $N+1$% \lthtmlinlinemathZ \lthtmlcheckvsize\clearpage} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{chapter} \stepcounter{chapter} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \stepcounter{section} \end{document} perfbook_html/img169.png0000644000175000017500000000033011672746042015312 0ustar paulmckpaulmckPNG  IHDR\q&*PLTEMJK# b``mkkXUVC@@wuvtRNS@f\IDATcp``p6`pR `*f`Pi ȂX @>p`pa@l$vbm V{EHj&$+[#IENDB`perfbook_html/node147.html0000644000175000017500000002062211672746162015650 0ustar paulmckpaulmck 10.3.2.7 RCU is a Way of Waiting for Things to Finish


10.3.2.7 RCU is a Way of Waiting for Things to Finish

As noted in Section [*] an important component of RCU is a way of waiting for RCU readers to finish. One of RCU's great strengths is that it allows you to wait for each of thousands of different things to finish without having to explicitly track each and every one of them, and without having to worry about the performance degradation, scalability limitations, complex deadlock scenarios, and memory-leak hazards that are inherent in schemes that use explicit tracking.

In this section, we will show how synchronize_sched()'s read-side counterparts (which include anything that disables preemption, along with hardware operations and primitives that disable irq) permit you to implement interactions with non-maskable interrupt (NMI) handlers that would be quite difficult if using locking. This approach has been called "Pure RCU" [McK04], and it is used in a number of places in the Linux kernel.

The basic form of such "Pure RCU" designs is as follows:

  1. Make a change, for example, to the way that the OS reacts to an NMI.
  2. Wait for all pre-existing read-side critical sections to completely finish (for example, by using the synchronize_sched() primitive). The key observation here is that subsequent RCU read-side critical sections are guaranteed to see whatever change was made.
  3. Clean up, for example, return status indicating that the change was successfully made.

The remainder of this section presents example code adapted from the Linux kernel. In this example, the timer_stop function uses synchronize_sched() to ensure that all in-flight NMI notifications have completed before freeing the associated resources. A simplified version of this code is shown Figure [*].

Figure: Using RCU to Wait for NMIs to Finish
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct profile_buffer {
2 long...
...ULL);
25 synchronize_sched();
26 kfree(p);
27 }\end{verbatim}
}\end{figure}

Lines 1-4 define a profile_buffer structure, containing a size and an indefinite array of entries. Line 5 defines a pointer to a profile buffer, which is presumably initialized elsewhere to point to a dynamically allocated region of memory.

Lines 7-16 define the nmi_profile() function, which is called from within an NMI handler. As such, it cannot be preempted, nor can it be interrupted by a normal irq handler, however, it is still subject to delays due to cache misses, ECC errors, and cycle stealing by other hardware threads within the same core. Line 9 gets a local pointer to the profile buffer using the rcu_dereference() primitive to ensure memory ordering on DEC Alpha, and lines 11 and 12 exit from this function if there is no profile buffer currently allocated, while lines 13 and 14 exit from this function if the pcvalue argument is out of range. Otherwise, line 15 increments the profile-buffer entry indexed by the pcvalue argument. Note that storing the size with the buffer guarantees that the range check matches the buffer, even if a large buffer is suddenly replaced by a smaller one.

Lines 18-27 define the nmi_stop() function, where the caller is responsible for mutual exclusion (for example, holding the correct lock). Line 20 fetches a pointer to the profile buffer, and lines 22 and 23 exit the function if there is no buffer. Otherwise, line 24 NULLs out the profile-buffer pointer (using the rcu_assign_pointer() primitive to maintain memory ordering on weakly ordered machines), and line 25 waits for an RCU Sched grace period to elapse, in particular, waiting for all non-preemptible regions of code, including NMI handlers, to complete. Once execution continues at line 26, we are guaranteed that any instance of nmi_profile() that obtained a pointer to the old buffer has returned. It is therefore safe to free the buffer, in this case using the kfree() primitive.

Quick Quiz 10.21: Suppose that the nmi_profile() function was preemptible. What would need to change to make this example work correctly? End Quick Quiz

In short, RCU makes it easy to dynamically switch among profile buffers (you just try doing this efficiently with atomic operations, or at all with locking!). However, RCU is normally used at a higher level of abstraction, as was shown in the previous sections.

Paul E. McKenney 2011-12-16
perfbook_html/img93.png0000644000175000017500000002320311672746076015241 0ustar paulmckpaulmckPNG  IHDR0'|DptRNSىH IDATx흻@Y'''DH z9BZ(:<D*s`9B#$s߷k=Rwׅԗ7 FJ1/KDԷNBe )E7)&KO(L(I[|lJLPѹ͈/ZKc"DڋZ=vИݙ6ߏ BM3`>s,&kơB'Ĉ8QmzWℕe+1B<}Q_ײ/-!gʆ JaBHĽ (@6ݚF2h*5RCrFf|WTc]M"c~5J=j'R7fli m[ϡO}NB;Wo SoZSZ,L eB F`}Ob][cZY(^u~X67Z $Rp=\LOBqJ}]1Or׈x7Z*?p/&3+zշUҏC*w7;\k(-ܯy9iW ۄidh®#Q@먶% `l]s_phM.=_d5#%kl ՜Fd*6A)3$ff>f]e2 /TJ$_~} /? (I5)+?rާd/lbv>㝙gY3> 0ȱSVVV h(3Bɩ&<~1=j8]8J#Lz:9Ki&/ IAN %}lZ76ofieISAv`H`("xgxB'z42p3`s&g.pxK+GqDpL/9BD GYISo(;=jZ!@ǵ/Po,^3L6A;36yGJ#m5e5GR$1MF廖適'GyD41ʍ0р\<@jUZI)xhr [U+og\$e:%@伩u|t!J72s**u:#4vO1/e}P;)Fͬ5n/eP`َVйXb6#r0tTNnԖE &.:&{ ~,uc,QmhiD54$=W,5Stm%]g4{hfˏ:IE60OD])kҦfѝ!ʨi=űƑǯׯS#.48]kifB賝W<]i(x\s\פaFX~Ծ^ i j^;QR#Y5UT Xیɻͼ'&,,,evf_YX4ZLh~Yΐ.p({/ oSOynk"#tIqʑqZuMK djnm/ga]ݓf6%# }f +:(b #g&-mM4qv ߖ3pVvϴDwq<2vrFl+u췢'%ZMOfͰ [ڿe3ď|`#h5sd$;dj8Iٳ#& *w*{x7 Z6]ܦ:s9&SuH~1ϖh1xS E;¼cϜ՗gxFn '*—Q֣|?LooԶ:+<{袽E-Y m-؃EƆ I Ǚቜ"՟jEv-ef-l{jVs+^q]m-~Sw1⃺ؚj! L9gKk$Usz[`sV)C;(=P, k@1/t-m5xư9wKܞp&Y Ś*&jP.Ep(0X/]8#:yt܈G?@ m#οVg1P0:䣒D͓3VWi LoCX7[+#JxX6Kvi+E lE(zMxP$h#b̓}]1jOPJH^jɭK#qB s7X7x Vh\(-@\%Ulvl|$4cjoֲ;NA`x۱P˛%j*]+hꇩ) oC<5; (-D^L]Ǔj{(ҸŁJVF"I6!pJ:_U-.pe9 C*Mq._mT1|z"O"I1 4qoqq>2=a߿ƾ7˷ZIY` P18 `dMD;U-[pi>3U~5XP RWb}W讘gFALrn`FɼS/c xW1Nc9zL N- `[MhƆ| ]Xq ڶb6 ;WA\YBRޭ%o&ɜ!Y&AKlU$L}X{LʯB(7sɻ"<cKDyhHbiuEq)c'VRsU>?&:Պ**+,c>;UbLwmTOMIC6crDHƩZ!T%e9'%T.o~oJx7Tnߘ7YQ}WN30A5~Ufƾ-^dS>ljBT5K8sUw6/#kD3i:ـeHE{]Ԯ`6YZԗ*3Т1k]Qࠅx #z:3D-^%"CjeP7-w8NIGD=&#R_0s Ɯ~5-3b@ls爒旧_&Sw?o!pm8{Bh&V28g@-S.2*Jk ~|NKs16bZC854as8ρ|P覆?e/w0=6<"UoG0؆!ԆͲ~OCl 4fi1,5m'xW%'61vIa+d B9}{9hshNԸqUk&4zqmhݵeo3]~OoȈQH$v2v*el;14ShdV5MWoKlQ|)pkQK~Jـ27%c ~}+k]b,8*j=P `@-,_6gIk E-d<^0ϰkC )q/?ц:F8Eь;00JּOnk懡2}b9&D%x-Xv8CdL$ybN(@rNI_mȝ18<$qvM#؈Hu\vI~sTg@h?&0>ΫZ'3d&oO4Ͽ dಪ Z/-IBd0hͻvIBAݶ}w* ږ?]gW[ibUhXF`Icnx bs |vkG`]S,;wX/E.i\ 6ݪV Cưti񻀝ۥ>/ 4n2](cD`0D1.hD|W5xS&9i} q4.]UrZD/K+8 q<ؗ0!zc_Q#+sZJ^>x74(: %Y[kQL-I9Zظq #-F{Z.)&ME.٧ YsBaO gj+e1PhiS4+|EkxS+^osl%~A=m"t\\tND٥`vГXOnQ]#d-3xL9ӆgy(~тYfXž>I`ʷn_O*`$PzQ! wꔶbQ^ (V{Gйފ\c(\11D{g5e(r-^o? y':^j9b^0}Wl)_8^s/4/ip^77 ppTsz;72OK\+^U4]{~wA7}[ب\W̗郏;m?7ʞq<>OOv[1lޝBfHM=* `D>G(sǧx`n6fG9` gH)6NK`|#nԹ%&RR`5E,w_1Qٿj:7>d_b}WX_tWLȅtMPoL|cX]X)y²q+t 4=<p@pLD,q1LqS#$ӒMZρ9bLE,JKPlY/']qPq<5\NuԹC6N t;T-N.Y(\\ >^'N8݈rv^p{^iגsPxjYUfNMkDS;@^_sq8=swIA}khW/ hqC7r7!:_ElրFuɆ8 4Z%m>['^"6XN6<>ͼKRY{U?c(گ<~43sk}Zy.^?Lc? V/XMZ_&" }NL51~({Ύr (gTT[ND}swI kٟV|_ ڈ]3V$iӌO(ҽh Omx%F@2TAvL_&sAa.:w !!Dwف1Ι{(QhI!p]ӻenB;k/> MYd^xG̻ڨKX8;йQq DGr>^.%5S(L/߱°ogz[״cUD# gCU$sDhBI#3=,"ɦ{4YwP/$؟3p.Ǥct. xfƻB\a$3`MPNG>%h7v . ?\NHAoa<~/+N`G $92InGgS!4~>뷮v({~2HKoErv7xw'D; ]݈ ht[ M^4~NH̓_gEkjs1[?p@ưfEԆChJŏ*"; ^GRjy,ɸ˿9zSR~|Bn?$SU252bF;/x(O"sD}?JT~*S# \% 2B] b_ZfhDP$S8M'&B*Hف$E6l"'2Vvw>IRd:WP+J#a2~venLk&>jzgn#%<aaZ\ޗ{ vz;s)9%xr1š ye2쪌=5ʷ9~AV눒ԙF5pUzzT;N4Ŕ}xOzU rXPckځ> >'L :A} 1O4cg&d8)/_k $/㶻hLJ B0Y^ Ps)"}RR^>nb=#ɩ|bb(Q:S܁L?7br HnÏL;t!τ1!9; J5i@NҘ]OW?Xϯ4V9Y+L&ȧǑm/=8~g$"tԈۘ.ޞY5{7̿ lµLlyaWeqBoG .ǕFx{_ MO ެdtQMk/(Rݻ@QY; \+|Jrяנ05:wwGk(OߝUM:{{mqK@MޯuvfBաrM[C? McyڲHƣFWH{'H;Mrs_Q'; (*u==}P !OlsrDCM7fI }Jn9:2zaRW'nwM;|)5o'=Yh"I1`x%KsyҸɵ= 9$.YM y^+)#0 )_G4r1N+pߊB7Q޾_6ab ;$kߊ#~ʱ ð?OT}5|^V++cg{{EY6?i18,Z˶oE2G+KB4~q66Jx6Ycfu/7j N7g<"ꇞ4RZ7!/V2gMx ү’N50(>An7 oBokEyj8o?+5y ÚADw)Ԟ-~9`?>*I/@k&6T00IDATީuo4Wq/m{ҩ鮄o@m/ ;@,<9=sԪ/͐6{xxwcn0A!z@,Gw@V_8a]'!C4S>{F>Veq[^E]_0BEuI;;~XxjXd|o }%5Kc>c%wEw.=Co +vsoC`,1_*ڹdLM"qMCwrxxz6"}JRC+N~)Ow fpOqs7Zl[wab5 ޔ'wxuD|?0DпI6{~|~yfV9/i܂gq\M6K?^'CYWn-+>'k˜_w-2^ |^@-Ed6ҩ؀w~hwu&Y6h\[h'T<}grR `}PL=Fa8ܲwwvx_\do]Fh^XRsIENDB`perfbook_html/node121.html0000644000175000017500000001733211672746162015644 0ustar paulmckpaulmck 10.2.1.4 Atomic Counting With Check and Release Memory Barrier


10.2.1.4 Atomic Counting With Check and Release Memory Barrier

The fact that reference-count acquisition can run concurrently with reference-count release adds further complications. Suppose that a reference-count release finds that the new value of the reference count is zero, signalling that it is now safe to clean up the reference-counted object. We clearly cannot allow a reference-count acquisition to start after such clean-up has commenced, so the acquisition must include a check for a zero reference count. This check must be part of the atomic increment operation, as shown below.

Quick Quiz 10.5: Why can't the check for a zero reference count be made in a simple ``if'' statement with an atomic increment in its ``then'' clause? End Quick Quiz

The Linux kernel's fget() and fput() primitives use this style of reference counting. Simplified versions of these functions are shown in Figure [*].

Figure: Linux Kernel fget/fput API
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct file *fget(unsigned int ...
...uhead);
40 kmem_cache_free(filp_cachep, f);
41 }\end{verbatim}
}\end{figure}

Line 4 of fget() fetches the pointer to the current process's file-descriptor table, which might well be shared with other processes. Line 6 invokes rcu_read_lock(), which enters an RCU read-side critical section. The callback function from any subsequent call_rcu() primitive will be deferred until a matching rcu_read_unlock() is reached (line 10 or 14 in this example). Line 7 looks up the file structure corresponding to the file descriptor specified by the fd argument, as will be described later. If there is an open file corresponding to the specified file descriptor, then line 9 attempts to atomically acquire a reference count. If it fails to do so, lines 10-11 exit the RCU read-side critical section and report failure. Otherwise, if the attempt is successful, lines 14-15 exit the read-side critical section and return a pointer to the file structure.

The fcheck_files() primitive is a helper function for fget(). It uses the rcu_dereference() primitive to safely fetch an RCU-protected pointer for later dereferencing (this emits a memory barrier on CPUs such as DEC Alpha in which data dependencies do not enforce memory ordering). Line 22 uses rcu_dereference() to fetch a pointer to this task's current file-descriptor table, and line 24 checks to see if the specified file descriptor is in range. If so, line 25 fetches the pointer to the file structure, again using the rcu_dereference() primitive. Line 26 then returns a pointer to the file structure or NULL in case of failure.

The fput() primitive releases a reference to a file structure. Line 31 atomically decrements the reference count, and, if the result was zero, line 32 invokes the call_rcu() primitives in order to free up the file structure (via the file_free_rcu() function specified in call_rcu()'s second argument), but only after all currently-executing RCU read-side critical sections complete. The time period required for all currently-executing RCU read-side critical sections to complete is termed a ``grace period''. Note that the atomic_dec_and_test() primitive contains a memory barrier. This memory barrier is not necessary in this example, since the structure cannot be destroyed until the RCU read-side critical section completes, but in Linux, all atomic operations that return a result must by definition contain memory barriers.

Once the grace period completes, the file_free_rcu() function obtains a pointer to the file structure on line 39, and frees it on line 40.

This approach is also used by Linux's virtual-memory system, see get_page_unless_zero() and put_page_testzero() for page structures as well as try_to_unuse() and mmput() for memory-map structures.

Paul E. McKenney 2011-12-16
perfbook_html/node75.html0000644000175000017500000002065311672746162015574 0ustar paulmckpaulmck 7.1.1 Dining Philosophers Problem


7.1.1 Dining Philosophers Problem

Figure: Dining Philosophers Problem
\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5}

Figure [*] shows a diagram of the classic Dining Philosophers problem [Dij71]. This problem features five philosophers who do nothing but think and eat a ``very difficult kind of spaghetti'' which requires two forks to eat. A given philosopher is permitted to use only the forks to his or her immediate right and left, and once a philosopher picks up a fork, he or she will not put it down until sated.

The object is to construct an algorithm that, quite literally, prevents starvation. One starvation scenario would be if all of the philosophers picked up their leftmost forks simultaneously. Because none of them would put down their fork until after they ate, and because none of them may pick up their second fork until at least one has finished eating, they all starve.

Figure: Dining Philosophers Problem, Textbook Solution
\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5TB}

Dijkstra's solution used a global semaphore, which works fine assuming negligible communications delays, an assumption that has become invalid in the ensuing decades. Therefore, recent solutions number the forks as shown in Figure [*]. Each philosopher picks up the lowest-numbered fork next to his or her plate, then picks up the highest-numbered fork. The philosopher sitting in the uppermost position in the diagram thus picks up the leftmost fork first, then the rightmost fork, while the rest of the philosophers instead pick up their rightmost fork first. Because two of the philosophers will attempt to pick up fork 1 first, and because only one of those two philosophers will succeed, there will be five forks available to four philosophers. At least one of these four will be guaranteed to have two forks, and thus be able to proceed eating.

This general technique of numbering resources and acquiring them in numerical order is heavily used as a deadlock-prevention technique. However, it is easy to imagine a sequence of events that will result in only one philosopher eating at a time even though all are hungry:

  1. P2 picks up fork 1, preventing P1 from taking a fork.
  2. P3 picks up fork 2.
  3. P4 picks up fork 3.
  4. P5 picks up fork 4.
  5. P5 picks up fork 5 and eats.
  6. P5 puts down forks 4 and 5.
  7. P4 picks up fork 4 and eats.

Please think about ways of partitioning the Dining Philosophers Problem before reading further.

Figure: Dining Philosophers Problem, Partitioned
\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher4part-b}

One approach is shown in Figure [*], which includes four philosophers rather than five to better illustrate the partition technique. Here the upper and rightmost philosophers share a pair of forks, while the lower and leftmost philosophers share another pair of forks. If all philosophers are simultaneously hungry, at least two will be able to eat concurrently. In addition, as shown in the figure, the forks can now be bundled so that the pair are picked up and put down simultaneously, simplifying the acquisition and release algorithms.

Quick Quiz 7.1: Is there a better solution to the Dining Philosophers Problem? End Quick Quiz

This is an example of ``horizontal parallelism'' [Inm85] or ``data parallelism'', so named because there is no dependency among the philosophers. In a data-processing system, a given item of data would pass through only one of a replicated set of software components.

Quick Quiz 7.2: And in just what sense can this ``horizontal parallelism'' be said to be ``horizontal''? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node276.html0000644000175000017500000000474111672746162015657 0ustar paulmckpaulmck B.2.5 wait_thread()

B.2.5 wait_thread()

The wait_thread() primitive waits for completion of the thread specified by the thread_id_t passed to it. This in no way interferes with the execution of the specified thread; instead, it merely waits for it. Note that wait_thread() returns the value that was returned by the corresponding thread.



Paul E. McKenney 2011-12-16
perfbook_html/img47.png0000644000175000017500000002413411672746077015245 0ustar paulmckpaulmckPNG  IHDR8q˱TPLTEb``^\\\ZZTRRMJK# hffvstmkkXUV856iffKHHC@@wuv.*+-**rppKetRNS@f IDATx]nR-VϒvgwQD|$CT_!&m8g4 Sy!d֎ROJc^iϺ@ 4{){Xyځiֿ󺖷hg1 (Wߥ\˷_tXZM1 z?ym]NSƒ#Z$7s-+V{y9)"ĩ!mqfa5M(\t|dը5LsI4wi iM30U)A/@qڨpg Eyoz03y# սm$}#%Znoٳ)o7V|ҨsY*!_`S[=m V mq ,)$$X-&=;.B nִ=;\mg! լOF䫦db- 1C[2xG0iGuF~NہL ކ9Q/5)p#zl`>!CaQ^8>D^sepkoyed+:慒>p7=Npo%@$Np;GN;`:7 7ue31q65NZ 7c xo!&b1GJx8 a&4JQZ Z x tIo)$(n䔄u s$+E/R;Ri2NV?Lerl7/{[F򒠘|GEb>0ӭE yM\K#ΥZ3xl*8 0x7&e:Zz+z,tϲO-5dyճ&;+N|7}UXu k|Q_@m:])/XI*֞UK]8+˙=,6^!4{3MuYc|yr뒻Lܰ T5-M-nnR)H;ؙAU7]IySn+Y[g_76 rW/` e,7,yMhqs m0A?qE<&筂o{:9O& #0`Ƙ2Z-uTqae\ ,ɎƖ3aԺ)E\6J#'5tδ,sV+@ej- T2U1N `|'ۇz0*m7h 9Խ=Wʬ`O;s!=y8KV>v?iuӧo?70HpY$;ݭ@L|iNJ>.AΐpW6=X940na}~NsBQ̟m%Tfp{Θ͇8a ܔbu8Epa.i2<ƮK M4{^`uPj|k AYc;3 7wʯVdBmo8w3Ywm>,跦pV|[|OwJ~ wp&sǴ'6늦=chF{Ր%MQzKDGӆyղ \.%RWpS#bERڑ5M% xaݒQe΁o7{ ,L#W^G#;f‰D/4p,"e&h=cDixXvyw{ų촬n} *0u<LxSB=TMIj\ Or0SRiTJ4gf\w n*xW` ]S#75x{z[ɖʨcg0:+: ^Kx/ ^$ӟ/$ܫT2ɲIW54we2i .gh3 r?I-*˻H{PiPa`T⺱qܝq{Ju 4|5lH/)E꬗= C^8 m8A3EM ~i>0ZxWBҨدEM?w2634l퉨q=SXb7+S<*ߺm7g |zh@W pj i+=RۙBP"A'Άj[ Yv}kÔ]acCip%_ _.{v:js:hk}jнzIjc}+V]򌹎hЃIX>rS6No#ٹuC4AWcO0/qKG:(s:_\74Ħ; )!计G2\֘ZsDHMV]ѲW|཯d3B^ӜMVqrH }ʁrZ (G;3Lu^W(9viW8~w7nQ ª)TK9RȻCUţ| #΁s3>Ҳ>ked;9=]aPM D}kbDG.s-G56z+?sj$Z|5/G*Më]@WЁ2?1ˀ@1˹7pɝ9jxp qra/9ʎb1k$kՆl'5sh9Gp:ݜ~cs)HKk<4{w5zNScW󛠥skrz |i ZlplW%zZe{s]Ř 'Rs-2KHliqU*мVߖMzSaqŕT+]Ah=փǿ*h UVj? З[%`UqY' f$@U/}"swt}-C+x3冟ۺEԕ\ yN9*2I"ukUaMno祡'6j7)!H?(]%m!5s/<7_ET35*GдZYY\0T1_{E9uF)YL*Ηes_\/l|&Va=ƞX9;cq` WM+rpV6VՎOH*)l.%-\AR;9H)}Eu4}.6IaX%y}9УΛii.TkL͙}xg[{F#XwMբ2 䜬A?ѯfwx+5>:ъ}(WC;,ۏSy6DC q=GK9wl#_'nFBҔR1+aK⚷EzN[[%4r<$- {'Ǯ6 `&*c%NJ= ȯ]N [| *Mzc/ },>Qz{#T&"ꏽ}\NBI|!h=_FWVn-fKc<]@H GӽDZY.gr32o1u{:Bh'EɄW8~nޡuNO--c>GA3ZՁ?q֮pWUxke`0 GLWPoo5ym>L1aAs5yfrzv71F_aEqWrܯߘb,L1Hp3߇Fe"N/N/F.v2zӋ (]`ǧR -2nqޝdJGfsEFM?Qϕ$,ν]כzoFڟaBAeȵHuOs.EV #}95-Mϱ"8~Bc)PɕקyƷ0E"&@Oٙ{Dѡ5 E r쑗TE23 ~nt}xGdiiJ3$[hۍSL#8N]8-1MǓo0I[Y,3hTo=Ǥ.־قvIKyݖt]ZϠ^w* nf4v0@: r|rs:Z+QZ_^ww\A^HnF菇/vŜ%sOvs;9Xz+- {:Px;v]8*=Êǵ{+=lDX=}Tww9Ix9Sy)MHΤ%Ŀ\hY*s +9N%0lnyO]|L^ 2Ƣ'B{%s .ta? uF[WX4IrMYMaWԷr_ApE@ﬤw ytFH@Ht3Z~@<{>5ɹ 9äDŌU7\]_h\oXsWmUUhЫoxL٭6d 2?YVlW/ݺ‘d;xL`cVJT;pz^ \ .-w|TUiܵ~*/b}] =}Hn vAǴ˥cJ0j:"KڳFeA[SϸI?s^'Z ~r;gWO΅D/6xz߮75\ ~r;gC?P,-' j:xѴE-ʙjSeZ ~%MuCJ#M/ >Jz  rooN+WX Mw5$J9^Qsr~tCP6_-0ԺpbHG=ޖ41 Zx] QmM ^Ydv[.yQ/7̈y˥Ye7G+_K%2)̽:sY+YAt#]6[.g N5Bye\”FeUQ20wٵ`@[|5톈lW"aHńQj[Ey[nF}$sz1u!/NӋo>rP9a/YL5㜅^A쬚nW׽ wZ//N܅o^ إYQ߰v-:05_t[z]9S)!&&\悫pEa.=FTt'i鷫Z ϶HeKS36iѤ3/dvfEM77~x3F*1w`xE$^-lĀsmǻcN϶HcA䦭d~o϶HHZ ̉.8_筨#:lcIe]ڸ~ZTZe]$0;9LPZsa;=/%WbT\WcirEqhpd|nE^1s 5zw5ܤzx@|~5^ 5\υ&ai\;]G{,l=toG6i?6k׊>3nl- 威E/־wOt\K[$Njz\.݃.neeVz;?ނgEq l*eCejfcIoȌզPE7* ռ[z\ =wb{^>NJ6##t(7gRS j0ۛ]K*qAݷ~Dc\utQoޡ9_7A!&-lv5Ypyߔ1UuUFggzj2O!}&Qw!9En*.TPO&W# 1'6ZJPp,_љ@kST8;ȧ#~VFJ gqXL)sJ#h3_VyIfugO|L=Ӂċx_z(/\ɫdv$޾0,/WA?rCVRu,J+ N _*s#e.4Df3TZ ~ܼZ$ OɿO`^\] - ĩɿOr &|Hn?'V<a^ BFc1xN3?j!2cZ_"3pkp1T-Ś_hLmpAR]уEǩ܄l0.ޅ<ا):N=&^9w+<~$]@#?.'Ag_m;*;68k&S?Miݱ"g~,= B⑍9hwyZw3=Xf~UUH<4 <,aJ+㕽=8COMb_lnIزq( [\ ]8}(yIB^1߸v>GG|d!_OXp6p0+YYYp6ph8ǽk/p~_D$/뜙8ې?}_G˟ /L|Gzv|:o7ix/94q3mpKʣ]F(5]E 8PfRyup/ZVE,x.B_-TT>9IDAT)E~30(F ܁[i/\}LAs'>sY>6[Gqt|Q|Gkp -W<GwGw-3^}q σ ůס5;g+#zssmv9Θ鋙_zK*s\AAv ϳxJ:\Al1l%P.(( ֟5ܦ0?cI|0N5(K=Ia~y)Ƚb$[Ux^ɟ?Ka~ysqxKg#sxn*)O9o"w*OX E9pCTp} pfQ5t #jE}x ӢѫXSP?w`ħork*W0c rvg[+84)nܜf `揍MN\v8?mg;z_CަCc~[S29<;޳W~hS8k=OŚCc~{ n7c™ B0Qc84\AC.$i`j.ohL3ڃsWM46[`B12y(.kmK & syVVwa9TT8Y*+Sd8qolP-`!_Ǎ3bnR`n~iݜ%"5f ~ ;74oo[{:;74oo[{ % $UUίj"VK–TWJ{ %aKAA \,AX\zrTᮀsyQ n6VW;s]䶸1q'YaQ<Ǧ\@ZJ N+Vd1[rnșo M\mr bV#3̾=@ky?gd 7)9s!Rlí=,9y*k +6=sf}ŬYGf}:`<;jw*|>Վ3|?OS-SX(@PN>ܬ 7~X"`WʚCAA~ *rK–c:m٢$l9. [@RQ|%aKA ~~.? @ |WPPPk`}OVE> >6,+df:h=} MN{P :GR|WZx u/r}2 rRTա@y--dS :&+m{ϥV ٻquBv}c壚"4Wz[V|X6W37l[u{[Q/OOç{X@F? h右.m^8k8ha`gF@cO:{; @Q8Ҷč?o8Vq~fr.={$~.m{D:?W` f~E5Tfʿ }|DG'p7VX$CZhK2{4[mcei8[i7$U{GϢbWmᬃ˱qܼ5&:d8ĭvw&V;*G5_(g(@\VR?Oz4Q׌it :w-FOѡ'8@Ro;A; D.4.2.4 Read-Side Primitives


D.4.2.4 Read-Side Primitives

This section examines the rcu_read_lock() and rcu_read_unlock() primitives, followed by a discussion of how this implementation deals with the fact that these two primitives do not contain memory barriers.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node95.html0000644000175000017500000000702111672746162015570 0ustar paulmckpaulmck 7.4.3.2 Parallel Fastpath for Resource Allocation

7.4.3.2 Parallel Fastpath for Resource Allocation

The commonly used solution uses parallel fastpath with each CPU owning a modest cache of blocks, and with a large code-locked shared pool for additional blocks. To prevent any given CPU from monopolizing the memory blocks, we place a limit on the number of blocks that can be in each CPU's cache. In a two-CPU system, the flow of memory blocks will be as shown in Figure [*]: when a given CPU is trying to free a block when its pool is full, it sends blocks to the global pool, and, similarly, when that CPU is trying to allocate a block when its pool is empty, it retrieves blocks from the global pool.

Figure: Allocator Cache Schematic
\resizebox{3in}{!}{\includegraphics{SMPdesign/allocatorcache}}



Paul E. McKenney 2011-12-16
perfbook_html/node87.html0000644000175000017500000002105411672746162015573 0ustar paulmckpaulmck 7.3.3 Data Locking


7.3.3 Data Locking

Many data structures may be partitioned, with each partition of the data structure having its own lock. Then the critical sections for each part of the data structure can execute in parallel, although only one instance of the critical section for a given part could be executing at a given time. Use data locking when contention must be reduced, and where synchronization overhead is not limiting speedups. Data locking reduces contention by distributing the instances of the overly-large critical section into multiple critical sections, for example, maintaining per-hash-bucket critical sections in a hash table, as shown in Figure [*]. The increased scalability again results in increased complexity in the form of an additional data structure, the struct bucket.

Figure: Data-Locking Hash Table Search
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...4 spin_unlock(&bp->hash_lock);
35 return 0;
36 }\end{verbatim}
}\end{figure}

In contrast with the contentious situation shown in Figure [*], data locking helps promote harmony, as illustrated by Figure [*] -- and in parallel programs, this almost always translates into increased performance and scalability. For this reason, data locking was heavily used by Sequent in both its DYNIX and DYNIX/ptx operating systems [BK85,Inm85,Gar90,Dov90,MD92,MG92,MS93].

Figure: Data Locking
\resizebox{3in}{!}{\includegraphics{cartoons/ManyHappy}}

However, as those how have taken care of small children can again attest, even providing enough to go around is no guarantee of tranquillity. The analogous situation can arise in SMP programs. For example, the Linux kernel maintains a cache of files and directories (called ``dcache''). Each entry in this cache has its own lock, but the entries corresponding to the root directory and its direct descendants are much more likely to be traversed than are more obscure entries. This can result in many CPUs contending for the locks of these popular entries, resulting in a situation not unlike that shown in Figure [*].

Figure: Data Locking and Skew
\resizebox{3in}{!}{\includegraphics{cartoons/ManyFighting}}

In many cases, algorithms can be designed to reduce the instance of data skew, and in some cases eliminate it entirely (as appears to be possible with the Linux kernel's dcache [MSS04]). Data locking is often used for partitionable data structures such as hash tables, as well as in situations where multiple entities are each represented by an instance of a given data structure. The task list in version 2.6.17 of the Linux kernel is an example of the latter, each task structure having its own proc_lock.

A key challenge with data locking on dynamically allocated structures is ensuring that the structure remains in existence while the lock is being acquired. The code in Figure [*] finesses this challenge by placing the locks in the statically allocated hash buckets, which are never freed. However, this trick would not work if the hash table were resizeable, so that the locks were now dynamically allocated. In this case, there would need to be some means to prevent the hash bucket from being freed during the time that its lock was being acquired.

Quick Quiz 7.11: What are some ways of preventing a structure from being freed while its lock is being acquired? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node409.html0000644000175000017500000000466311672746163015661 0ustar paulmckpaulmck D.4.2.2.4 rcu_try_flip_state


D.4.2.2.4 rcu_try_flip_state

The rcu_try_flip_state variable tracks the current state of the grace-period state machine, as described in the next section.



Paul E. McKenney 2011-12-16
perfbook_html/node427.html0000644000175000017500000000754711672746163015665 0ustar paulmckpaulmck E.3.1 Combinatorial Explosion


E.3.1 Combinatorial Explosion


Table: Memory Usage of Increment Model
# incrementers # states megabytes
1 11 2.6
2 52 2.6
3 372 2.6
4 3,496 2.7
5 40,221 5.0
6 545,720 40.5
7 8,521,450 652.7


Table [*] shows the number of states and memory consumed as a function of number of incrementers modeled (by redefining NUMPROCS):

Running unnecessarily large models is thus subtly discouraged, although 652MB is well within the limits of modern desktop and laptop machines.

With this example under our belt, let's take a closer look at the commands used to analyze Promela models and then look at more elaborate examples.



Paul E. McKenney 2011-12-16
perfbook_html/img43.png0000644000175000017500000002473311672746031015234 0ustar paulmckpaulmckPNG  IHDR8yQPLTE^\\TRRMJKPMM# b``mkkXUVNKL856iffKHHC@@wuv.*+m5ytRNS@f IDATx],rRֵRSB̀$$g=9F "03Ø`,TCDͪ[O|s im\'(*ƺ~gr {䀣=ҿ586/2{͎y|*xov qw?SY~f: \=fp7`m 2=맺}grYGCl݁|0jzFdCyͲ 511ݿkDmr2W#n48l&B } eXv?[wk`W^։cHnވйHdI3Uw{=^SmcF : q7LN`05og˾\;~ŋoW)d}a Z:cs_؉ψОI<[t[7c^Ejgu[|G O-穋Ëpk>v .]d$VaSR{VUmmޛKGtQP'jq!$jdNΦ X=ӝ3#4W OAђqij(E^ZXX[+jF͑rtJ+ Wк7 ;#\3 W{E:|8mqw Û.M ` L;MJƻkٱ^Ũ`Vm:}]szGk8[hc"zmW~& xj>>Dz;(= Le6Le:,yնrFS}Ĥwd/IO`K+xWCzW5\$;nlm>uMK<ބo~Ȇwe3 ,(61Jg4v%w +"~`6:eÍL{cN᷁OsR6ZVyGPUiT*~->}Nb;E>a~=67z}A5ANP?\FĵB!N9iqmif\}&\)K\r9~sZ>⍻zhwn;yZfkt_hV1r G {k[`g]|9qŠW B_ƯO⛅!inİVٛr?lZK<;=捫{^U8EGߪ֏uր00Nݍ HLۺZ˱q&:fUeURe+m1ύ26N)JƭJ;LgƱpМ΀PӅnx}1Yx2 Cی71+7j( Cʆ<2uX`ݐ]ͦ ]:pw\ސhefJxJirذH&d$7*e_ݦ݀& eN2^bIC &DLsU}`SzmtPV«Ьl%!"~.;N\0" (s $9N;6fxDf0"7H[WΪZq^:z`꛸>ItK59lXWNik8NqJiI㕿wb/ոTU=bfNkixaBL׳/تyRS}`3ݻ;0 k<)–֖KѻƑS?Ů;FgK6Sl'"/ZQ_DBQqxc*׻nbE!yiU? xC]4fTGwMs'&z*en;*59nVa,xߣKIa},5jZ5Hv6BnjQrNMf: @BX`^\7 T%2qtl -H֭`bqIoW"YΩ0KQV*cTS{ |" Zÿ_aMN\s81;m+8N($N͒؊}+i\ƨ Kl\PtoV>&Swt2v;-[Eo%|~ڦPB sRao~߀XгuikZX#MNySxs׏㍃8%6_٪>OޮN#к룚u 1:u};[weݸ1>Hƀ+N^$iʟbSMQNQDQN/wjSV αܸmEL[hr->~̘VNIqH{t%)Ԍs `Z!s1*k~FMm.rXg8 Җ2MA iVe5/rJ6p &sͪ\vhZgZ{T۝9Bt-/_pl%YUqͺiz_ԋmUcNqd=[=}{k{miػZYʁQ&JepXggou u //kXiy V7$-} !t#UntE SjtkAS$$4#cWc #\kqBIhjIq,tr'PaW$7^jcZ7i^ ̓}=Gd=2n9GSlq=Llw_Pl,˜ 4r?<kW"\j,8V;휱8`p2BoQdUBl]#H'̴qL_k/bK&rQ\+mm|Fb/Nþg"P9V6rD7d8k-x r? KŐfuuP^*(xE7(_|S|J,)nto.y/[(EbC>nEWB:vT.GeSeL:Os9ւf,1"D޾rQ%tOCt>2褄PU7yolep,0SgOS>Dz.R!D'Pҋ~ 768gK/_!RNgPs9B*2ܪdO8eT2"!U]%O y_) s/: \u y3C&楩ͺŚ^%f+2rWܘ?_537>l9=On贼R FBHƫ<&EgIM߭^:0a dM8xۼX*FsE$GBj[K\ Ƨ$|9>y#?Ŷ%6zzRDZR(1Es6DR/,QsIS9}|8_Pwגj\- BsSm1M|l Wͦ?iChk`99flˤO&4fWʞؘrXإn/ۙ},gX#]0cc8Tsޕ8bMNSW:i0<cƫW&`XXZX妧s!DIa'pUEwjqf:c4%+-W dG8}#VnoL@Jv-4f!efz_5n,%fE8d +7Gr'W3|?twB|݅@g۸0׭e`=ڏYnypYEsQkRREҨ-R -lPGf=447AVʺHeؿ\zV)^qCM ~/eGfeGʤ/ܻui(NGT6ސŗ96ΩCa]P*`CļL^I9QP%D1NtNVUpkLέ&{]иEsgaO^uH^󺍲N6X֏M(>v% .Zf@',^@' F:&Ne9F@O]ym!rkpɭJ QkiX"Z;6N7*E=J֞4Dc.+ I4&% 3sC>c9ם^~n|#Dj,[V-ZаkziBB ţ6YF4f$لK&Gr‘eddT>Hb+*.Ae`q>4!Np'Nvj{ŝo!xOWC֒:mf>+wrӰ;#!;#ڵ upREbT*S̫!]PPNP7e;-"8q&0A\vq 4&>ϙ ,84s:1p 8Y^ <NjPuS}glTÔϖHͻvE~n̊WuϕܮO kC'#l]8gjuc̬RlȣdXٖ{w$ӀZ- D.3;#N#yAfvpV %dj^"s:%oԷBbWʥjɷDRL :}F^O69@OQR c^_Mڍr@uNoU1)}jCqբq: ezQN%R3| m| ZREuܵI4V88[u{DwBf5- $W Ex:ƔܷosXvj);r4I]bzc[JwthkIW>kk}G p[+JZJ78o^"a`"L.RM1#UDT\ЕRl:Ųܙp3DZ mS[O;C+ٕvꆔLIw*aq-: VpO`לzq̭mxjS@8f-U)%b0:caXhUqpý&#(qde^T䆿iQŋՍֻ//5uKU2FPT͑Ëx,\[8* 'fwNAT˚ZZDrЧ֍8˸B.5_ԷK5ԊqF?O3'*)%s g^qK|RqѸ涷ZPpk;F@q1YL>RCِ [+#n,8h-ۜX^sNdHAB0@ wD,=oP5D}r!sƵ7C t<[=O#Ʈ*!O 1ļApR7'M;M؂A/7?> KapSjAAz#XӛJ/1]Ӎ{h1oȁ= 'ҜrҼݽ{%f$uGP.{ٽߌDRUk:;1;^!ND9iKa~/AOVO`wcS̔ h.՟Cǻ.imwo[Mɟ @#?Amhz KNbe6rbʑ4AC^r%qwB")B_թ:u)͑?75vHTo?SB"&Vj,r,YwekWUy\MO7"8%cw? aPmDr(ۗGJ})vu23wߘ"<9!bT +{.wTMqQF ,IDATtx3AŨU0=xĩPDZ[rTY((8r2)hɾiƣ?,a!,J C?s!(yimz}3>x*Tơ&\xXATT {J?|ߌen+rv8w\,t45weަ'`gn%OU2͊l>ܠ ]$aGa#4+PPe:[w26i d+O揫4h>LX_+Vy"s^W$' 6qaPq`7;/Ey"sT<+{C5[M +8⻾{s4uc%'ݧj!;4l*WK qׄT-i'ɺ(Gzz/7Lr\U~nCq^DGƮUCt'- SluOuKH>ӓd:`BN;w\!J4%{$r1|#${^vE\A-.mWB-S_odWVi8.\Ԇ~?7ߞvx8r@/aWB)hvd8 hJA#@#WFC( r7 6q~;\yWPP Hja.x{nͲ;zݳq&`"Jy'ǬuűuͲPqķ$6@":\pjZ"ڇJ!i.=eűuͲ;!lta}^5-Y3%HJΣ-cr]l3T9m7+Pg)fYpd:zAAA帐? C>V-;5'"|ewov6/\ RU8xuigǧvYA({Qv7SC`,Fw2a Y5teӱuY-+#{a|cPt;tuk[֍8;y->B79čgFPܒw]xg갑eS(Ҟ2>]hV,KIÍN :!Qnds{h|ul7(H \b=E:g_)Is@waOZͥN\|EFGiUA%?]\*.sLiмϴ2ubOw\)YG\:0]W+'8ߙ.Syi%ʹY'/J4Lz3&%(QհrvF4&c9yǜKwuO<"]ޚ~sR籍 H 4m :vFFĢu? /Nc */N:{%?kTVpP IENDB`perfbook_html/node353.html0000644000175000017500000000631411672746163015652 0ustar paulmckpaulmck D.2.7.4 Enter and Leave Dynticks Idle Mode


D.2.7.4 Enter and Leave Dynticks Idle Mode

The scheduler invokes rcu_enter_nohz() to enter dynticks-idle mode, and invokes rcu_exit_nohz() to exit it. The rcu_enter_nohz() function increments a per-CPU dynticks_nesting variable and also a per-CPU dynticks counter, the latter of which which must then have an even-numbered value. The rcu_exit_nohz() function decrements this same per-CPU dynticks_nesting variable, and again increments the per-CPU dynticks counter, the latter of which must then have an odd-numbered value.

The dynticks counter can be sampled by other CPUs. If the value is even, the first CPU is in an extended quiescent state. Similarly, if the counter value changes during a given grace period, the first CPU must have been in an extended quiescent state at some point during the grace period. However, there is another dynticks_nmi per-CPU variable that must also be sampled, as will be discussed below.



Paul E. McKenney 2011-12-16
perfbook_html/node218.html0000644000175000017500000000576111672746162015656 0ustar paulmckpaulmck 14.2.10.1.3 Read Memory Barriers

14.2.10.1.3 Read Memory Barriers

A read barrier is a data dependency barrier plus a guarantee that all the LOAD operations specified before the barrier will appear to happen before all the LOAD operations specified after the barrier with respect to the other components of the system.

A read barrier is a partial ordering on loads only; it is not required to have any effect on stores.

Read memory barriers imply data dependency barriers, and so can substitute for them.

$\dagger$ Note that read barriers should normally be paired with write barriers; see the "SMP barrier pairing" subsection.



Paul E. McKenney 2011-12-16
perfbook_html/node310.html0000644000175000017500000001445611672746163015651 0ustar paulmckpaulmck C.6.1 Ordering-Hostile Architecture


C.6.1 Ordering-Hostile Architecture

Paul has come across a number of ordering-hostile computer systems, but the nature of the hostility has always been extremely subtle, and understanding it has required detailed knowledge of the specific hardware. Rather than picking on a specific hardware vendor, and as a presumably attractive alternative to dragging the reader through detailed technical specifications, let us instead design a mythical but maximally memory-ordering-hostile computer architecture.C.4

This hardware must obey the following ordering constraints [McK05a,McK05b]:

  1. Each CPU will always perceive its own memory accesses as occurring in program order.
  2. CPUs will reorder a given operation with a store only if the two operations are referencing different locations.
  3. All of a given CPU's loads preceding a read memory barrier (smp_rmb()) will be perceived by all CPUs to precede any loads following that read memory barrier.
  4. All of a given CPU's stores preceding a write memory barrier (smp_wmb()) will be perceived by all CPUs to precede any stores following that write memory barrier.
  5. All of a given CPU's accesses (loads and stores) preceding a full memory barrier (smp_mb()) will be perceived by all CPUs to precede any accesses following that memory barrier.

Quick Quiz C.9: Does the guarantee that each CPU sees its own memory accesses in order also guarantee that each user-level thread will see its own memory accesses in order? Why or why not? End Quick Quiz

Imagine a large non-uniform cache architecture (NUCA) system that, in order to provide fair allocation of interconnect bandwidth to CPUs in a given node, provided per-CPU queues in each node's interconnect interface, as shown in Figure [*]. Although a given CPU's accesses are ordered as specified by memory barriers executed by that CPU, however, the relative order of a given pair of CPUs' accesses could be severely reordered, as we will see.C.5

Figure: Example Ordering-Hostile Architecture
\resizebox{3in}{!}{\includegraphics{appendix/whymb/hostileordering}}

Paul E. McKenney 2011-12-16
perfbook_html/node209.html0000644000175000017500000001560311672746162015652 0ustar paulmckpaulmck 14.2.5 Review of Locking Implementations


14.2.5 Review of Locking Implementations

Naive pseudocode for simple lock and unlock operations are shown below. Note that the atomic_xchg() primitive implies a memory barrier both before and after the atomic exchange operation, which eliminates the need for an explicit memory barrier in spin_lock(). Note also that, despite the names, atomic_read() and atomic_set() do not execute any atomic instructions, instead, it merely executes a simple load and store, respectively. This pseudocode follows a number of Linux implementations for the unlock operation, which is a simple non-atomic store following a memory barrier. These minimal implementations must possess all the locking properties laid out in Section [*].



  1 void spin_lock(spinlock_t *lck)
  2 {
  3   while (atomic_xchg(&lck->a, 1) != 0)
  4     while (atomic_read(&lck->a) != 0)
  5       continue;
  6 }
  7 
  8 void spin_unlock(spinlock_t lck)
  9 {
 10   smp_mb();
 11   atomic_set(&lck->a, 0);
 12 }


The spin_lock() primitive cannot proceed until the preceding spin_unlock() primitive completes. If CPU 1 is releasing a lock that CPU 2 is attempting to acquire, the sequence of operations might be as follows:



CPU 1 CPU 2
(critical section) atomic_xchg(
smp_mb(); lck->a->1
lck->a=0; lck->a->1
lck->a->0
(implicit smp_mb() 1)
atomic_xchg(
(implicit smp_mb() 2)
(critical section)


In this particular case, pairwise memory barriers suffice to keep the two critical sections in place. CPU 2's atomic_xchg(&lck->a, 1) has seen CPU 1's lck->a=0, so therefore everything in CPU 2's following critical section must see everything that CPU 1's preceding critical section did. Conversely, CPU 1's critical section cannot see anything that CPU 2's critical section will do.

@@@

Paul E. McKenney 2011-12-16
perfbook_html/node200.html0000644000175000017500000001122111672746162015631 0ustar paulmckpaulmck 14.2.4.4.3 Pairing 3.

14.2.4.4.3 Pairing 3.

In this pairing, one CPU executes a load followed by a memory barrier followed by a store, while the other CPU executes a pair of stores separated by a memory barrier, as follows (both A and B are initially equal to zero):

CPU 1 CPU 2
X=A; B=2;
smp_mb(); smp_mb();
B=1; A=1;


After both CPUs have completed executing these code sequences, if X==1, then we must also have B==1. In this case, the fact that X==1 means that CPU 1's load prior to its memory barrier has seen the store following CPU 2's memory barrier. Due to the pairwise nature of memory barriers, CPU 1's store following its memory barrier must therefore see the results of CPU 2's store preceding its memory barrier. This means that CPU 1's store to B will overwrite CPU 2's store to B, resulting in B==1.

On the other hand, if X==0, the memory-barrier condition does not hold, and so in this case, B could be either 1 or 2.

Paul E. McKenney 2011-12-16
perfbook_html/node348.html0000644000175000017500000001522011672746163015652 0ustar paulmckpaulmck D.2.6 State Machine


D.2.6 State Machine

Figure: Generic RCU State Machine
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GenericRCUStateMachine}}

At a sufficiently high level, Linux-kernel RCU implementations can be thought of as high-level state machines as shown in Figure [*]. The common-case path through this state machine on a busy system goes through the two uppermost loops, initializing at the beginning of each grace period (GP), waiting for quiescent states (QS), and noting when each CPU passes through its first quiescent state for a given grace period. On such a system, quiescent states will occur on each context switch, or, for CPUs that are either idle or executing user-mode code, each scheduling-clock interrupt. CPU-hotplug events will take the state machine through the ``CPU Offline'' box, while the presence of ``holdout'' CPUs that fail to pass through quiescent states quickly enough will exercise the path through the ``Send resched IPIs to Holdout CPUs'' box. RCU implementations that avoid unnecessarily awakening dyntick-idle CPUs will mark those CPUs as being in an extended quiescent state, taking the ``Y'' branch out of the ``CPUs in dyntick-idle Mode?'' decision diamond (but note that CPUs in dyntick-idle mode will not be sent resched IPIs). Finally, if CONFIG_RCU_CPU_STALL_DETECTOR is enabled, truly excessive delays in reaching quiescent states will exercise the ``Complain About Holdout CPUs'' path.

Quick Quiz D.10: But doesn't this state diagram indicate that dyntick-idle CPUs will get hit with reschedule IPIs? Won't that wake them up? End Quick Quiz

Figure: RCU State Machine and Hierarchical RCU Data Structures
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeRCUStateMachine}}

The events in the above state schematic interact with different data structures, as shown in Figure [*]. However, the state schematic does not directly translate into C code for any of the RCU implementations. Instead, these implementations are coded as an event-driven system within the kernel. Therefore, the following section describes some ``use cases'', or ways in which the RCU algorithm traverses the above state schematic as well as the relevant data structures.

Paul E. McKenney 2011-12-16
perfbook_html/node17.html0000644000175000017500000001121011672746161015554 0ustar paulmckpaulmck 3.4.3 Resource Partitioning and Replication


3.4.3 Resource Partitioning and Replication

The most effective parallel algorithms and systems exploit resource parallelism, so much so that it is usually wise to begin parallelization by partitioning your write-intensive resources and replicating frequently accessed read-mostly resources. The resource in question is most frequently data, which might be partitioned over computer systems, mass-storage devices, NUMA nodes, CPU cores (or dies or hardware threads), pages, cache lines, instances of synchronization primitives, or critical sections of code. For example, partitioning over locking primitives is termed ``data locking'' [BK85].

Resource partitioning is frequently application dependent, for example, numerical applications frequently partition matrices by row, column, or sub-matrix, while commercial applications frequently partition write-intensive data structures and replicate read-mostly data structures. For example, a commercial application might assign the data for a given customer to a given few computer systems out of a large cluster. An application might statically partition data, or dynamically change the partitioning over time.

Resource partitioning is extremely effective, but it can be quite challenging for complex multilinked data structures.

Paul E. McKenney 2011-12-16
perfbook_html/node53.html0000644000175000017500000000705011672746161015563 0ustar paulmckpaulmck 6.2 Statistical Counters


6.2 Statistical Counters

This section covers the common special case of statistical counters, where the count is updated extremely frequently and the value is read out rarely, if ever. These will be used to solve the network-packet counting problem from the Quick Quiz on page [*].



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node337.html0000644000175000017500000000742311672746163015656 0ustar paulmckpaulmck D.1.3.1 Data Structures


D.1.3.1 Data Structures

SRCU's data structures are shown in Figure [*], and are depicted schematically in Figure [*]. The completed field is a count of the number of grace periods since the struct srcu was initialized, and as shown in the diagram, its low-order bit is used to index the struct srcu_struct_array. The per_cpu_ref field points to the array, and the mutex field is used to permit but one synchronize_srcu() at a time to proceed.

Figure: SRCU Data Structures
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct srcu_struct_array {
2 i...
...t_array *per_cpu_ref;
7 struct mutex mutex;
8 };\end{verbatim}
}\end{figure}

Figure: SRCU Data-Structure Diagram
\includegraphics{appendix/rcuimpl/srcuds}



Paul E. McKenney 2011-12-16
perfbook_html/node462.html0000644000175000017500000003501311672746163015651 0ustar paulmckpaulmck F.2 Chapter 

F.2 Chapter [*]

Quick Quiz [*].1: 
Why should parallel programmers bother learning low-level properties of the hardware? Wouldn't it be easier, better, and more general to remain at a higher level of abstraction?
 
Answer:
It might well be easier to ignore the detailed properties of the hardware, but in most cases it would be quite foolish to do so. If you accept that the only purpose of parallelism is to increase performance, and if you further accept that performance depends on detailed properties of the hardware, then it logically follows that parallel programmers are going to need to know at least a few hardware properties.

This is the case in most engineering disciplines. Would you want to use a bridge designed by an engineer who did not understand the properties of the concrete and steel making up that bridge? If not, why would you expect a parallel programmer to be able to develop competent parallel software without at least some understanding of the underlying hardware?

Quick Quiz [*].2: 
What types of machines would allow atomic operations on multiple data elements?
 
Answer:
One answer to this question is that it is often possible to pack multiple elements of data into a single machine word, which can then be manipulated atomically.

A more trendy answer would be machines supporting transactional memory [Lom77]. However, such machines are still (as of 2008) research curiosities. The jury is still out on the applicability of transactional memory [MMW07,PW07,RHP+07].

Quick Quiz [*].3: 
This is a simplified sequence of events? How could it possibly be any more complex?
 
Answer:
This sequence ignored a number of possible complications, including:

  1. Other CPUs might be concurrently attempting to perform CAS operations involving this same cacheline.
  2. The cacheline might have been replicated read-only in several CPUs' caches, in which case, it would need to be flushed from their caches.
  3. CPU 7 might have been operating on the cache line when the request for it arrived, in which case CPU 7 would need to hold of the request until its own operation completed.
  4. CPU 7 might have ejected the cacheline from its cache (for example, in order to make room for other data), so that by the time that the request arrived, the cacheline was on its way to memory.
  5. A correctable error might have occurred in the cacheline, which would then need to be corrected at some point before the data was used.

Production-quality cache-coherence mechanisms are extremely complicated due to these sorts of considerations.

Quick Quiz [*].4: 
Why is it necessary to flush the cacheline from CPU 7's cache?
 
Answer:
If the cacheline was not flushed from CPU 7's cache, then CPUs 0 and 7 might have different values for the same set of variables in the cacheline. This sort of incoherence would greatly complicate parallel software, and so hardware architects have been convinced to avoid it.

Quick Quiz [*].5: 
Surely the hardware designers could be persuaded to improve this situation! Why have they been content with such abysmal performance for these single-instruction operations?
 
Answer:
The hardware designers have been working on this problem, and have consulted with no less a luminary than the physicist Stephen Hawking. Hawking's observation was that the hardware designers have two basic problems [Gar07]:

  1. the finite speed of light, and
  2. the atomic nature of matter.


Table: Performance of Synchronization Mechanisms on 16-CPU 2.8GHz Intel X5550 (Nehalem) System
Operation Cost (ns) Ratio
Clock period 0.4 1.0
``Best-case'' CAS 12.2 33.8
Best-case lock 25.6 71.2
Single cache miss 12.9 35.8
CAS cache miss 7.0 19.4
Off-Core    
Single cache miss 31.2 86.6
CAS cache miss 31.2 86.5
Off-Socket    
Single cache miss 92.4 256.7
CAS cache miss 95.9 266.4
Comms Fabric 4,500 7,500
Global Comms 195,000,000 324,000,000


The first problem limits raw speed, and the second limits miniaturization, which in turn limits frequency. And even this sidesteps the power-consumption issue that is currently holding production frequencies to well below 10 GHz.

Nevertheless, some progress is being made, as may be seen by comparing Table [*] with Table [*] on page [*]. Integration of hardware threads in a single core and multiple cores on a die have improved latencies greatly, at least within the confines of a single core or single die. There has been some improvement in overall system latency, but only by about a factor of two. Unfortunately, neither the speed of light nor the atomic nature of matter has changed much in the past few years.

Section [*] looks at what else hardware designers might be able to do to ease the plight of parallel programmers.

Quick Quiz [*].6: 
These numbers are insanely large! How can I possibly get my head around them?
 
Answer:
Get a roll of toilet paper. In the USA, each roll will normally have somewhere around 350-500 sheets. Tear off one sheet to represent a single clock cycle, setting it aside. Now unroll the rest of the roll.

The resulting pile of toilet paper will likely represent a single CAS cache miss.

For the more-expensive inter-system communications latencies, use several rolls (or multiple cases) of toilet paper to represent the communications latency.

Important safety tip: make sure to account for the needs of those you live with when appropriating toilet paper!

Quick Quiz [*].7: 
Given that distributed-systems communication is so horribly expensive, why does anyone bother with them?
 
Answer:
There are a number of reasons:

  1. Shared-memory multiprocessor systems have strict size limits. If you need more than a few thousand CPUs, you have no choice but to use a distributed system.
  2. Extremely large shared-memory systems tend to be quite expensive and to have even longer cache-miss latencies than does the small four-CPU system shown in Table [*].
  3. The distributed-systems communications latencies do not necessarily consume the CPU, which can often allow computation to proceed in parallel with message transfer.
  4. Many important problems are ``embarrassingly parallel'', so that extremely large quantities of processing may be enabled by a very small number of messages. SETI@HOME [aCB08] is but one example of such an application. These sorts of applications can make good use of networks of computers despite extremely long communications latencies.

It is likely that continued work on parallel applications will increase the number of embarrassingly parallel applications that can run well on machines and/or clusters having long communications latencies. That said, greatly reduced hardware latencies would be an extremely welcome development.

Paul E. McKenney 2011-12-16
perfbook_html/node332.html0000644000175000017500000000644411672746163015653 0ustar paulmckpaulmck D.1.2.1 Initialization and Cleanup


D.1.2.1 Initialization and Cleanup

Each subsystem using SRCU must create an struct srcu_struct, either by declaring a variable of this type or by dynamically allocating the memory, for example, via kmalloc(). Once this structure is in place, it must be initialized via init_srcu_struct(), which returns zero for success or an error code for failure (for example, upon memory exhaustion).

If the struct srcu_struct is dynamically allocated, then cleanup_srcu_struct() must be called before it is freed. Similarly, if the struct srcu_struct is a variable declared within a Linux kernel module, then cleanup_srcu_struct() must be called before the module is unloaded. Either way, the caller must take care to ensure that all SRCU read-side critical sections have completed (and that no more will commence) before calling cleanup_srcu_struct(). One way to accomplish this is described in Section [*].



Paul E. McKenney 2011-12-16
perfbook_html/img186.png0000644000175000017500000010627111672746040015322 0ustar paulmckpaulmckPNG  IHDRY[ PLTEؾ &% (*1RLM>< wWTUof\a"$.   7 $  \  u}  x" {ic#+1/7@|jd?BI$xaV'(.KINI|+*|cxy"&,EfXQ$   ˿ R1   && #ѫɤE?@YYH j!8:@Wmgݪ= "(: f b l\Xp_0 b _PK35: #@<@  YNEG23<=-/7  -1: B#* i &-6uec1tRNS@f IDATxwu'XIGlL6!G!Ru OvѴt< U][(Ñ z12ꨝ>꥓D'F0"R$iѝ`]lbiWvk{}URNE@կnw-C=+0gX0z|lFhO~lyxlވFhD_fjX ?lY~ f/I=8ij <!:z= u8gѳ1 ςYWbu"xVK#Fܑ (;]tVp<,ͷۥJ>0tv-t#ײ͹Ng6_ffZ[\U8 'vcxFF(Fx-87th `ȾlU,Olik\ǝ̙Gw,kYo:1pPg6sN|u6"-"Y+hm:Nu^h`IhQ lmSpt!!-TZ)"~4ƈ2_$va=G|D,wh>n jcdB ;U~S6Wdk,pzFiAzŋGtJ$V9 YG~+QQH3 X޲J6&^hl|)7~Л-Zݏ'pwpldp!!ά6W"Jzoqkd bV?^g1,1f! ֥*,[Lh\K&?EZOcEB9 1Oz , R*d*̧qp"/ DpY*# aT}Z /?ōJX/#nϯk@Xʆ! gM 2R+UuoG$D 0::-T\ADio e)b_A)tlΡcpSД!/HBpYH/aýZYn|USF+8H *n@* tը6q'AYr ww;N68 8U,V*2yОNu*m,(ȍFcUA%n ̼VA0; cvg|÷p1^V+lԾ;1YD#;Wapiڬ:\u>Gd,:WVE?t#Ã:.Y)V|ak]X97/%jg>/`XtnH6rqdAHm5g~un;ծP*&/زA瘱 -xglX e̅fmsdoҴ9ut, e#֪>X3ȍW`Njph.@e_;p6\=^N5~H 6c!ʆ\B%<}n}i_v:|Ʃ w|rhV z@<ܻj%bq3ֺO?\[[ʙS>JN]AWyo1*}Ѭ.5PDv˃q~Sq7OfX(*8e֓: m ݚ溝K4ۍSD9] ;c.ej.Z +؞ɊIA`1Z_Lh)9p^ ]^\\_L dW (7{^kwةǑZ&m@P _(pq^׷6 fψV8s8Vc\, ߁`VHAǭG"w^h =-@BXVXtxU[19q/|dEb4Wo+zݖf&u[BAGr8zZ n.mԳKmǵw҃[h|uG^2ʳUbLBŖX&\L:+!Z'GHb NdQRLZj dDQt᭞P Ri};6ң 7=pZ4f>W H쑒 d+Cx>vFWaF̑,9UP .K}Nf _DK\_d TSA)$v FJ8@JxԴb&T=0 4k I54~Zq%q#u~(H!-U4'eOI%eՇS-z+wE \(&E[gĥO`Q<Ƿmd$cܪ  :X@`9 p6A2`UPc¨j@#- e\\`zb$>Q21U ;<2<)'ưVfs9y{>"0ǚε.:3^:_nqԢ/dDk9zsNضÅ'ۜ2=jޏYّ̱{EZC6v o$n'wnjlK-m 0D@ -\ òٖ4HyfӖ6- b2(` hI˛;[FYB Jꍄܖ K8سOi[ࣧr˞LKIM)"$~5GFWKZ;JWv 4*B %f~o_g/7`˨g!yH\>Hd|8jX@aiȮFgjƧx6(4r)wWOmZwGX/&>A:U[pmewzm8-F#,|"g߼vXW9g*LKFFtf<ECjuOYms!w4_XKj۠7}/7`jrvn胼5ΐW}"t-Rtè0Rh-T8ڮ>kڙ3gpSsD7O{lHdv޺.H~=;s>|˭iGɦ;`P^MO5κ ȶYs\fl\sx`C'g62f #ZOdZ5]wiKe7"`ֺkk:ՠ%uC_Z>DH꭫G)Zpxϣ녵ۍӲehcw,kI~l+B`lLCqƥۧ\zнIR1nvLnP®'zz Γ4os{螭,.s7 %D\ce 5;VӒ=eXmN[PȢu%g'ZN[)rߪǽȁ ݃E/ʱ+cA娏>pBOlHb4q]A&'{b$ȮL[5m"VmcÓ#}yL] 5X*~#+a8i)d/QY2gS=[).6ٷa42wXZSHjbSLgtE}ǔF>ZHc=}'l;<wDNjEu {uXukߨLtlm;_J l4?~k=18ˋ{ͺFWG(bL0zݳcr.zH9?0w_ aQJ(˔. g{0a߱֫mjt< m xoA+/Yԃhdݰ[`aVmb%[i_t汰;B7XِnQvl2ώ t*¡w8P)xӛ*` $tIHK`Ӌ{ Ϋÿ! Кf),n>*`%bdE6|HA8e+5#ҧV@(;,b&6Ǥ!̇{TqU$蔯@(1_z]n $#UWhQfFo@FKAFKћdIP4~R'Rr9 c(Q\dT,N "Eժm(W/ߊE'{qdt95HJ( x2k@.f°<kPZ0M(µXE 8TyI'Z+HVUayXI 2$ r.8o[ߪm/'/$sOT$h,.ZSXRORI{ڥ/yq֟>6LgPz`Xby}ߝji\i*QTH"#5:#iLϟk4ww~wvJLnck΁8L[qBF6"dDO$%NATMiO~M|`*Y)8"lFMӎ8Z]O+5/6jjUZZH3" T0v1oY[zϒxZnU6nv׍kU dU03m$wU>-X8*/i n9a W\:YH0BqҌb<ʒ]qhJ(nGȓ[ CFqXi]Px{w|%vOZ(ѓ/:EvMs/}L'BY*@tc-`A~Pg܇fSWpjۆ7(V5G+ήB*+'f"%)fZ t>jtM 0:/%B׏1,*R)+{\:ie 0D -N4=5 vs]1'4/5^jqm:/~"SӰ /B Pt? 'y "vK%PlVZݝʦ t76f~ҧwٺfoO[ 7?ajcGs_ ˡ,V=F.jǠf`H|{`ϩ7n9vr;ڲwŭ|k00?pyuvُPq=n%VO4ipjxRmuGKw ]b>C߬5n[;w/ YuˋސVa`sq#@N.tTYB (4C%IEZ04ּdh | Vjh70j]uja.mOmV*Up#bHU~B)=N fZnSf컩ĒJUs1VeS[r``6R'UcBQ%|i%Ca0W*a|B N-j4͚`q; I?A27[ a][Q_踌\}v{GGPRz"1P8{6&,^wڦ3@ۻ7$'6!mBxeev;Nw;h-U1+ i UL yV鸇M~:|lwrXb:iƀ5lmm #N[w@B(d{+~^p{ӡ 8mLV.r동wrXl: c؊oa yN_^`/=[6NS|xqfGμ3!e)Xf˟]0ѱ| [sjLeLaLy`m9R~^mCh.K2&Dguv< [$hgc)獗z&*Y *v8;,.^3i3=\JF.ۑ ]b_P`;E6QPőw2D"jo~K!43Dq Y;euFN#ԽyƖsalj?^:GVzΈ h~`t⍳84Ph2 1hP{ Ool|hCUll|t_]*$2.<˗kLjd!I(Xp40F^}>[w0ïA'VwӧSTo@y^Syc}{K=pg֗~ߨnbϊmu^HwxLJ~ky_!}ټfňVn=sbCk]͎K |xm_>JAx=wxA8=ܹo^|=Ta.J;K巵(mo`+D޸`ݗ7m?FJ$l|,D זnS'ΛҎ-pu_-yFZh@jc< ,wXK} n 0zeC"~P:ZՀ~߹Aym؎n~;[#"8V l\4NT4Zee  `@-z~ ع`KR8NTy -IpR?8賀g^A¤!`N^PJ:Ebs#4:\#MQF0r"R@Y<@Kb ʎ zMzttfs68w5^ &2W ^]ʥӻŨ.2*Gw+f=7O̡D0q10I_.d3|( uۅɊ, 0eCOPlK YՂ ~klJ{ \[4j&wt+)_HX5ͭcy񽑕6]?nlhw/]?6,YfBwQ}9v[D7ù 'z@谡܃aνR >VTJh4ds X\<ԃڔ-~;3( E^v֖1xa=w5 ~2_j55^{LV9~4Jų#ꁂ8ҫjj = XS{R SJ_DR܇|0d4W 6V-Y6:w,k8nNp:%0vy Yzaz'xb܅X{ךޔƜ WCe I=WfjW|lu=5]~n5vc:I(/=`P F&/(,%9Xi""Ngю!\IX,86̸6} (ǚݭ[?M.?yHM@Ҏalv,&;)='I ^[iJub $[ݪEoRSOo}`+;5flHBR 5m# L9iρ|+oDAmva.hb{y])KVqp Ѓ;a[ԣ 9Ud\nuK`h_j4b`2a~cx1<X獍G\)ds vD.f^aXUע iPv}ss9 eqU]d%܊EnG?yK}gu: q.߉UJ,muREQ1d]"VtE;9 |/c;gMLqaoWX_coY_m3 Ds8Jnz ܩ!Ek tc$\zuP9G; i -bV!HӶ;JG%V{~ C^Z +56NYn2GF)a![.w0Q؉ͼ`jfVͅ/]2/[-Fu<(ݹn{}'+p[>!m";7f0QZVR}na(͉Ry0jyN˦h,S6cx P߫`}߹閧lo8Ě;Olq{rhɂJ) mývshi:a򩃛 ]=Ľ.;Ŗ6"\,2Q_ 'bJC'w w]wf|gwf?@]]5g'l6N|^8 \@,KV1opo M`d5GտY]z?- |;Qxf~.ukU*Vm;jah[ta*fAAŜuQ×[䘩Ae-0v{C15`@C":V/rh[2'#k̝CH,^i?msp,X$viĐSvﰽl{`X%':;9*ٸ#ndxVVK nTq2+lʓ2kq8emkqN9- ^9fil 0.x_̧Az)i'@hW(cEaŕ ڟ14mG|k8 ܈gC ^gl/;RXM.)#2xޟ{C3EPduV؞I(,ñbm*d&ZCEEW%0f 7خWDdFg T;ݖ y=[&3`/:aŅ[wКΈg0c<][rGukfL\01֬Q\;:aQŔ|[LӚ&4=pOcnZJ]%v"q:h>SؖUut4޼pݭn-/3 m>vߪ3+8ʷack8lj[\9y|O6"GWDžP[e0ѯҀjUضNi$sbseCqSfxos(69Z1.nnyM emPOѶenEi7V@,~E[ҕw؉m;q''+HJ%xŭ႟;sxoP8rݼ}d-H_k>ۆwi&Rajbsv㊔vԮwKMZ;Y;@?QXpZ bvh/Qm7!)M7l.8M͛K9 yEXj+8rGlCk+oݧ+$^%̍PT_+^dKXy 6,| עdHAR`Xd[ϛZkg5T/\h/];s?D=(.1֜{uXcb˾-O6WnQ6eDF36ʙ(Oac9z/}V<뉴)=62$N!˃eG( U d2U4^frGݦOjOs$F8ڑW^`@b!\AHq Asx6+sS|)mdRp@3v2Y7JbbF7b7 k"o'fkko}.iɏB 3L_bѢs{\:Syql'+>҄]+jm~R7`գ ֮S%JF'  'H\ M?d^ڈQ^!$xr~QޅιͮՖKɵԞ_;A]_H4[†7 T*-LqtuX=6P`~LIKM36D C4Qld!V:~8Z' `n(+v kD'⭯(иtzf1k7 r TkV`H:ZY35G5whηT`|OŘV:8ăQTS\h7'hNmXA@٦Zi }xi#˒Յ eՂsQi@+2=z@ f 0yװ4֔M,;@wkL֤ѳ}b2)JDdR,Gr֌CI›󾿐O %'Xٓ7R6aO-ax!eX LB#S#E31@|\5F,+w-;o!m., PG"LNd~RE nugi.V+@?^vɛ8ɿ;K5 IexC48Fg\ hbP$ZdZcLy-lPuj鸝 P#[ 7k^?_9-x2_Fi>C)blZi~,#,F ꫗'D~s?gH,oLb&[/>vPZw2uI/(+8GERֻC8-TO5B1~0蹃-b,.GQqdz}:+B *gسxSh} ˪֍t] k 򴆽h6GEtߘ:S U9w6^ųM~C =!QoXYe~>-^Z CW}w0P4geA ~~\R[^b?7oYnG_64;vͫG>У ֈHZ;\ÛkّΟܓ:TjX;/֯Ep3U >)_ln ߪǂĻE+eVg/6YzW擺~7u~Y*=P <۞﹎4{3Xd9xzاBQݶ?GlFgO˿f}~G-NKSn.4{5z@f^9^^?h.F=bd'YVȏXDƱgwUqGoG!:fLfYu},>Xh Z{U-0ZIW3'd3điL⹊>T%}DUɱ!SSEs]xseY MISjO1Oxvfثƚ!+;zjc\∓Z >Y4}읦Yz鯧Tn6yɵ1SES'Hyމo,(-*q5q0LYލ%U6˜I\sIDLmUKU%jD˪ԳAT+,K;ʕf*DžԸ'h8NٓN=d>% 8+Rm,C+yTDI*PV}m KgQP!E$e <8upNZ!uUm>ck!SiRFt,R퉖i!K>,z7"!lwTiUATp#EWYF6\[i4y:Op:#em|5oG4SU#evM]D7آz!&K183B@]+egpʘf@]%#=h,lG DvIr”hi{a Q$b4eTX}4KMe~gd%% (xP$>@Et%|8eqiXz~RyʇPVc~hŔMQV}~iI!ՁE-GWraRI ersh7i+I>52 L 8,R2H]Q/L+ aIڊU~I@ըeơaY5D)RJk EBL%I Mg]W3$LI"%Hz[0{iJy6K=cfIJt;1 MF$N։9i)wu/J$7V,B7P|'e~g6uĀ aKzF*yߣ'Cd88ɓNޡ܀S\ xO ֓D 䖬NT)x XxbAsgSO«x % P^VQ΄FB+-%0RMYQ-bA96="+@-KQV$E.eSk=KKKKRP=Y3g[v8\^L/O=q-U$lI2i2 8qŎItR޽e%=7dT+l/YK^(ml8r5μl4>oА@Je(A$7%{_O;@\vAVfIŅˢmS>&p,GB̄òg?˽XL>J[ljS&WYN' ϼMW\Ɠ8(pΚՖg[)c0{M28JPԧ&+b7\cZ4Š 'd=#i.PMB &LY¤4 TQjaVc]:p˦,J9{Px m1u4hK ڄ1'S$&5!4[=,oe*K>ufu̻[Q\-^ȥ*jS0#;f]hK-O8 {Ky^Z<$KCSؓG!PX wȠ7xQ_1"+.* d< rݲDoUVu6ۧ?b?}9e0\0[ԣ+Su)oҥ~MS ٛx C 8NY8]{?TbE❀ ed){^u;n:nm~$EPdN\7;؊A@CY$A0ROA5I3U݄+!5sYI}%tSF'M''װ]-u0=&kӄ-׾Z.-l@zҋpYMpH?aeq)i1h-1sSHI,c%$8*NI*o*Ƅ5盟yYq")9}/Xvj6.I軞Hٔ1DUAmYf [Ep^uJz6yqV *EϺAo0PtwδxٕsV3cBYҦ[}c fۼ%YSf k0%P+~8eSxWU0#efxH ;$FI<HFU=Æu^::%M{߻~^c Jٸs?|ܻn]͚6r j^SU))fԒ|1+M>ʒU Liu2+\O^}>K㱭agGV 3kO^n4hJ֮$}^F#JMn]ξǹʳلF4g>'u `6Fn㨰:&C_VlvWt316{nHljlʒ !ܤń狌W\f1EJW}p}u$ 2RK?m[v.山Y*a t^ tnv*,ߓ4ԝC>lD.TjDZh\,V,+Vg@`>ss/ ss,LEqy77_z|Њ'8iG.S*.CIJӶ(Xtb= ~6d;5X6*Uh8qqjJk #df֧ԖJam=Y>İb[QRL)Jz`aR%%tV2N?׀Al̕ӳ5l_E8EF?k!`x K==ٜhc)Q67"|()~ķb.) ;|fvA6,iz*aLAH|L_G"1^T:7ڣ=&fF<><2tf(3D6[.]F[~x#xs_#Y(qrsuZ"l,"ʠ@:$?4·mt6dY=K,E%VT=ؖcben!ՉnK k`4\1~Bh55I;?rώ`S f%_EE&i: Fy(4щ#W6 9ƯTi_R,9, l˥Ep97kTnQjc% %׹/$Wg{%CU/-e&'X'~oRXot'-úaUM]]ms]EA߲ΒMWRx}A"V +-&T =e3z{-юFh|:].bvȉirA^O<[-&IZʝcj5irчxw߹^և~`fc;ï"P>++b~B0N!> X?Ezkͨ`cfe5Zbťc6ߨHs,`!-z,[֖+` ڬW|azd'U(,sd?x)KC òΖQ3-k>|sp*;uVI&2ۼ%X?t0obESZR2*]DXLnRYR")Ҿ*,Z멡ҞDXNqTOv?ԯ8 IDAT&y؏ڏNbE2|c 3ѨZŞ Ϫ[M6,1)-rZ,ݔTMiDҢ"-ɴܵ.<>YZPoyTb~.@4$3gΣ w  |hVf15ڤUEJ:/ةfjߙA`.(US>XȒi.[[Q"Jx&l&IY+CCC/ dTh&PRŘچeȲt쎡RĺT#仴vZޒrltBo4yF.j*/5 ҹ2qc*CI+>Mmf&ݑ.6Wq_KpwvR4{2, `tQ%&~!0@CEnf~<!G4#xOtg},=nE,k \"adj0=ܨ}QYYɩY7Bx?6+,VuѮ) 3@mLٞeXg36Hp"b S Z;6$4=[i:ɡj촔H>V(6 mj 2/Fp-PUd'&<1Ş^k~|}cQw,娹c@{a]~ܼD ˷i00 ЂN3`Y_B,Ȓ"G4hC6&7cŖ6ISx-,+bsh6,X^50.n\}QP`gE ("bմ~Mf|VȒƆJiSc=s(ѵrP1dIkZԦG6JHH LfEgN|\ J "l]-[r,ҖppdrŶR[ .};.EK۞jC/E0RJéqusp:ig0YV:NjNc£R ;_4ekϰQ+ѧe(.e xERI@ df=2;۔U"٭M]>ǸcY:Dr4:Q0Ia]HAוOe>2z@Aj4gg}"Uh=~o1閩`ɤ_UwY%wm03FRq_}d6^)`Uo,U&w"MPHߕ{ {/ܨHK\̑)"iE1aU5 :z!J4*(NPI[D׭VTrSf-M)Iذll+aԅ Z!@j\0nx91?vfqe ʨO ZQam? ; ఁ]vtÉÕuJG~}&Zuzx Yy&;XϱH lV,WBqMB攸WZ] TPdl3(DCMi2ȁ`Zsa0CݝU܈2+x4A?@l4N^6$taх|{D0J`ZDbYo{")X$6Ϩ[OuSr _%k_MZa<ȅЦUO @\ʗY0G&-3&ּxɲFr1l ʘc0ZUlߺ+m-PbX9GU@Vdj nC,`IUcѴmSsاÿ|~}j ncsӘir;buv"u3 Z`>n8R 3h\ seni52-9{,w& Uz FKwλmbV%sU}hY/.W, VWFON&EP~jV.gHV"dPT ؑ&2wWY@nd}T1p@S2}d91QAIr䖂xŨedG}̯Njͺ8y."" qiFڞ.RS9-9Y "͚ L [#W#k1]km1qƢؿw;XbE!Ydȶ[1秦,J8{ P#iv}ڟ6M0f89tUD<)>L"kpKNЪqlM#D*in`Z l0A6R { ܱUc Q$y/ #Yيruɡš`oщM/owhfllN@|D"4}t/[j kDj75yds~2.ҴY_åNVLr2#z n*ȶ`C9&XCs"BNN:G}ճ؞ "ޖϏGj|f&՗4I=t6sq !G-g l-I@`i,`)y%,UFgx-۶lO ~ơEaղ(gƽ@q1׭_9۸k7#x4Bn;K֞.C[A%kʌL< %vV*|@y? YٹVZHud+&p-ݒ@[Pz8["y:8^%xT¤TbIQyAhPMY! 2QӰ-7Ic@ t׉˳~{bY #.+(W MX ~TcF| t=mlإqmH?gP*ls/w'XY{ȒZTC5 zg  jiFEWru]ThhILa~G0C& LcM. rXulL#EHpp:Ctf/S:[=G|S3.xB_}ع3ݐZ؇ebӮ@6vH41ź]?ӮE/TnK 0H8r#fJK'(1SQfYыgVGQjR(+Hp09+}&oO&9 R h-:s}:ѩܢ ̔|7SЈq$}&+^@o9XxH謕O~Q}qә]^bT;S+/qCO AnʙTYU8 J킮kQT#S,Jȷ@ mlIckŏ|A.gßܛ |…n"QBf 0r4r;OV  {`}xy*8. MΗ&_:odu\v G֎ FY"xAyEnZ;j64YE/4$Аz;W-|>؃߁`iUyiFM+(lk?Y mc\mx$"N1&*nB_MNV40]bqj)b:I%GHLOk{ M3%,EB~^쟅 Q}ݿoظ܇}d4VmV%s~$HQF˳nAe"W9Hi?J`vtl]IT*gRIz{{%}2l)EO+Th+]ݮ{]wݥꏧ518ihPfG oWv.l|wkeIï*>/-߅麓AcQ{k<6eG &ZH5WUe7{{jMA]jrr&Z8`3p|'nP\?w?$I y/ՠ]#2]t[j<>ˠ%`&8Cmb<~ʓO0~r!Yb-VO5S;$<1^ړ@/p tIѫ":!tb,]u*Y=*h4 n ܟA>ɳ _ok#-pZx2q|;MN^ qH3aڑ?4>6lVI8-s }kQ#A<5pAXJǵkAQ.PX/A[]EMcvGo~ְ"Ν}_vemQ#1+ M42IwMs+ a촷o0t|E2`kg_e_W;ţ[ؚ+ZYful/cR;dY9݀~Mdh'8wvw~{`w/]ݷVCiә$ѝg]{;>t$ؠs\O^JXe a`[*1o wnt3g]&^ϪeGFE-0O%¹',ئ5?iJZg )rHtEX@0ɔTMWGEڿ8]$ւ+ӧ|̥N@³ׇ,/QKk&ѫ ^d":d+8yC/}pY4vmOUNuDI?]4 |GhdCǯl"RJ !zxy$ڗIP<6K\UVtgǵs$v Y]L=uȩ )\څ%].Ny('J5/a`g({Wd~F+9KjIENDB`perfbook_html/img234.png0000644000175000017500000005226511672746037015325 0ustar paulmckpaulmckPNG  IHDR#d!?PLTEb``MJK# hffvstmkkcaaXUV856C@@wuv.*+ ;tRNS@f IDATx](E~ȨzI aZʙ鯺])DHrN ppPJko2]uRF/,A*5dN;>v0Q ?7y0W~ ="v ՌW:SGt^WzfS?:<qmSqX;~"bmk{' =F:2Ƃy?:X[[hI#ZgGlNp^:(nyaX߽ 84ϻ<&ܧ8cQa*nX?dyL0M]}.x. tgv;&jo{cܬ_&w OCzf~kcBV1xb cŸ{Θ`i~@G1&,Vᣘ|q=V8NGr"4 mWJci/ݦ<'~`ȍ C\gՄßMD;OGѬ{*_zlW0Vuʾn~F5Wɪh n_o>{S 0C"\L&o]'[_vGOPǽguАL+6*貶,~mag{a'5au>-7El XO?w|fbTS^}4=Zg/cVnhpt|1˪#oF1.9BG|ݧLAm{l-6 l9l$z[f3ַ9X0Z2T[^2Zh}dYqvwxgwtxCc3MR.X3#w3Mةpřo7̦fy>6Plmd8Lf Vm&x,ϖۧ͐6΃[heW>|k7kWS/Gm hґxuIwl&MšXűhfWsEy윬ynG Χki.:ۇ&6`9jU :8\ SqC8tۇid<ʹ]Zte>w_ S0]eӄjܨaS134qI=}w\g F@,;7)W3܌G]7M=o,wҍaqM^;m{/R&44šsjDTxaC/ C ?Oq`Mˠإ 3hD+y:xnW-̉Q'q5&~cihB6q y֗[z6 FtP[wSsGo^qG-8g2ƪt("23УU6MLYAk97iWإGxHܡdžF8ƪtan ] <?,pU0Дk7$NY :H  J<L+&v Ѕjk$pVSϚ=E^m R6`!/G)@lٖ foB߫kgLX~)5M9+YBqk|7Y~8Һ[epd3*eox#xkGV`jQvlEs[ A5ߊ1( t;7qyue"qmmG=): ZVv`yrTnL6SF>#~Wpu#c9}~ |l\Ҧ.nvj Xc6em KcX׹٥ĺ/ o50)(EMxVdsJJZT4 y x9cN{m Ϡ# [([>F;ô˭[ф?6hF+b6T6E[`e%@4fr5 |"]0 rp0}gr5;%uJBtȷ#h@_͹A3!B0kGW ɨk4Ij<[cH6,!+z &y3?$AG'Qum|pRÆ!IMb8sM]?+;Ω³5ez]L@FLޣWn峕b_-b#9IkAN ͳY6p9 ;5 u:|bPk?:JG5k@zE%i^ԭ%o)ahߠnn.V0"TйWd{x }!렮(܀:w u}kT>2-=v"O[üt[Mo6YaW5 ~?Wa^kϺr Ӽ{SMdp X?RPF \+i!e Ev\dkNnlӱEMc-ɠzFv3π]5 *GS&rݐ.j(MxAa! :Ad$g v@ g+91*gX _gPP|,B|]c_+㈏S;_5 4LF~s4ћ)9>]qe \"lĜ{ K¢5 ^d/x5]aX} 5&ʫ CHap QZ?pU7k!_uk&hn s{ lj*p쒗^AM9_ÔFvVؖ 5EĹL_WLk(9x8ccAñ2 ?w5v]&~VCUe/x4EUFݾ4)Eb]8\h\ĺڎAcdfcg9 BBk\yaW$*r.iqur/ k\$B\);5K`' __%Pab/E{_嶷1Zu[?W]EW%/b+%MAk藥c~ $aUQlBZ2K':nHpdFu*j^O}SWppRAZehCOLl3+u̜[ĈmSUK1TppTb^+zRE >Hϣ\Zmܹ^rIxH|9)PtO$o˙D.^V-B&T]I0z cqr\F=˺tH/I"AGKuѪTޯP@M+8 E$YME^!z$,Ezag֪ZSV#ΐ!F٨̎73S^F1eget VZɡNT!쟂lkҴ[ZH5cV0޼TRXT!d9$^NHE#꿇}hge}~cX^ymʍ7'`M fn7D8sgͪݠC|sɼ 6+ݎewnro1袅}ٶof@8L 7d A;᎓VS#YmЅE8UQRk6-MW/b`ͤDW邷Fņ߸&v6BwЊ|fq5htʙʺ'ΪzECQm<;Rڴzl|!Gl+aGqcUHwe1 wtցs\ IqoяGZu`l6jB."+˺xlsu1:kЋ*w:0Fx+`lofp# F#8Vǃ-^(Buf8r+bA}?JgEy@ՙ{psxF~x31jlփZF..4[csبib?Omׅ#qŸ֪Z&X>1\D0*N7T@9.(SWk?M}Dsk-7aRJTΰHEE^kxj- YbhUohw kVj>O@8a;ȬGC Vho1C"|*®v"plQ,a?# 8oCǗV;U& bit@8! ۢdsa3oIQP ,п2P [!<$`j("~?jr sӭXL4ܵ?a]8<:ۉc?D9:ht%qi7}--N[u= sr1~&^'@Lf1 -uA(0gι/ ୔RCoG_PT'u~sNq7'jQ82]|eMk8AȢ +c_08Ɗڙ|*h 2uFp'h Qƹ9]4D$ɢU[+ޱ1 .K/dA2%p H=:RbUWIG`K`@$BA@ޱB- E|5\k#nqKG/$%%/]C?b{;xm!ɟ z1RtLixۏryK~p0W֣.Ò[Ibb2z;s|_ؿoמyzu-O(&t7-YD*3ɊPMYByE%#ۍjA^,#.*/~B154KFnV}TfpbNMEZPuZK9p:`} 'ǓEɛqUȃW#bgo_][ddX4duLUgFDy:r$@^ॏə] 3xԝ`Lra}[H.lZ=ii18@ (HtaDguX `6%BhOfAF`!ʆ#18o!@>1ب\`" )N[3&TEeeh[45j}qAkM ]t P.7]@Fc:'AӁqq |THLѻ>Tgb6JL!oȚI|G:],7d$gcə'rI@b&{ɓ,HkҍZHDgOpypcrMw=NB^,`1fIa8V }7Om;9SLq oKoMzyLKw8K mѱ&CL:>vċ3gsKrRӁk :K\IK>PSyI?XL[tD/R: ЙØ:u1&o¯!5ZTĤ)^YcpљLġv)è:<6!٩<6+p%/HEL ^YP htG9[qq8pݐCgpl5DS\NNw $g2e!:%q~_Y+bL ` :8f_YciJ{!){.[{#Ť%L͵pN8]ȟP:]w#'ŁԸ!q1Ran9qw6j?9Eǻ 8\csy)aމ8!5]JK]`ڀ'=n UT|7+bpӐMQ+̀8twнBaYf ' b-tcۼ WQ1utJ+{!" 8FPv81.BCcJJC~?.~xd(.\(~-:;.ҫ MᦈpG&pdSbɅXu΅qb5pw |Y,?҉Mtd%".0N"B!@ڥARSo!|XSRLlpز-3IYS7$L&A`G2=1y[ k@# Be8. BǺQohpw]j֤mREli #\@V7jV(."oVLy4DE@:Yq:41㍻MR'vqM(~ tsXD{ /&Tw~ғ q&?۶|H04GR&!#)eYt%stdO® .!N`:^YJMY#zH۰st2'aW9n \19ƣ>%ƪm9y4W!cnyp7#K8~;x"ݘ i⛞&޳OpeT02ៜLL^ȥYLJLNY@S)V=Iݝ"aA^XT74R_yUAsV D%PVi,6*;cW@ | ~Lt$,: Q.[!V 0QCحebbdu":d\)F<:QtRZ`* &.8 *~麖I:mVt IDAT QL{a5L~ }fJjշifm\F ^Š<L̋xtG 6;[X3K=cX !0a1NkNB:  ;t\gO+lJ vzDB 9B xXJ0U)YAO8QOw;hf㬇U?s1> fc7+ao턫e;X z^d8a!%I%xX즿cE*UQ2mH"3ax*0\tl eMa~n{g -ЋҲ7+"u-":B;{X8Hzy2`RbYԪ/Ƅxo qJ9r(b,W "*qYw=Gʽ=,Dѯ S~ؕ~o~\~sb1qYczAxne@ݱfʟpHAI!zMAA [Ƥ]] p 沆|K6I_%p SQ DA% G@Lڥe?U^Z\Z5 8c]]ppEvcw7 I #\]8ㄸo,]P:M٪MjՎPfp}cT .ߨrGzX9 v({*_yX]~J^v?Re<,|``uS裏Pߢ3 Z%fhT-epAF5Gٽa GXJxv Y4J|8a9rv@pr#=, Zo!X,?ҎII]0=,0iH ߲"= JPXKhLƁ:/&_F~ Ӊg xXKJ@^FdXRI_Uai1'}](%L+yeBuֿ@ BtuK 4L W*[љF(C(RXV ".K8,ԉuKjaj銣A-,ˑҪ ;`;H- "Q Nn+̝B&%Oja[RX<)ͅ"l'VBNF:R‚idKjaRanbbB V= K Z6_fja䍢\+9S-WP:^yWN}vEu˂\32@ ~q2*azt?0+zJ6&t} $LQ 2xWxe 0S A| xCJؽV^T1:6!*adl;Q {J@ \s wfcWn,xR (flppzcja'C7G.kؘVCŀFhS&$ /Bi2.S(܁EfcyTǨCӆ|2YjKy aY܇b%ă۔EQ( vCyMAxJ@1Ô;N/~'GQY`hC1uZ ǭQQܪPn՛l&EZ>M%C.EWK}W"| Wܺqx(3xX,0bUb?]|a x 5\®vXÎ: ^xƬ"F BB(; 5a=ww 쮖O%+B@fx9.:m|!>vm7 ̸ xڊ?lpUK/(06՘FQ`,9:i;>R9GFQ0(0}>RٯJΛ56cgy赱(0?%%~`TWD\ s0ALD.t$v0̡ax94 @hq]" zYE 3NR֠9 ]܊Bj0Gskݷ3C!ӝw`}]"af~X8c  [ќk:羣nЩhd_Mic&Ukǣ V>ko*Y`PL)Mhc 'BQf6Ÿ;( /5auYcyX2/M9 `9.mu@? zX 1pbS?Ò4c(8]a)hAdN;H@SXZ _tr@9,?6ЎhUD#]HK@ Ȁ }$%MےOڅ̘PLF3ܙ63TrPiRrŽu(N7ԝEaW~J*a:0\(d,_,]t5iSv.3 ܙN96ur]M5~XnX6t-#9,GIA`̈́vʝɭjp*U 7;GQ\֝)9\5(תsIzo]EI#04O}ܙkB1u[U6Ԫw;ݩ; AgVrUN40%#Uq*tE8 0OZG3?B13H&*Iuf;bn\ݙCr01`A&u;݋2e ;sN/_wܔ 1eu~@p#|E]l#~NH <,vY*a)0 /ɨ =Rn f6Fp%!0TnT`-? donbn̪.g@Kv3ïN|VvFE1U/B1i*a7*0Ä&#ڰ[pi7ܪN; |Jm ̸ ]:y7(7 bfHf]x:WJ';Y"<,L+yJ-h@U%S@{Q*aDX>嫸-~Cg;VG8_2M6 ,yo$- Y% JFE7؄.oSUpc~BQ +3g*aہ5jI?7I^[%r 3t= ]bD {XБNnODK*8vՑEhL3IqP,ZDZq.j%ZƸ>Ey0xXaAGJ E͖`eA'pgone RTVMn[5~;X,`Ot4ˢ"8RU˒:R ,ԪiL01(*V3 }3Uຬ¼ 7P걪cO9)G0@8\r#6#e'c G#ehw)xl0?)2݃S*a 6%Zh[> 6)EK1Jw){[ŋ0RzQzWJX~ bKvwHFnnU;XHQ1`3Zu2݃SZukU- -xLmHز&Gv) F *aY{ "\,xG;)=3Rgrel{dH _˗)2R6g\ dfyO @{ \[}qM ? (TE2bFGH<`;!mA<Um+bGj nSܜȸX :kMa%V饖)e0< pMi\[Yɦl"PQ`3#HC:ΈM8gv@k"FjnI<7!m8q9Ŗ"»El|mXxs"VwJ זL 5jU6R*@BW"XԪ'"»ElФ$ (M"B\U *¢?C k>}3Er_d0< ,xoCP4Rh@fN1T{El 5ɤ(٥"3Y:1)."(-pd6htR B>Q$5hss \w'}cā0q*Ԙu]qNGtdBfX[CgO }ߎNc a] ߛ `C\~Xn^Cn!!;XcW!!LCw. W 4$`R )3VCoˁHXwRkg#ո6ÅL4'PU63Xǧ=:\g[BƔu;+:t`p+7[P+_0ӥG >~KW3L5pr] ovp00~~'POr":wXm!LeA3._aZF\d8ĉ@ ?Ѻ) ;S趯ҤMܰ\]; YP{.PFPZohau/z5b-l% H#uoXFnD)OsL[]%/tp5ԑEJK5؀xƺ±}5(Q-lXE mrVM.bc"}lnnd+~4%_y 4݈کnՌFm_3FƸM_!t&Fl@v9\6],.˂ ތn@mj _R0m/ mΌRZh挚m_m_jR-.Ƶ QRڦֈHvH#}6֬Kx!ݮ5t@|Ǎ0~d}. 1c ߻ϸZptTr }5"">67Aηߐ1 . -M&S3mDIjju˂.VaO@ ^;讘8LsX*d #elԪ|?Ι8,pƪn 𡵡ر[ߐs~O}1>åbbL{pX"E*~pBd8g}a# HXկF}vv=]mvZpj9,roh ,gBU\Wtn}>U{ꋉ6L{pXB Eb8Vx1HG3LO7Ql} 9 `~O} d=8,DQ!JEQ \AˤׅtlsX;N p<6l/Vsb9Ak vy>ni+Sz*ab@J!7TtKkpdi @`Z#/n܂q(l*aI6P諑`6(âi*rZztߚò5M@-\Sv3<6j1c" =,)aQZ9,[: ~]~$Uaͣ}tm$M붯~V׼B Ÿ  k8Yu?ne;X6:Lw.~ Z"awY6@ z#stΜ?J x=Vk)W31HSa{0L+@ 1c~+XgP_-IFrM۸Ȼj Cl25E1 M LcfME"]&`d{ k* &R :c,_4(F:HW"]& >YF&5u0KeE1#$#Ƃi ^Sj nrkELsNjaIgL!b(#ƂiyG2 @ ,Kkc;2b$\o4.G#~[{g;m \{mHFloՠ+hveIh˟mZ-N/X)G NEKQ16Mn-9}ǎ(HlFꗡSbl&wHFì:DSY}W]jOv }`悔 1nHFÂ?6OsJXl֤~ک mhIL @ ^oǹ2e&r;;E Kg`+t `}oxTۺF_L/9,t2e7X&r ]v2|@^mVNԕ0dji.H_*4EdK æ$)K^W#ꇮ諁rJ}u{ }^g-J}G#t@^"d?D]pW K36mX,}a*e{d˜Dn!vI`0$KHTܕ|fCv*sv E wYy[@ ֮%aKYqSO`@qJ|QŸIRSz>Ò꽥_<^#CG42Z(boZuC>.~%6(rxƶHsvfcf+`3S ?ÒIiˋk0b,{Eh1Rː5Ap.Nt1-f>ס{SGt7\#;넋-氈A @ Adxlaغ!۶3"xjrXQCwH-grX]{"|5c9,_wH-3Kn jTXsymlIS6w&/qW6ԏdIS.k_h-aɒlщW dԏdISjtԏdIS**߄ 㑸?@ +9,J}%fyXiWhhk~<,;iW6Ʉ &;/ò5-7YòvEw}ev%ݡ@wH@ 1 <58, *0'&]MƬ̓qiRL}#}@p쐷 Epnxf};I5oUV]+>_չ#Rwln(iT\xt|:z<.dZodW~ mmym`uc}5M4gkEժkEgd\eKUaOM(綘T'S<۝NȶNvkߪ `r~tyVTV{`OqsXU?ò{Crm\䫳U"4U쌫5; 6e_mw"qYz;ۼT+V] UDce>RP׬>6tQ>NU"u1VH}\6e6 \jYng7Zu3MS<3Urejq]fK&?ē9\F-n$qȱZF]u[rj]@  :=:K Շr*]b7)`}%ړZ ~TtSn*KVOtj觺MܛGTW!t08oUKE?n* 7%@ՎZS]즢rS ^$wؓV pz.zJ @ 221siLoGublO6ď^}uGM𡠾Z?S{ 1Mc|((U1?U{B V&|: SIȭ?@@ Б`nraT XkD,e#fƵ̒jXU=.rƂ:Uv ^yl?J3D6,fTbfI$a^΢,e#fƵ̶Zf}4xM&y>FѮt%:rX2" UtU}5DjH_e$x@0TaQ:Knوqmbf3Gs9ʺ5[WuyXPI*sX2"پH"5K$1Rj1$BeL6ϒ[6bf\YWh8=5]pQ{m89,|_EȆ%ŒJ,#d8,;oݳ䖍f+fVe6hWG"H¡7x!3;MȬUÎm'@ @ ɱ)\HaN{k E@LeOtrzW_`@\<08, zIj|.Be%4QZՖ"P-U?bTtΆ"܎;pX@ _ N[\J}hKG%Z%<,;7Y:o@;òggpo-70!?5Fo-9 jWanD{#Ccvl.^!vGUW}`5{ h grXvn \2mL<2mL7fw~p\a9{C>s^g\p]ѽ6&_n Ma>>òmڸBWyce6{ QMco}:r3=| >an$9OM6Tic1s9{CiP1o@}:[6/V~oGrXv'g2mLm-ե1K|"7握1Uc]t#=Q_^_@ Am7'8,eTiWDURe+\Ky# òVmڕ?QUl|*PU a@@  |Le2hVYHq(tA8,@dUe*pr\a|)+aɈ(v t|KQQaɈ(q\;ݡ@ @ xo5Ƙ"RX2HL+#$0%?SZ}M>$r}n8VZr &6׃8,upX#ezu2_ L鲿@-2F $e^Z%0 BsÔvAqxHat|B]yCh.jÐSGT?䰬3t<0#a/Q(ai%)G&;|&7$!@0MٖgdjʅWR,hc <ećOŒ/iHD+:O1LO\g*6Y6Pۤ3-(Nc rF NH &HI;V=`$\!Ĺaʍr Hat|kY om;lƤIEk,|*HYT| @ \t\P gB͑1GJ2H{$O>.I>r ΁9,` }Tmܜ 1&G ' &G]#~tG.J>B[3ni;RsX( aIòy̘|9R)֙N>|$,H(= |2hK>ƒr+|lrpkr@L̎ͼN>RkP­d>{>.ƹ)uH)NeƢ|ƟB @ |ߪ"fE^,Zo< ;ߪL#X{͈:S @@ 5s oǹ&=DVNS4RSՀJ20GUi 2Th8 =[$vi-6Ob[Ԃ6vu_t ,^1 fYH6Jd,8nNY"zXHҾ_.29JqU8RdgBWREP ]^u_-kA8h=]h-[wBk4F^)mA{ ͮ);: *u'KP pڶͮ+bDe2nȳ*mii6P{$vy-M-lg{"tۛ_l1Md%BȾ(^CF8}Ug}Pj;hb !])Q #Ϫb!'o̼LԂ.E] UM-\g=Z-BڼO.m^k0$^ʥA9/Q"KcV8RNŽƢhR pZXQJyV-)*E&va-ol#8hg=~-[Bցd;Su4q;\-jJPQ@ eڪu)ל.֩I0m-W 25sDYvTT;3CmܰZ8_6J;jwp$VsX0:igARe׷jL D.3.1 Data Structures and Kernel Parameters


D.3.1 Data Structures and Kernel Parameters

A full understanding of the Hierarchical RCU data structures is critically important to understanding the algorithms. To this end, Section [*] describes the data structures used to track each CPU's dyntick-idle state, Section [*] describes the fields in the per-node data structure making up the rcu_node hierarchy, Section [*] describes per-CPU rcu_data structure, Section [*] describes the field in the global rcu_state structure, and Section [*] describes the kernel parameters that control Hierarchical RCU's operation.

Figure [*] on Page [*] and Figure [*] on Page [*] can be very helpful in keeping one's place through the following detailed data-structure descriptions.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img236.png0000644000175000017500000004246311672746035015324 0ustar paulmckpaulmckPNG  IHDR]Q{fPLTEb``\ZZURSTRRMJKEBC# b`ahffywwvstommmkkXUVVST<9:856C@@A>>744wuv.*+37BtRNS@f IDATx}³Sg;0#me@P<$1/ACa%@hq0Jr׮qO^nWqhaR cƣHkjf0P? ]v{eݥ+7}jfg9oצZtpcmѢnĭp=XEpD/ ogw}mK+2KYõ¿qݬfmbMǝpd+dU> ?u%u\)9ȥ˭QC`sӍշGq/x 1x~3+nU׺dn\~y[ݸp"a$UFvۧMJki*aޱ-dA*y߲HkI(Ag6vwm\uHzR8UꦃpYá\|I)*=XX7@ӢH@Tv0T]v(;na=ԅC8w8UPXj/uI[te;WPGŕ7GCn&ӔM) B41j0P/ǹxRy@'ݥ$MUMm8:&.xݾy03ƈXh襮A7YCR vOm]\5v"]Ft F4%28?UʟρI֖=Fm]*BKEi y?ᯜTTn]55~4}?.]|+{cE+ Q6 ~ gF:~-Ȭ1ukq`ky_D˼dE&B{24 no#{)IZуe񠕘ǡ^ )}tZVc!Bl YhPQâkx+ O8ycP uHrxZ L҇ h47IF{'B+|9>/h [zJh&ߵUp,/tXس{,Kj;ϐ"|x[VHn< eljpZiMIޯڔ”*7Zӣp7QF+Uiݔ!0/f /G#g)fcۋ"O mWn +`˳uSYҴ6fY5ZD[NJ *.`}tv]!47?Uf2lidfcj7-/E2PUO8 T_<6A)6-UMptʻwT7{L7;8&"x YQ]k̛#G- <~s/=”JBb #*7AXpwmM9oQ2'3A9&GE%iMt[>g&>$EvuΌQ_𜕷'Vrӥs3UL%(x bD/;v]wy()A!*3@6=CΈޏ3E1#J][^* crTn {Hlgq|P/jUvȈUi8Mrus8b8d27eKo*#ccT-Hؔzs ps)@!!M &nIڊHvh7zȺ}˦k6m߅9'zd1z`qƀB@2,m4K5Io5kv+Vx,e㯌 S.֧T 8j2";Lw{ xHr~.TtT/KGhcET8w?/>t23`a3d`A@^X9zl{f4i mR$O#InJV%U~l6T'pSJ߸Z }#׷p37=(Er$%oaG}sifZ`z sMFl"G}~ KIcnaf2b'c 菝CBUSxL̐c*7>=7]NR$Uls?EAq(; `lHT5^2c>D R$*Y?S> 6HF,iAȦ$z Op~9@F7 ܃-:#8 `p̍L馍B!4wL5_ ٤(t_#R"m xe udEˊ pǖBWPiɝN@דS,<  ǂ\w`geoK6uQ˩(NFQpmW9Vn SS/$B=ϡk:hާv^Q7~CӈoB*yPY a;v,[Nc.k7e/{پɼ9@ypODww.#=#;<W䴸~@ľ38a͊ d W `/YɅ#D̡ pX%Rc_rP?/r}yjK i. $"0^oVS[+P }vuKa}Cul쩿S^I?8n˰z 9 ^oJ7CX t:T"YxD[Pw<ȕu`:m)#(DZUlȳ Z#"Jݕr$|QM\uL5$>CA'iE}R+UZ.]Ae IslnY_L5ߜwi@ݒZ`U9AB]Gʶe2c֊ 꽣aFhN>ޓX%QƴM\Qfkfähg3C1ICX6ClĬ_= 6/>,f54SC &|Yqkg3%foeUK- U_8zMڋdw/7ڏ[)FH ۩Qw-~<\1*ljL1R7Q&XI12?A/$dŃ$_oGjRᵊ<_+Zލ67Jz6#{)ƪ 7dh 2?Tl]ͧwKǞU??>CX&dAHn'ȫ lMļDb2yA"6=sd)`朧^YMڶ1^>"à"Z&$Y-i@S.3&ֶ0s1JC Z<~r1>Z Mf)+X1 6O O],/dFM߃O{a=^`K>U7s +8TCC8x瞤hKw!f&3]5վ@H%_fDiz8nkY:Q{Bo/<m lOn`qJIC/~Tbi`ro'Cuɐ$&yHq~d$hQ32DTQy}/j2y%)B2qC߻2@w#r2P7 7폙nb@Gz,bB+nR߾˧VgPI5\Ւ. =Iq]jVE Q *ʧ \:M׋5ȴ݇OI.Q"* J=W^%^щ9P(^UH2t [5gQ-.Q.Q4(^8 _Avg447c~*5;Hy;r1gqSRP]9~Z 5:'?P-UkFYfURNj|fEv[np87SzſQp1@;);@<;Ռϳ[@퉊%]`ڮ]fkSNjk;8{Wbėd&c}|p~.ꄮ<7y2=obGǷ"b(g෰B#PF-ZxЖ%dOxGVKoZ-b6К'?OoZR^K>jѽ7Y&7|D(P` XHO ! GB?uQBfُU41ւqݤTE'I*D"!B)X"nEffٯ} ̣8H27 '5NH̚*TPƂ4 iF t%y42,倀g /Ei rVu^'񻾒(F|;AĂ"Lݜ.I蒫JI.r+x09Zĭ"9ƺ? r`8'U5MZSKq r:E xtI81MtXԞ+la2DS=b3mnĂrN'|$pح4]rœ?4޸iA̺$ADr;z*ֺ[=]*9 IDAT,AKSlEER\LU)1h.5rsL>*}IG wg&0zXtx?9/I9-[|C0Z`=[6%`>f):ف,'7!,C0ZJ:X-S7Wq+j]JrY8rRo:|ƵWK6?#iIW撛c&X,8Qr3%q8L&!Lt RR(we*?6: T|>\fcwQ ݣH."9.&&Tneӑ&7O*1Pχ>uQ (9Zǧt$DB+jLkʔ|tkuy; Q*` NQ[ΈŅ CEp9/H4x.3?:`LP<OP~O ɸ;t#ZV3iUef~/ţ 'a䣸.\&f ڝ3px.Qm@IWSF'௚:utISՉٸm-D]I_ov $<,;E5 =ֲSsv(ݣtk!~w qcWl^cofݍxjL@񻳘JP/EK򝩏(>8] w<:Լ/[syp+C̘uMTŸ9nAsPx3Pa'ED-Ѹi(Zk'sHX-N5&n[eIt=j>7I'n [A**н7D`@?9SiS~h[CA*8ͲB2dV567j$dJ;]6uk1ѦUN\Di.!c]X$>ܥtBc]iBJh wU(݁exָ;,FX][(܅<@pbχ8ΟSiPG xך5f,i^z[;[Uss{v w΍26>-H#^zA\p"q>0].?,Cid?"4"80!SOmY^V!hL +!g&]3A3 ms &(^ w)?8/J!sc; _d;r. -U,Ǖ-߱ *@nz~|..GP "nOe@yP,b^`ݞ\@ڳ2sp?>P,b{Tp _tԥIOYbNhsPUl]@gtgx|t.>zuɻOWreWG;a;eVoq0WK "ΫS."\}0"bVd}SG?_wA4":nm\ud'aʕZw1DQ "G"xQZ T[""UZGJq}V~)ȑ'N8pd/<wj 0=wy~fv5ye &}^t2|4&aVڶP@e 3D+@~z3H=Mj[ژK^_{… E}'v$̖Zι[1,[:#vǺnɉ啺8HB a>V:9Tc> I4Ԅ5{lz R4N_mYDUஉymNI,9dFW6?U4h,Cn\@P{ߝ"H466ݩKsRBB|]o)%jkwA}Qօ gGak8 MThfGEÎ-h.w_8#LzZv2}2T64i;YZ c 4-DZ֛oBvԜq)6 .[i}敛̨BJ֮M5rKXXcř̜3ҵҤ!+N|6>m9xn^ /R>ptGcV l6\yբPy1/+ݛM+G ].=Z H5E#݃QK9w׽.\;M3ǢX).V%Ol-q'NxWT;pǟ 3pt\dNS}0ڷBNĹu`n>^ې'?$O8rʰ\97)uΚTawJ)p燚Ps"y{ {bS{6ϊ^+u¹<|-.e-esN14t}>g\x̉p86N``:itpKv ?& gsD> 7>?eMwAߖ:vEpж*~Њs-yI^p…wAbgXunYUڮe\vU&@ݥV* Yjk6)Z-ʜg1O3Ҳu'.e^6W\p: ϛ[fX5H) q:Gf۔- r2-ʻ2CF(E q_ӠAldW.\8bf9Q`hAMŠZcd!k-M(YCGDEG'\6ksjlG@q {T檨F1iRx? e8{^elS~gwIs@Zho,dw3+7vF72p/5'r&^ j2ئ4מu'ϿK?Xs\>m?yh+\ڴL;]Bw0]VdϬGa)}4gן ȳA0A}oZ(-6NǙ lƕhqq/76fqCgʸ[(7(t { e@)SdqAgb0sK:¤/@K>чܜ>I>/PqyR"oUx=JTyu+PIwޥQ݅Wpi`ӏ"t,#:?D' ^ ɮjD8 |ZJ49藹OQBӒz-~#N{unUz :yxFG/IіGP!N EDFY'!?AY8Nҩl9S۠vxx6s Eߝ,̔=C0i<.L`J1Rޔ0RapA/Z`k2d,n>Tm@+nR0ږlܰȎ+$+DKÒ E \8 lnm5dFMHGw%hU aK=J/ƅ 'DtSQ[IF}nOn È.ٕ ;~|#ȊXO5N;2N`nĭKtȋoL`:o ]Y}5 ^ M'6U/b9Uȯ Sf`RtrsϽ2d!1i {2bgdYh>JZ ׽҂1{$3L;OMp\A9="-xq i#vKf;' d7ӇAA/-tVmQfv$?3rŗK q<./'KBϏ[Ͻ%ǥ$f8_a{0"Zmq 70h˛,qx=,VT#wual$$t]lI.8nJ' EBh#4e/ ]tV)+ڦWhRQJEΖ@/>W #՚);V[ 5r]՚s᛹7& mfVV4+a84 .uzd;Mp5Zw9"w3Vîv*dW2(ϯ/3&nv)l0"5#wq:$1hU! &)5\F4qíh]P/*@#w3.Zqj+-[UAƽF7MSzEe;Mp9ZLQxM.A̬1[E2Ni̍Dvt¹@-KXlI+7ol._wcDd`>) 7 @DBRsxRR1bh]9[wcDd`E(\7荨_|]쨠PtRRqݘKoz@ӓNf}\yu1d=Sov>Un1vw<|~*mBnNQBwrL.:azv/ kep.\sNcn͓,ޡ&uiͷwz˺uv{}V-/1q6/S.9zpCGn&sʌa*yPL9fwB+b~ (rw;iWH~+S/PB.C}]12-{~6&\#L ԻV7%D* 񧅓a1LG|;|;buVVP|褹,IoI+rd֩r]X GpTwBˬlx4 3}[Q2 :tN{W;t2ðaq䈧h 8#i>;NvI(UtLLjPm$r8Zw1%!i!3}[$K̃NSv ȑ2A}l\_G)'y{|>s21O "Ϗ2 ޻|Dd1gICd[ϖi'ӮRNҝsquSnY/VM>)= I&!^{1bW" mL8ݨrq\6׋ޞ(_w?)|_Yq|0GF A/!ש @tpg'e7HM׋ښ7- S0R/G6tK\;HG!鼼t]`.<-M} /a|ow]WZk4x4ŽIR+t4% a\0E ǽ~JS7e7؊Ϳc/Q0C`_ a _ \hr1Վ-CH0}:+/ͱEތ&b=. ,3DHH8.pB{sh'Atppg 3^.w65ll>V̩wLl[@LKH8N3yr7dJT–}>L;G7ˌMҶUK.ci*=S Ӆ}yd_|Ѕ wh]҄Xs<&| ѽ,bh'kep…8k-ˀ}- .l$d69?|f7M /A / hso璀7qtxypZܙNZܟtЕt6my;V*|> zDz}vd-%=$fކ,$ LP.'ߑKB;I@,L&b, wPG~@X&E[qnZv&Z^sh :~sn. ,#%{җd*ĦwgD]zHP^V 5 [1@F*ߝcR~,\qX9lxdX4x F}q88#ovlje $``YxP36tv# S2q.ΈQ 谂Ay\ 3Bk+8'Jd4}>tD2+iq IENDB`perfbook_html/node271.html0000644000175000017500000001073111672746162015646 0ustar paulmckpaulmck B.2 Thread Creation, Destruction, and Control


B.2 Thread Creation, Destruction, and Control

This API focuses on ``threads'', which are a locus of control.B.1Each such thread has an identifier of type thread_id_t, and no two threads running at a given time will have the same identifier. Threads share everything except for per-thread local state,B.2which includes program counter and stack.

The thread API is shown in Figure [*], and members are described in the following sections.

Figure: Thread API
\begin{figure*}{ \scriptsize
\begin{verbatim}int smp_thread_id(void)
thread_id...
...read(thread_id_t tid)
void wait_all_threads(void)\end{verbatim}
}\end{figure*}



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node226.html0000644000175000017500000001336711672746162015656 0ustar paulmckpaulmck 14.2.10.6 SMP Barrier Pairing


14.2.10.6 SMP Barrier Pairing

When dealing with CPU-CPU interactions, certain types of memory barrier should always be paired. A lack of appropriate pairing is almost certainly an error.

A write barrier should always be paired with a data dependency barrier or read barrier, though a general barrier would also be viable. Similarly a read barrier or a data dependency barrier should always be paired with at least an write barrier, though, again, a general barrier is viable:



CPU 1 CPU 2
a = 1;
<write barrier>
b = 2;
x = b;
<read barrier>
y = a;


Or:



CPU 1 CPU 2
a = 1;
<write barrier>
b = &a;
x = b;
<data dependency barrier>
y = *x;


One way or another, the read barrier must always be present, even though it might be of a weaker type.14.8

Note that the stores before the write barrier would normally be expected to match the loads after the read barrier or data dependency barrier, and vice versa:

\includegraphics{advsync/MemoryBarrierPairing}

Paul E. McKenney 2011-12-16
perfbook_html/node162.html0000644000175000017500000002614211672746162015650 0ustar paulmckpaulmck 10.3.4.8 Nestable RCU Based on Free-Running Counter


10.3.4.8 Nestable RCU Based on Free-Running Counter

Figure: Data for Nestable RCU Using a Free-Running Counter
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...tr = 0;
6 DEFINE_PER_THREAD(long, rcu_reader_gp);\end{verbatim}
}\end{figure}

Figure: Nestable RCU Using a Free-Running Counter
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
... 38 spin_unlock(&rcu_gp_lock);
39 smp_mb();
40 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_nest.h and rcu_nest.c) show an RCU implementation based on a single global free-running counter, but that permits nesting of RCU read-side critical sections. This nestability is accomplished by reserving the low-order bits of the global rcu_gp_ctr to count nesting, using the definitions shown in Figure [*]. This is a generalization of the scheme in Section [*], which can be thought of as having a single low-order bit reserved for counting nesting depth. Two C-preprocessor macros are used to arrange this, RCU_GP_CTR_NEST_MASK and RCU_GP_CTR_BOTTOM_BIT. These are related: RCU_GP_CTR_NEST_MASK=RCU_GP_CTR_BOTTOM_BIT-1. The RCU_GP_CTR_BOTTOM_BIT macro contains a single bit that is positioned just above the bits reserved for counting nesting, and the RCU_GP_CTR_NEST_MASK has all one bits covering the region of rcu_gp_ctr used to count nesting. Obviously, these two C-preprocessor macros must reserve enough of the low-order bits of the counter to permit the maximum required nesting of RCU read-side critical sections, and this implementation reserves seven bits, for a maximum RCU read-side critical-section nesting depth of 127, which should be well in excess of that needed by most applications.

The resulting rcu_read_lock() implementation is still reasonably straightforward. Line 6 places a pointer to this thread's instance of rcu_reader_gp into the local variable rrgp, minimizing the number of expensive calls to the pthreads thread-local-state API. Line 7 records the current value of rcu_reader_gp into another local variable tmp, and line 8 checks to see if the low-order bits are zero, which would indicate that this is the outermost rcu_read_lock(). If so, line 9 places the global rcu_gp_ctr into tmp because the current value previously fetched by line 7 is likely to be obsolete. In either case, line 10 increments the nesting depth, which you will recall is stored in the seven low-order bits of the counter. Line 11 stores the updated counter back into this thread's instance of rcu_reader_gp, and, finally, line 12 executes a memory barrier to prevent the RCU read-side critical section from bleeding out into the code preceding the call to rcu_read_lock().

In other words, this implementation of rcu_read_lock() picks up a copy of the global rcu_gp_ctr unless the current invocation of rcu_read_lock() is nested within an RCU read-side critical section, in which case it instead fetches the contents of the current thread's instance of rcu_reader_gp. Either way, it increments whatever value it fetched in order to record an additional nesting level, and stores the result in the current thread's instance of rcu_reader_gp.

Interestingly enough, the implementation of rcu_read_unlock() is identical to that shown in Section [*]. Line 19 executes a memory barrier in order to prevent the RCU read-side critical section from bleeding out into code following the call to rcu_read_unlock(), and line 20 decrements this thread's instance of rcu_reader_gp, which has the effect of decrementing the nesting count contained in rcu_reader_gp's low-order bits. Debugging versions of this primitive would check (before decrementing!) that these low-order bits were non-zero.

The implementation of synchronize_rcu() is quite similar to that shown in Section [*]. There are two differences. The first is that line 29 adds RCU_GP_CTR_BOTTOM_BIT to the global rcu_gp_ctr instead of adding the constant ``2'', and the second is that the comparison on line 32 has been abstracted out to a separate function, where it checks the bit indicated by RCU_GP_CTR_BOTTOM_BIT instead of unconditionally checking the low-order bit.

This approach achieves read-side performance almost equal to that shown in Section [*], incurring roughly 65 nanoseconds of overhead regardless of the number of Power5 CPUs. Updates again incur more overhead, ranging from about 600 nanoseconds on a single Power5 CPU to more than 100 microseconds on 64 such CPUs.

Quick Quiz 10.52: Why not simply maintain a separate per-thread nesting-level variable, as was done in previous section, rather than having all this complicated bit manipulation? End Quick Quiz

This implementation suffers from the same shortcomings as does that of Section [*], except that nesting of RCU read-side critical sections is now permitted. In addition, on 32-bit systems, this approach shortens the time required to overflow the global rcu_gp_ctr variable. The following section shows one way to greatly increase the time required for overflow to occur, while greatly reducing read-side overhead.

Quick Quiz 10.53: Given the algorithm shown in Figure [*], how could you double the time required to overflow the global rcu_gp_ctr? End Quick Quiz

Quick Quiz 10.54: Again, given the algorithm shown in Figure [*], is counter overflow fatal? Why or why not? If it is fatal, what can be done to fix it? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node451.html0000644000175000017500000001370611672746163015654 0ustar paulmckpaulmck E.7.3 Lessons (Re)Learned


E.7.3 Lessons (Re)Learned

Figure: Memory-Barrier Fix Patch
\begin{figure}{ \scriptsize
\begin{verbatim}static inline void rcu_enter_nohz...
...t_cpu_var(dynticks_progress_counter)++;
+ mb();
}\end{verbatim}
}\end{figure}

Figure: Variable-Name-Typo Fix Patch
\begin{figure}{ \scriptsize
\begin{verbatim}- if ((curr - snap) > 2 \vert\vert...
...f ((curr - snap) > 2 \vert\vert (curr & 0x1) == 0)\end{verbatim}
}\end{figure}

This effort provided some lessons (re)learned:

  1. Promela and spin can verify interrupt/NMI-handler interactions.
  2. Documenting code can help locate bugs. In this case, the documentation effort located a misplaced memory barrier in rcu_enter_nohz() and rcu_exit_nohz(), as shown by the patch in Figure [*].
  3. Validate your code early, often, and up to the point of destruction. This effort located one subtle bug in rcu_try_flip_waitack_needed() that would have been quite difficult to test or debug, as shown by the patch in Figure [*].
  4. Always verify your verification code. The usual way to do this is to insert a deliberate bug and verify that the verification code catches it. Of course, if the verification code fails to catch this bug, you may also need to verify the bug itself, and so on, recursing infinitely. However, if you find yourself in this position, getting a good night's sleep can be an extremely effective debugging technique.
  5. Use of atomic instructions can simplify verification. Unfortunately, use of the cmpxchg atomic instruction would also slow down the critical irq fastpath, so they are not appropriate in this case.
  6. The need for complex formal verification often indicates a need to re-think your design. In fact the design verified in this section turns out to have a much simpler solution, which is presented in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/node225.html0000644000175000017500000000606211672746162015647 0ustar paulmckpaulmck 14.2.10.5 Control Dependencies


14.2.10.5 Control Dependencies

A control dependency requires a full read memory barrier, not simply a data dependency barrier to make it work correctly. Consider the following bit of code:



  1 q = &a;
  2 if (p)
  3   q = &b;
  4 <data dependency barrier>
  5 x = *q;


This will not have the desired effect because there is no actual data dependency, but rather a control dependency that the CPU may short-circuit by attempting to predict the outcome in advance. In such a case what's actually required is:



  1 q = &a;
  2 if (p)
  3   q = &b;
  4 <read barrier>
  5 x = *q;




Paul E. McKenney 2011-12-16
perfbook_html/node129.html0000644000175000017500000001567311672746162015662 0ustar paulmckpaulmck 10.3.1.3.1 Example 1: Maintaining Multiple Versions During Deletion


10.3.1.3.1 Example 1: Maintaining Multiple Versions During Deletion

To start the ``deletion'' example, we will modify lines 11-21 in Figure [*] to read as follows:



  1 p = search(head, key);
  2 if (p != NULL) {
  3   list_del_rcu(&p->list);
  4   synchronize_rcu();
  5   kfree(p);
  6 }


Figure: RCU Deletion From Linked List
\resizebox{3in}{!}{\includegraphics{defer/RCUDeletion}}

This code will update the list as shown in Figure [*]. The triples in each element represent the values of fields a, b, and c, respectively. The red-shaded elements indicate that RCU readers might be holding references to them. Please note that we have omitted the backwards pointers and the link from the tail of the list to the head for clarity.

After the list_del_rcu() on line 3 has completed, the 5,6,7 element has been removed from the list, as shown in the second row of Figure [*]. Since readers do not synchronize directly with updaters, readers might be concurrently scanning this list. These concurrent readers might or might not see the newly removed element, depending on timing. However, readers that were delayed (e.g., due to interrupts, ECC memory errors, or, in CONFIG_PREEMPT_RT kernels, preemption) just after fetching a pointer to the newly removed element might see the old version of the list for quite some time after the removal. Therefore, we now have two versions of the list, one with element 5,6,7 and one without. The 5,6,7 element is shaded yellow, indicating that old readers might still be referencing it, but that new readers cannot obtain a reference to it.

Please note that readers are not permitted to maintain references to element 5,6,7 after exiting from their RCU read-side critical sections. Therefore, once the synchronize_rcu() on line 4 completes, so that all pre-existing readers are guaranteed to have completed, there can be no more readers referencing this element, as indicated by its green shading on the third row of Figure [*]. We are thus back to a single version of the list.

At this point, the 5,6,7 element may safely be freed, as shown on the final row of Figure [*]. At this point, we have completed the deletion of element 5,6,7. The following section covers replacement.

Paul E. McKenney 2011-12-16
perfbook_html/node185.html0000644000175000017500000000436011672746162015653 0ustar paulmckpaulmck 13.5 Bits and Bytes


13.5 Bits and Bytes

Bit fields, endianness, packing.



Paul E. McKenney 2011-12-16
perfbook_html/node326.html0000644000175000017500000005251411672746163015655 0ustar paulmckpaulmck D. Read-Copy Update Implementations


D. Read-Copy Update Implementations

This appendix describes several fully functional production-quality RCU implementations. Understanding of these implementations requires a thorough understanding of the material in Chapters [*] and [*], as well as a reasonably good understanding of the Linux kernel, the latter of which may be found in several textbooks and websites [BC05,CRKH05,Cor08,Lov05].

If you are new to RCU implementations, you should start with the simpler ``toy'' RCU implementations that may be found in Section [*].

Section [*] presents ``Sleepable RCU'', or SRCU, which allows SRCU readers to sleep arbitrarily. This is a simple implementation, as production-quality RCU implementations go, and a good place to start learning about such implementations.

Section [*] gives an overview of a highly scalable implementation of Classic RCU, designed for SMP systems sporting thousands of CPUs. Section [*] takes the reader on a code walkthrough of this same implementation (as of late 2008).

Finally, Section [*] provides a detailed view of the preemptible RCU implementation used in real-time systems.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node183.html0000644000175000017500000000443411672746162015653 0ustar paulmckpaulmck 13.3 Design Tradeoffs


13.3 Design Tradeoffs

Trade-offs between memory consumption, performance, complexity.



Paul E. McKenney 2011-12-16
perfbook_html/node418.html0000644000175000017500000001370311672746163015654 0ustar paulmckpaulmck D.4.2.4.3 Memory-Barrier Considerations


D.4.2.4.3 Memory-Barrier Considerations

Figure: Preemptible RCU with Read-Side Memory Barriers
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBwaste}}

Note that these two primitives contains no memory barriers, so there is nothing to stop the CPU from executing the critical section before executing the rcu_read_lock() or after executing the rcu_read_unlock(). The purpose of the rcu_try_flip_waitmb_state is to account for this possible reordering, but only at the beginning or end of a grace period. To see why this approach is helpful, consider Figure [*], which shows the wastefulness of the conventional approach of placing a memory barrier at the beginning and end of each RCU read-side critical section [MSMB06].

Figure: Preemptible RCU with Grace-Period Memory Barriers
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBnowaste}}

The "MB"s represent memory barriers, and only the emboldened barriers are needed, namely the first and last on a given CPU for each grace period. This preemptible RCU implementation therefore associates the memory barriers with the grace period, as shown in Figure [*].

Given that the Linux kernel can execute literally millions of RCU read-side critical sections per grace period, this latter approach can result in substantial read-side savings, due to the fact that it amortizes the cost of the memory barrier over all the read-side critical sections in a grace period.

Paul E. McKenney 2011-12-16
perfbook_html/node258.html0000644000175000017500000001333711672746162015660 0ustar paulmckpaulmck 17.1.9 Persistence


17.1.9 Persistence

There are many different types of locking primitives. One interesting distinction is persistence, in other words, whether the lock can exist independently of the address space of the process using the lock.

Non-persistent locks include pthread_mutex_lock(), pthread_rwlock_rdlock(), and most kernel-level locking primitives. If the memory locations instantiating a non-persistent lock's data structures disappear, so does the lock. For typical use of pthread_mutex_lock(), this means that when the process exits, all of its locks vanish. This property can be exploited in order to trivialize lock cleanup at program shutdown time, but makes it more difficult for unrelated applications to share locks, as such sharing requires the applications to share memory.

Persistent locks help avoid the need to share memory among unrelated applications. Persistent locking APIs include the flock family, lockf(), System V semaphores, or the O_CREAT flag to open(). These persistent APIs can be used to protect large-scale operations spanning runs of multiple applications, and, in the case of O_CREAT even surviving operating-system reboot. If need be, locks can span multiple computer systems via distributed lock managers.

Persistent locks can be used by any application, including applications written using multiple languages and software environments. In fact, a persistent lock might well be acquired by an application written in C and released by an application written in Python.

How could a similar persistent functionality be provided for TM?

  1. Restrict persistent transactions to special-purpose environments designed to support them, for example, SQL. This clearly works, given the decades-long history of database systems, but does not provide the same degree of flexibility provided by persistent locks.
  2. Use snapshot facilities provided by some storage devices and/or filesystems. Unfortunately, this does not handle network communication, nor does it handle I/O to devices that do not provide snapshot capabilities, for example, memory sticks.
  3. Build a time machine.

Of course, the fact that it is called transactional memory should give us pause, as the name itself conflicts with the concept of a persistent transaction. It is nevertheless worthwhile to consider this possibility as an important test case probing the inherent limitations of transactional memory.

Paul E. McKenney 2011-12-16
perfbook_html/node399.html0000644000175000017500000002364211672746163015667 0ustar paulmckpaulmck D.3.9 CPU-Stall Detection


D.3.9 CPU-Stall Detection

RCU checks for stalled CPUs when the CONFIG_RCU_CPU_STALL_DETECTOR kernel parameter is selected. ``Stalled CPUs'' are those spinning in the kernel with preemption disabled, which degrades response time. These checks are implemented via the record_gp_stall_check_time(), check_cpu_stall(), print_cpu_stall(), and print_other_cpu_stall() functions, each of which is described below. All of these functions are no-ops when the CONFIG_RCU_CPU_STALL_DETECTOR kernel parameter is not selected.

Figure: record_gp_stall_check_time() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 record_gp_stall_...
... =
6 jiffies + RCU_SECONDS_TILL_STALL_CHECK;
7 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for record_gp_stall_check_time(). Line 4 records the current time (of the start of the grace period) in jiffies, and lines 5-6 record the time at which CPU stalls should be checked for, should the grace period run on that long.

Figure: check_cpu_stall() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 check_cpu_stall(...
...LAY) {
14 print_other_cpu_stall(rsp);
15 }
16 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for check_cpu_stall, which checks to see if the grace period has stretched on too long, invoking either print_cpu_stall() or print_other_cpu_stall() in order to print a CPU-stall warning message if so.

Line 8 computes the number of jiffies since the time at which stall warnings should be printed, which will be negative if it is not yet time to print warnings. Line 9 obtains a pointer to the leaf rcu_node structure corresponding to the current CPU, and line 10 checks to see if the current CPU has not yet passed through a quiescent state and if the grace period has extended too long (in other words, if the current CPU is stalled), with line 11 invoking print_cpu_stall() if so.

Otherwise, lines 12-13 check to see if the grace period is still in effect and if it has extended a couple of jiffies past the CPU-stall warning duration, with line 14 invoking print_other_cpu_stall() if so.

Quick Quiz D.53: Why wait the extra couple jiffies on lines 12-13 in Figure [*]? End Quick Quiz

Figure: print_cpu_stall() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void print_cpu_stall(str...
...(&rnp->lock, flags);
17 set_need_resched();
18 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for print_cpu_stall().

Line 6-11 prints a console message and dumps the current CPU's stack, while lines 12-17 compute the time to the next CPU stall warning, should the grace period stretch on that much additional time.

Quick Quiz D.54: What prevents the grace period from ending before the stall warning is printed in Figure [*]? End Quick Quiz

Figure: print_other_cpu_stall() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void print_other_cpu_sta...
..._start));
34 force_quiescent_state(rsp, 0);
35 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for print_other_cpu_stall(), which prints out stall warnings for CPUs other than the currently running CPU.

Lines 10 and 11 pick up references to the first leaf rcu_node structure and one past the last leaf rcu_node structure, respectively. Line 12 acquires the root rcu_node structure's lock, and also disables interrupts. Line 13 calculates the how long ago the CPU-stall warning time occurred (which will be negative if it has not yet occurred), and lines 14 and 15 check to see if the CPU-stall warning time has passed and if the grace period has not yet ended, with line 16 releasing the lock (and re-enabling interrupts) and line 17 returning if so.

Quick Quiz D.55: Why does print_other_cpu_stall() in Figure [*] need to check for the grace period ending when print_cpu_stall() did not? End Quick Quiz

Otherwise, lines 19 and 20 compute the next time that CPU stall warnings should be printed (if the grace period extends that long) and line 21 releases the lock and re-enables interrupts. Lines 23-33 print a list of the stalled CPUs, and, finally, line 34 invokes force_quiescent_state() in order to nudge the offending CPUs into passing through a quiescent state.

Paul E. McKenney 2011-12-16
perfbook_html/node262.html0000644000175000017500000001732711672746162015656 0ustar paulmckpaulmck 17.1.13 RCU


17.1.13 RCU

Because read-copy update (RCU) finds its main use in the Linux kernel, one might be forgiven for assuming that there had been no academic work on combining RCU and TM. However, the TxLinux group from the University of Texas at Austin had no choice [RHP+07]. The fact that they applied TM to the Linux 2.6 kernel, which uses RCU, forced them to integrate TM and RCU, with TM taking the place of locking for RCU updates. Unfortunately, although the paper does state that the RCU implementation's locks (e.g., rcu_ctrlblk.lock) were converted to transactions, it is silent about what happened to locks used in RCU-based updates (e.g., dcache_lock).

It is important to note that RCU permits readers and updaters to run concurrently, further permitting RCU readers to access data that is in the act of being updated. Of course, this property of RCU, whatever its performance, scalability, and real-time-response benefits might be, flies in the face of the underlying atomicity properties of TM.

So how should TM-based updates interact with concurrent RCU readers? Some possibilities are as follows:

  1. RCU readers abort concurrent conflicting TM updates. This is in fact the approach taken by the TxLinux project. This approach does preserve RCU semantics, and also preserves RCU's read-side performance, scalability, and real-time-response properties, but it does have the unfortunate side-effect of unnecessarily aborting conflicting updates. In the worst case, a long sequence of RCU readers could potentially starve all updaters, which could in theory result in system hangs. In addition, not all TM implementations offer the strong atomicity required to implement this approach.
  2. RCU readers that run concurrently with conflicting TM updates get old (pre-transaction) values from any conflicting RCU loads. This preserves RCU semantics and performance, and also prevents RCU-update starvation. However, not all TM implementations can provide timely access to old values of variables that have been tentatively updated by an in-flight transaction. In particular, log-based TM implementations that maintain old values in the log (thus making for excellent TM commit performance) are not likely to be happy with this approach. Perhaps the rcu_dereference() primitive can be leveraged to permit RCU to access the old values within a greater range of TM implementations, though performance might still be an issue.
  3. If an RCU reader executes an access that conflicts with an in-flight transaction, then that RCU access is delayed until the conflicting transaction either commits or aborts. This approach preserves RCU semantics, but not RCU's performance or real-time response, particularly in presence of long-running transactions. In addition, not all TM implementations are capable of delaying conflicting accesses. That said, this approach seems eminently reasonable for hardware TM implementations that support only small transactions.
  4. RCU readers are converted to transactions. This approach pretty much guarantees that RCU is compatible with any TM implementation, but it also imposes TM's rollbacks on RCU read-side critical sections, destroying RCU's real-time response guarantees, and also degrading RCU's read-side performance. Furthermore, this approach is infeasible in cases where any of the RCU read-side critical sections contains operations that the TM implementation in question is incapable of handling.
  5. Many update-side uses of RCU modify a single pointer to publish a new data structure. In some these cases, RCU can safely be permitted to see a transactional pointer update that is subsequently rolled back, as long as the transaction respects memory ordering and as long as the roll-back process uses call_rcu() to free up the corresponding structure. Unfortunately, not all TM implementations respect memory barriers within a transaction. Apparently, the thought is that because transactions are supposed to be atomic, the ordering of the accesses within the transaction is not supposed to matter.
  6. Prohibit use of TM in RCU updates. This is guaranteed to work, but seems a bit restrictive.

It seems likely that additional approaches will be uncovered, especially given the advent of user-level RCU implementations.17.4

Paul E. McKenney 2011-12-16
perfbook_html/node175.html0000644000175000017500000000433211672746162015651 0ustar paulmckpaulmck 12.3 Static Analysis


12.3 Static Analysis



Paul E. McKenney 2011-12-16
perfbook_html/img79.png0000644000175000017500000000031011672746137015235 0ustar paulmckpaulmckPNG  IHDR  h*PLTEMJK# b``mkkXUV856wuv.*+tRNS@fLIDATc```a L`B0@A3q2 3@JTAʐA P!$D g4g2IENDB`perfbook_html/node126.html0000644000175000017500000004047111672746162015651 0ustar paulmckpaulmck 10.3.1.1 Publish-Subscribe Mechanism


10.3.1.1 Publish-Subscribe Mechanism

Figure: Data Structure Publication (Unsafe)
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 int a;
3 int b...
... p->a = 1;
12 p->b = 2;
13 p->c = 3;
14 gp = p;\end{verbatim}
}\end{figure}

One key attribute of RCU is the ability to safely scan data, even though that data is being modified concurrently. To provide this ability for concurrent insertion, RCU uses what can be thought of as a publish-subscribe mechanism. For example, consider an initially NULL global pointer gp that is to be modified to point to a newly allocated and initialized data structure. The code fragment shown in Figure [*] (with the addition of appropriate locking) might be used for this purpose.

Unfortunately, there is nothing forcing the compiler and CPU to execute the last four assignment statements in order. If the assignment to gp happens before the initialization of p fields, then concurrent readers could see the uninitialized values. Memory barriers are required to keep things ordered, but memory barriers are notoriously difficult to use. We therefore encapsulate them into a primitive rcu_assign_pointer() that has publication semantics. The last four lines would then be as follows:



  1 p->a = 1;
  2 p->b = 2;
  3 p->c = 3;
  4 rcu_assign_pointer(gp, p);


The rcu_assign_pointer() would publish the new structure, forcing both the compiler and the CPU to execute the assignment to gp after the assignments to the fields referenced by p

However, it is not sufficient to only enforce ordering at the updater, as the reader must enforce proper ordering as well. Consider for example the following code fragment:



  1 p = gp;
  2 if (p != NULL) {
  3   do_something_with(p->a, p->b, p->c);
  4 }


Although this code fragment might well seem immune to misordering, unfortunately, the DEC Alpha CPU [McK05a,McK05b] and value-speculation compiler optimizations can, believe it or not, cause the values of p->a, p->b, and p->c to be fetched before the value of p. This is perhaps easiest to see in the case of value-speculation compiler optimizations, where the compiler guesses the value of p fetches p->a, p->b, and p->c then fetches the actual value of p in order to check whether its guess was correct. This sort of optimization is quite aggressive, perhaps insanely so, but does actually occur in the context of profile-driven optimization.

Clearly, we need to prevent this sort of skullduggery on the part of both the compiler and the CPU. The rcu_dereference() primitive uses whatever memory-barrier instructions and compiler directives are required for this purpose:



  1 rcu_read_lock();
  2 p = rcu_dereference(gp);
  3 if (p != NULL) {
  4   do_something_with(p->a, p->b, p->c);
  5 }
  6 rcu_read_unlock();


The rcu_dereference() primitive can thus be thought of as subscribing to a given value of the specified pointer, guaranteeing that subsequent dereference operations will see any initialization that occurred before the corresponding publish (rcu_assign_pointer() operation. The rcu_read_lock() and rcu_read_unlock() calls are absolutely required: they define the extent of the RCU read-side critical section. Their purpose is explained in Section [*], however, they never spin or block, nor do they prevent the list_add_rcu() from executing concurrently. In fact, in non-CONFIG_PREEMPT kernels, they generate absolutely no code.

Figure: Linux Circular Linked List
\resizebox{3in}{!}{\includegraphics{defer/Linux_list}}

Figure: Linux Linked List Abbreviated
\resizebox{3in}{!}{\includegraphics{defer/Linux_list_abbr}}

Although rcu_assign_pointer() and rcu_dereference() can in theory be used to construct any conceivable RCU-protected data structure, in practice it is often better to use higher-level constructs. Therefore, the rcu_assign_pointer() and rcu_dereference() primitives have been embedded in special RCU variants of Linux's list-manipulation API. Linux has two variants of doubly linked list, the circular struct list_head and the linear struct hlist_head/struct hlist_node pair. The former is laid out as shown in Figure [*], where the green boxes represent the list header and the blue boxes represent the elements in the list. This notation is cumbersome, and will therefore be abbreviated as shown in Figure [*].

Figure: RCU Data Structure Publication
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct list_hea...
...;
14 p->c = 3;
15 list_add_rcu(&p->list, &head);\end{verbatim}
}\end{figure}

Adapting the pointer-publish example for the linked list results in the code shown in Figure [*].

Line 15 must be protected by some synchronization mechanism (most commonly some sort of lock) to prevent multiple list_add() instances from executing concurrently. However, such synchronization does not prevent this list_add() instance from executing concurrently with RCU readers.

Subscribing to an RCU-protected list is straightforward:



  1 rcu_read_lock();
  2 list_for_each_entry_rcu(p, head, list) {
  3   do_something_with(p->a, p->b, p->c);
  4 }
  5 rcu_read_unlock();


The list_add_rcu() primitive publishes an entry into the specified list, guaranteeing that the corresponding list_for_each_entry_rcu() invocation will properly subscribe to this same entry.

Quick Quiz 10.7: What prevents the list_for_each_entry_rcu() from getting a segfault if it happens to execute at exactly the same time as the list_add_rcu()? End Quick Quiz

Figure: Linux Linear Linked List
\resizebox{3in}{!}{\includegraphics{defer/Linux_hlist}}

Linux's other doubly linked list, the hlist, is a linear list, which means that it needs only one pointer for the header rather than the two required for the circular list, as shown in Figure[*]. Thus, use of hlist can halve the memory consumption for the hash-bucket arrays of large hash tables. As before, this notation is cumbersome, so hlists will be abbreviated in the same way lists are, as shown in Figure [*].

Figure: RCU hlist Publication
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct hlist_no...
...p->c = 3;
15 hlist_add_head_rcu(&p->list, &head);\end{verbatim}
}\end{figure}

Publishing a new element to an RCU-protected hlist is quite similar to doing so for the circular list, as shown in Figure [*].

As before, line 15 must be protected by some sort of synchronization mechanism, for example, a lock.

Subscribing to an RCU-protected hlist is also similar to the circular list:



  1 rcu_read_lock();
  2 hlist_for_each_entry_rcu(p, q, head, list) {
  3   do_something_with(p->a, p->b, p->c);
  4 }
  5 rcu_read_unlock();


Quick Quiz 10.8: Why do we need to pass two pointers into hlist_for_each_entry_rcu() when only one is needed for list_for_each_entry_rcu()? End Quick Quiz


Table: RCU Publish and Subscribe Primitives
Category Publish Retract Subscribe
Pointers rcu_assign_pointer() rcu_assign_pointer(..., NULL) rcu_dereference()
Lists list_add_rcu()
list_add_tail_rcu()
list_replace_rcu()
list_del_rcu() list_for_each_entry_rcu()
Hlists hlist_add_after_rcu()
hlist_add_before_rcu()
hlist_add_head_rcu()
hlist_replace_rcu()
hlist_del_rcu() hlist_for_each_entry_rcu()


The set of RCU publish and subscribe primitives are shown in Table [*], along with additional primitives to ``unpublish'', or retract.

Note that the list_replace_rcu(), list_del_rcu(), hlist_replace_rcu(), and hlist_del_rcu() APIs add a complication. When is it safe to free up the data element that was replaced or removed? In particular, how can we possibly know when all the readers have released their references to that data element?

These questions are addressed in the following section.

Paul E. McKenney 2011-12-16
perfbook_html/img251.png0000644000175000017500000004643411672745754015332 0ustar paulmckpaulmckPNG  IHDR[QeԲNPLTE^\\URSMJK# b``mkkcaaa__ZWXXUV856iffC@@wuv.*+.tRNS@f IDATx} *-OkUe.%1Y9d%^aybdɰlWR}ϕսj6K_+I١8&W#WJ?AmԸ/dMA495qR1d/&t|~aCwGݠ5kT>κϲ\|+blA{B|g zY۸~+|T\D[ [BIL:aVe:((]鰝}tԙȝ* uv(]:L5ܳ])!sKCI ٍs@]Z;XG5CW7d^G1x %= taVXfeVNIOz+IܻuNޚH̻ ~u/K;6A19|j|uGcVuѠdKkP+7YүL \tp.%GmAl ZҢyM1-Lp%_phl:^R2h燆ʝ03cclg4|v8sMe ktPZ+boD`PVb7y^C2~Y" +5Bn9k̚VGڮ+XݫV[f[*\?g{N=~p˞5溬U05kՏǚ{%&=.Y g$9.u [Z6Z86N1V,"rUuNډij fjk(٭>.{Mj,]SkW+MduSuy )`|FyeEcnA~ 8Z͝Ck'J8Tӳ߳+P!8'omٌM'*{nz:|ҽ\5=s\=լ{qZ lW}Wo6?RҍJoa0ֈoJtO@vG6@tu{ _6cU$. S!E@-0-jo]pXq}AקokIV4b z粳nDE(l9UNt^#;;1lk\Ͳ8ntQ#J{k/O޺1?Fٷy88`6Z2748ەs[|ox=xЕ@1)􈶣v!kƟ09y{x]Ƶ|rtaxs;|J ]P~o npF".$; )z ޅxGv{s|u3tcr%-3 ۊBP M},뒒~eT.1\{gi6o̽VJ@*vU;2,{ĎŞ'P .3uh􇆦y?tEneC~0v⡏ߑMoy+b 1WՐ@{g[EB^JoYv8@ F̔l]]W qMJ,?4&ӈH'enr<໘inJ V68YsOZgyPt3;}Yb޴2~W&cUֻ&Wv|=dC d)axոԁ2{zm.yDTg`rKI]1WLBo7Z:,B@6u*ӌ5h<`?}.j}6Oj~%V*V2hfOVd$4S@*ZU EnYЧbs|P150|4F+}Qy{q/,L,3?09Fo!߆P6 3i^~k;`\pz-ae,|Ž:\6# @=.a2ҨaA#'c=xt̺$oP$ԺBMJ#-:sUr@S+[}$Q-MNR 7TLY}z7aB ߺf|p={LiӨ䇳nK.܄1TCQ 0j{b5 z.ekt kWU_}.ͪAH/_y<}شr*.(~ujSoM׼bbkT/J?:S1fUx[R@GZ ?-t\ )B. 6g0drm6ࡪu=>ъY"hǑsJr?bG GXVOFGawj d0X5ma6ZiQR3,)B$i9 Qfܧ.J üS]G85cYv`> {,yp5𶕸wy*}"ш4pPukv9P!WU3L+1_:1sE[.qԩOP߂NT7u [4M^؜b:?d$] H ҤF`F%ۛͅHX2 84RƤZ@S żk:30E~PM3UF9| "Q ,HWq.½l%@T6eM-'N1R3w,9 U$׾7D>.]BٝOY`L}pa$x"V|qXR R+hQPv8eJx3@Y0dw7.-w3ZxT+'{oR@]ŜWgAuI]DQ[ 0ڨ9Gks΂ý`;M7-luv6$>O5|G껠Zr$t\،=]NA$w?_UޤFwLdcbBG`)* K.s@)}㳉 "Z!!6KG@ jJLH2}i-'QXC{SdeDPk{ R4֪4);ғi6^A P\L2yHbcb"k9gQb.e&bL)"M`,ְp ;86*jqبP,P9ط* G=8 Zُ 3YX+7 컁͔Tn:e;-}dRnՃ4V6ӧ]JLYhY$/I(L=]}"H@YXkjp`"!e/iDNmbT#i<'=&ȄMr[B1Bg%[*Ʒ KYB TiI=3-|nm}(htH2J Lza-r1uɜa"892( Vd619ʲ@93qIbqjxee&o2#v|RNPmivad'ؔO7;0ˆPu֎O]|#$FNgLa\k{"ϱ9}5,g40%ě~qS⼓p@XUa:|fYv%<֟3~I'9cǖA񩲺;?lMiegVxR]$ 5M` M$WR$VpκX6?hR? K}W[s M\k? V+(Y}ݥeh]vZ/r 6;3CmO7=,nHsJj|,h>˪F0 |JvE7TLk9ےoŠdTE.mCDuuѠuijE7AqK+@UIAiQE-G-?FlaڂY:GFQH{?/Dts-9ּOZ yY6}(#I+ t7i 뭼146S|Ocf ?^Bj-oQreU@0 y6k'L*'h~t *;JZm{&F;![(|<]`o#*JK P\'[>On/n/wQQ~)[e9WmIC?$n`$hոp0-4D\? ],"auqt:^Laӑ¨X_~R 2=u<6b_ڸbIj]tІU7>!bwJKjMϏ諘k6t %*݄PQGix$#5!\?,ky FvB8h<[$NrL} RGd6h/-֩/ \Skܮ.߯yD?67|.,<*Փ rutalw+&$蒌`-\Oj iP&˱Sy錯;'Er/r=[4dԺ?3Soh9~(gP/73d@ ^CՇFa0^Ѣ_+yAnbcJǨɹʲW)E[(5A20uִDmсFNšEpꨢ 1"g(<(!#ltWQަC'r~c>R-N塥c~S@-Vٹ,pok!<LJAؔ3-BDdoG%C pgݙP FQw&7]=usψtYLXp+,2ѶO(BX- lR&- oJBv 3,E41 -.As"1L벭1AIF8& X;hd*Esn AԆ1a- 2bxQ&OKG: _F ti I)[DuoڂQ$_`ߨڋ$+yփxL@,&PFF.зLͳ2Y< pH8fڈ[^*Ԃޠ՜)^jMQ~VDk5,SJ>Tz- IiG|SFhC{ \ IF>#~i? Ǯ3@(G\ 3L'* FpP9 9 L FIJ@ Ff^+ õ$_-kėLk3ԝZΠKZ~|M#:}~A?K7ߧˀ[iZfo_Txޙ>};+\2#I2s IDATЛl51jՃP-B" Y ;w#wDjQmeĚPmaT{JF_s:PmD@-ngx,U6\! UfGI[V_ߪpo p"ˬim k(ۓ^|qɥ.>ì %xF,mh˟^Wܘh B'## rВ ;vUްm "45qNc?#[sњ] 1K%yoœLn^Am+\#4Q@4iqHe\\!xsUlE2 %z{ANu/ +M}+)pt˵\0^pxGUI.)k,uz,RffaH4Uc*pܐ_^XiɃ[l2^։l  M"R)e$=mW_:oCfV[7TvYĖbNe7 oV/4ڍD "Iq[Ƅ2^b1 goQFc(Q- "xH*0T,-f>Q_Szdc%smhmYusiݖhm} [p v^*WA3T +=V:4JW:cD1 L(~d(HB}`3"# vS\ 6@z@>t|@DQ~BT*E+g'J`wIwdouf_7'C#6~OUJvFh\L%Q䘗r>i%0N"+0%+j2A.tm\WVcS}jnXogpm`\ܓ{ D )"XYubdUn؃Ono (0Mb8 7"oG uRJ1^ Jƛ~ +"#M'/ȐRkBގI{ mW*Nu8RY9aJ51ϟ*# N?p=E*_5XLW[t %ho, uqAou2. Xia);bVFVd"\ځRڦtڎz(#sԊgEV4.=^fyLj[4ێwdk{*MH8fq-L%k--8vty13mA<#R$ͷ+tЋ?zd+^Kc?|m1Ya%aWqKgO'Ϋ犬 if\9E,&e.Yz$,5-X㐸9KpIt#aUqF=|NP]5V=?[Ḽt8\]HXlCk5|:'rs><٦l+CK㴚;ٌђ-P+e UFEoxeСe-je *Ɣ ŷloބĖ۠I;[&5FFjlmS2u!w4NW[$9!JRskgvV=8f0RQNߛJ{G4#XFǠjJzAgI8hc X+jҝΗq@,TZ&c89^2#Wb{5_t#܀ \Rf5 BLrjI#vRHލ O'0 pox3ά.tFY, m6q) b2ɯq`Ѭkn٤=V:KFY "d+n/Wj»>VB(M*`msFKn#ĥ\C*Uv LG.byN=^ĞmKHk'cEI1K|qcUF_qؒY^ u[&Ec &`Rf3%,jriFYZxJ,{ʎoc FoX@meMKá:;%DQj0W8Mif ᐙ[P ˕d7t-+^-fҩY۽@GL~Vondi$FNJ]Pcm,@# &v/Ш1;)mPZ< F[$ɐ̫!d!mۚ@d)6J*c5*ތn. 3 rrHȝpAc8[ jE X4PiDS𕡫corS1 T]8 h0k+,!|Pϴ-T^tN2 tj+ |a@uq,@TimOvs]1cnTPk5,o6Htj:hZ 49t(2INg[_[m*VC* bmm?f8ZO: %7ѓc6ty~+퀸}8](|Z/%*p>ys?)*֔ ZCGj V><4lTlyQgĭt ӸoiŀCxEmc^ %l9LN*D}GڗX$-ⴧe9P083,ی^f|qޑJ[0oT@|ěC5QRdur$B^E_sZ ;(zBWN_0jEDVEg)D(m:Xl@S⋤ՓζC h]YJ9eV:l52*y>yf: mqc,mET r$ +y#rsP `LH1ʮ<]@a=3:y0ʮ[?Aa^Ę 'sV40&`1ȃSV8 PmSc6;QK38wLauL ‡$) r/$);4lχuES!wԡЕ3RO,b32ӉzE^ ZR6\LLj5;ڪz#߽%!">T9:2`+bW~|9r1m\o6ߒ\~ 0eUN[~k^VXoF d~txJkas3X cPuv3X QQ ߮,jk>v&-\%xxb3):)@A|7+gaNeD4%MN(} 4{jEkّ\:2#r-4`9%u-Qx 8ēk[TUՄ8g@CbTI KE.#CM7\Sr̽(o!+;̎hwq3#q\[/HCŖ[ܣ֣iJX.ڥ YۛPFJAy0 gIجY_M[őKn̓[)eq# lF9؞v*rP7imLDsY^rwλ{|F0{OĪrB_]@Ik\__Ziߛ5'ygZԔn70Y͠^ʲ]RΡ 얙ȶ qvǔml[*bcnm{-$%zFɔMB{}R/1 EH8LS]ucѱګ摹˒>U?[*7\zvOERWZKqLȸ>kWk_$3ոCUڍ!:KV٭nƴXwrUNw9zCoc\8w۽B)cù?SGG+kTchv,1TuXS]- 3 tکϽdqդp ̦7kW{Ob56@ e-Mdh *& \l~^-~~kj'GJՐʀww*IYj*xqO~( "M,maxU7*4ȯaH5pײ3O9EV.m/tW>6v4ڱ7+Sx;|-!QGW n~ପ]X>R%5R' slRJ HF5SQ +һngNJ[>)e~KLz-Rcf?$w4UwoKeل5eŎ6qsoX(m> ~Fۋ.l/K#K&9|dnSF![{ꦨ3_5U ',DV4MOh-I* Ky cjh-"F K#&c1ʗ9䶡ض]e;vYGWAp(_{Q1Ͳe)1.1oy4]>~PiSM][n7T)OԀ8N >? Yלx!H!*~k:|o!#ӯ48}X/vfAߍ$*\&(D\&YN~%Y: dzSO"?Dj)vٶk w&iITF@sh JSВeBºwljl=,3{8}=ZV)Th'qL'Gfe 菊4|ΐ5q.IYپKOBtV xIvs%! vz?ˈ$?ߒ5sBw2(v!ݦf;[9CEtyN7s=;v`* 9A9Tn-Pca8SY,ep@e3)=R-VWG6ڼ !y 豵p(4f}hU'ۖA7=N~& cN$hKE}~[Tn@NKz] NmEq"LNu ϊg?*DQLEUhI߮jZ OKhVƴ7o{%ɊB@n#O, &w[ 6fQ5P|<+oƽVXA€\yR`zn[$oWm5nfO7VXI\#OI,2mv}oMϗ:TLyL^tc蓷A6[x_OպN`9FUV#kf!@ TOڒc$iS ,/b? R1|5 "=sE[nlmxmKԍ'/HLu&,B>C} ;&ASW=B`'m9亱N5mC]p'Sut\cƼV\7:]Fw73}:&e%06kd; Kx${טT8OzBŗC r9Ӂqj` P ٔO'tI:FǢw8^XB"'sqw`Wb]n0] jVOq.;o[>~ؾ:Զf$#sn[Ϳ!斟( nl-!64lbxtɲ 9prKKIZ໲.G&hGt\d:٤ypۢFCۤXpq5`Ȧ<*D7"*C\ٶTeӉSQyMn,wIP{ !Q\s52(E>G$* QNTf8-b>+D7#xS0䇲ә.Bv <ȺgcUhʊ52 +Sp:@ ":e#W Gn-YmU f'׏M1B- )U)d_OG&.R[8#|!]^ByJRsQ<7˿̐+*VSF,&kO[aksW.cTI)vJεR (w*Ndq~8dwpJ9[\+6@BKIF:ӵ^맨IYKŵd2& {iWx/(GVsn[>*,ʇ]l5i[/[H= 1d-k<-@gq1揯G -+MA[Mv6C8l[eMPSJ𻚻}$;X:TLRCpomm5o3*VE&(T)%GcA1 #5`KY7io[co f VU ˮ!9v \HJsv:9#s Z:s#-mMECp].W`={14 ۄD)Xp}u[2GO(rKyuEzJ+=5 .b+M6!1c rp4L1ߐ)0. ͠]׆~/ڶ(*W\F[i SPk3Bj dIDATz`~bP8 2 0õA}> ,="x=tU IϑׅۨY=*PR P3ZB>PЫ]XLZ=۵9e"*<s0⚑RG.B>T/䌯V*Crl_8R g`3%;|= WϺ'\tͫ(N1 Rfsn_Oճ~e^(N0{Kvz _8#N%WO׳q:oj3rObW.Hm)%`K<6*-8X-40NS{f6W!K`vaf^BޒA!m $9I6۶mW3Sۺ#*dp .ܶy[m}:)^KKrp^(m,yy˛~jL喟,X#E ^)-3 [Z9KL8z"-K7/TQbBȊ:U zˆJU|p(=;FR%>[Ĝ)zѨ('TkTȿCC&¡x(Dz|YBHcʪC~D;+p>_J)NS(ȧc uR$Y:INHh+*׀(I.m#M D“=mAbSY|^!D,Mұ|kfD5uEoǍgPObFJI-G]jd(125+ bmEicƄ<(YVREoǍ A6wʦ~,#V_p;ۅ~]N~KR`l{r%ȥpz! *Eip:bdc)SEN-RAL)a:6dA6m#O $o!6mɏ$EgSIo%YW-膹RBzGlfIyQ^v2Y{oF?wPcz%$;rvq^v9yޏ^v9BsGO>7dך)10gV$B3Ϲ ֕"H!+=t+c[8WrSD JK# a]s*+7֎9u1, s%?+aBXuŝ̗B$m ig Lm]|-+)">)TN&eG\M>@ϐ_BA&$M3Jl  m[ 5# 1%NVZ8޶ ne8,n6Ј\LUPȮ>~‰{G/`,%WFDF+ \EaU"ˊPtm%F݉cOR+/Wn-g Yioö$cEzXJfFӉeV#4ı3&BzL Wol:G8q{l5JCv1i4hf4HRvj9v9c">g%ljy2sK 'tC|i9b 'bWe > [;I(|^TN]Iy[ ƛ7Zܑ}̲p%QR SYgɋus%vm?boN2B 4y55䩨3v"y=5#r'S oD!NVd;f3),\$!+jlQ¿3weyf&?!3'"[>z&;hIZTJB,>-Fj=|7ĚB"#|\++Ծ+Iho[s !1֔W..A9y5ȥgGl5ߪUA2-.NoSv79Jƿ%j6g(top߲&D(sy٧sҮtN5Wm4e0%r_5Y5pzdH27Fw:mi@ aw'R5!4~kxO N& AA=l=ѻz{e뇱ZXС  *L|XO Fߓz(Qϕ47j)Oɧϕ ~ BO>/Hل?iRr m aKIzLv,7[Ƃ\@cšX췩pGtY _pz>'L) Oȫ=S@mߣCt@O M+ JBRFbVAĘgx첤Wͯ#:ɬRuEH˂^e?^Ï0,Pk".sz* ?ҨיUHƯrZnl[>Cro'6(m 7`w6o{Ay'\'x\M~K ̖"'>sV:~KV ?ϥ>g . ?¥vOGX[RB>B>YJ >\=&r-%Ȑ̹:QRvPňgu ߑ3Ԭx _x´/jF7Ivouz7 RiDO0{{AƎ`mcmK{%U68=Nx3P<0^ȗ2V&ť`m^W1H?{ef mܾ lcfu$6喣V$nʒrA}J]i!ɂup3r$z V+px_$oWs_&2aXPfH5#l 't9.B{ VjNC҆4ÝZu_tLIJMKWY-x߳CuiuZG{=Vx{lOȐۏsxoD,~9rDŽSP!/^LIENDB`perfbook_html/node343.html0000644000175000017500000001351711672746163015654 0ustar paulmckpaulmck D.2.1 Review of RCU Fundamentals


D.2.1 Review of RCU Fundamentals

In its most basic form, RCU is a way of waiting for things to finish. Of course, there are a great many other ways of waiting for things to finish, including reference counts, reader-writer locks, events, and so on. The great advantage of RCU is that it can wait for each of (say) 20,000 different things without having to explicitly track each and every one of them, and without having to worry about the performance degradation, scalability limitations, complex deadlock scenarios, and memory-leak hazards that are inherent in schemes using explicit tracking.

In RCU's case, the things waited on are called "RCU read-side critical sections". An RCU read-side critical section starts with an rcu_read_lock() primitive, and ends with a corresponding rcu_read_unlock() primitive. RCU read-side critical sections can be nested, and may contain pretty much any code, as long as that code does not explicitly block or sleep (although a special form of RCU called SRCU, described in Section [*] does permit general sleeping in SRCU read-side critical sections). If you abide by these conventions, you can use RCU to wait for any desired piece of code to complete.

RCU accomplishes this feat by indirectly determining when these other things have finished, as has been described elsewhere [MS98] for classic RCU and Section [*] for preemptible RCU.

In particular, as shown in the Figure [*] on page [*], RCU is a way of waiting for pre-existing RCU read-side critical sections to completely finish, also including the memory operations executed by those critical sections.

However, note that RCU read-side critical sections that begin after the beginning of a given grace period can and will extend beyond the end of that grace period.

The following section gives a very high-level view of how the Classic RCU implementation operates.

Paul E. McKenney 2011-12-16
perfbook_html/img164.png0000644000175000017500000005326511672746152015326 0ustar paulmckpaulmckPNG  IHDRY?6kPLTEIFAֹޮ̍D@<4,)ǑDž1(&vPۼ62.Бձ@>;RMFӐ&"Д߬wlSDBBˋTQKդf`Vy׶ŀyђ(|ϐƴ\UE ڥ[SD]]]e]QnPϓUUUjeYSNIMMM)%#mliVL8Ғ[XTvkT???nܼWTSWQIVOH٢Ʌ>:7ZM8_[TOGAГБưmϚ״ؠ|ҧtѐΕدccarcHp\PăW?g\GѓB?=ԡaYNݲϓ΍VRMʉ`^Z:4.]WMߧ}\NLHғdʷΑڭdddpgR֩ӭ\\\PKC}VVVTTTIC<{ָNNN`T8NIDFFFJE@p @;6ӔOH>xёЋpi[6/,A=:iaTקsݱZVOg_U}qZ̍FB;ʊ?84Ż<61ntRNS@f IDATx{`u/ZR+RevTJ$R`TAqO#A5 iRYζ⣽d)T1,#a+?bَ$iq X@a>l I)ٴe73x/H!8̙sΜ9#W@7> */{Z\#AimЊ_;m-ml HKS2`27t]4 4/j ;f-1FM(H5>q'!yZF޶Jya㦓ڽ4Ew"@I- ߻~=)-ٖx'JE?LSJB ,j?&ئӴdrXe"Ř$_;#`c[BN_@?xJHOrdi;Oƨ>i&-25|EcQ6ԩ5$MFs%0h /[$8N M-#-Iquf;I}MA3ė?h L6O: J=#.P `*i٧[(@/UmLcAv1jc=[,Vsj#0[[cLl,CoϿ"r/ޮ6Qh{e~=-Hhm[" ^M"SI&~ 3-Y# SV:;nʨ}81 Ja۾>.'@AZ>NmW)T'\Zr` (pFZF=vS _[4PB4ݿt[BC/s.tmmP+ Ӆ}O-!1u2f%k|yd.mb} E \cYY[oC"2'R(I%6]l秷,'vEWlߞ<)UtfIncC+[,2&ƞ>`E[Ӧ8ה-mqQZ$ Ri@]4)l jI'+T˷Cɫ4^eo {co-]-mUtg]}#m֨އӯ{5TWd筀_2H^iF.ofBw="wy/cԶRIvfFJ釺l 0,J?&F~KP6.&h('+;~xѷHpx֠MDeҲ^(F5@IKJV l&IB%YHe_=|:؋E (^ ф<k~{[vKFù $iF;[a#K  ʯ\2j7>.W&l&ںMZZ Ή׏x?-2T Ѧ4TWjK2)nXoRKYe~GmDD oxlQSb#vuw6 v!Th9v:M'Zķ?O/A"R\mX6Y]=hC%[IJjG#Ku Al#p a'E#5:.oa\549; \w\ Muw]_&tf?7789rO'N4IsDvϩ)}8wTtEgrF:o# ؋5nw}3}nb~sDlI5iIZQ"״ d!izmɸo膪EHd%/~.襼rf&hI@;iLg'%gzܳC>t VC+}RWyZeU W*\!|vAٟ­ٟ(D1B ~u"!XчLxv/[" 2 ^SHN2PK2 Ut Ht$0CJcn]ԘR[i/w{BRQʺBf509jJ Q.tmx߮jvƘw+$y ȟL N &0jᷖ ^*kd{Q*tK`)%&RH-։ YGQ3gPZ0Fu5+WUo t/kWe,j@mw$xr,I_7ALš_Yǿ#+;fJI8_,eϡS锗[]"z-yl(M[cVPgnbht'rN8ufB[JEyfn<(2ㆼU7>׆Gy,-s5jlF-^^- p^SKKE݆lN䫓~رsuT -A`Z Ap5i4D [poI}2VHUu_R|QԲn1zI[N& b/n Yl{QE-%a/dY(_v2fM&1h!Y?u1ߚ EH~"nh nNۘlyRd)KAZI e+'lTPBU;-Ulަt"."dS`ܗ`{pиnQYQ>">|J%Z4~L?e(lS 2(.[эZA@DBv2 85bAYvOv%E }ا@&g:e>4 M\Oпv4&ڸ̆8Vju$Oߋg 2m Qd&FfAQ b》o,-8C:A<ɐ- _FlHby^&rU\xO$ +Hr_KKwyl! []?e"k { ]6KxǐPmr^ed'ViX)b7AF<}9k3'vZ#E"t~/ݍ8F +Yمfts~뗟ЌLco jb^mS$-m 8"=[aMP{*Ӿlwm>0]t7 tR֮<3fB&dJ%kƄN#]*+@;w>eAT}{QI4sϲbZ[hVId?}WXZ%FQAU_`[]Wgi@jbf BA@igG|>2zz6FI2,v<g>;vP9Zq*E8Ts ršOO&l6[eKRv$ tp `Z+Mh.x X͎+?X t%.YiR?a'=vp)d3^)f+pmQ*֞5q[ nWٝwVKT֙c-<^S=*Ɵ}MV{Zl$7PZ-gְ+*/R]WW Y:ưBL Nf i۔!^}F>/ <4ݣ+!:5Yg3:3KNZ Rp<oڹk@(4j;e!T^pu+i z+h9і:/BѭLRJ&u38n$ n'T*eC\b\@@$Zx{w-(̭=VxUpʸ5Ue9-v( Xa7c1FoPB8=P(>,|{$@2}6W[$8 p1ܦ։%T+&bta!Ӵ.XFC,}O++Ao)]^CעR~G d ]t MŎZZ BW-""o@VNX䙶~ը$s|[eX׃a6|c^ [4KK}-A([2ӌHX/8R顂̮)mn~Ѓ[[xNQF:L@ ,m48"~(b[XXGn!hNTn¯JA !B|;REVkָ^qq|$ad2 ;Aohf&-tvYP‚t-wst0[hr6e dZkA%>ué-WFE/zkmJfQ߾'hb \ 7:l.s&x-2SgS%2׃[ oHY1h֢ (ɬh/<]2wT^ɛ$ĥD 79>.Dvn:47j_eWkTl${}Duo|޴vg*/~w?rUY@Q3!h6/-g_1{hu̮4]3@DdK^@Yke<*xvwgU&͇j_,Yɮ|_"yJ&ͫ`dEte^ݬm[tP1Q7<1TfBW|VwWQռRfd2) RM{_L`iB~זGnt6ĠGm0]}Ef#FfAl|) ԁ˦טO7}cD٥dt_ט [;9 j3JHl51K U#מ-DJ$ꥰV,sZ" P̲HQÒ)߶D- 6s"c4.U8n5*?TC݀hthM&"?ƯDq 23l%‰Eh֔Ť k =|Gg] fk8TmjjkfpiEkh=f9nǕtZvT9[ Nu~ 8m!AS"ճ;x=Bli?wc9(+skO=O1%h4ŁĮ(` IDATYz^"v.BeĸUfGGx:$BQ17ɔ'OfRf`-2+pI{r<p8`G(\g׷|>+(BB*1@JqCEfnMd*]:G5y]O}*څH{Oξ^1!`fȶ 1@_W3pb5nբYB ;yPPiϮs^uBP8( +0mê F&ho+VqOqjljS{^BM ̚]XU$Zi(^V *8EK>+NEZY.dƒ$i-K`iZUCQ!{FvG޴m幔K2+-0ɉ`x˲U<KQ)TH[޷%<%RluJoIUog\m.to+u)fP4ql+ElvB[R񼞧<^-%嶋a!ĄRĬŒ*_ɇ GU:cf!=/ ~G{5e.ʬ3-lqTȉVkn XeE_V0 gp֓oUBjcjXlu'&SdD$IJJ*ҨJo q Vj6ǡI&SA u^e|I UQ83>-Y!Y=EY}¦@@:NIo!55J+9.(D*jX|@lx嘵 Α vc:l->L/lDŽ* $U###7k_ddT?7rR ;YÞL^Ij`µNA޶?hYaFfRW81YV4VJ*A|Pzȭ˗^GR{E mse7vYdI8%\ڈIPu|n ձXC)Ѕ7 ]*Se/3[rGm:x;JV1+2m j):uG Z=0iHnX滪Ț \ÑDH[r¡"rT7V4֋U@uԚۇqҌA&T ;"[E~R:Y[>*=GVMSUwa-RU}v-(g=oAPK~܊Hry팡S mgX5rnyff 'rxuwK2+g<˙-o䕛n+l8VlRT7CSm%*-m{*s& +`./۷i0eUؖr6Ҧ_ɸ_VQޫ]>Rn\Mߌ*g[X*/I,f\Y'ϫ5g"# -~ VVtGIkrCrin;ȋ=@*0d)2e%K3 3^Ⱦ(GQA 2 X-O#Hȏ C2k)|u&M*R)*xlp[Rk(%BiB̒9fKFр7M3&lh%*xG:}ڲ5aCPqN JtN"aTQO]2[yfC7~ ޙ3K |qLԗT=6zv( Ya tI̚Du1 F :^RaX7LcP>:Y 'e4\ 2NNLR(8u6+2 nBDa Yv04ؒqߑ(^X܃C¦ʖEN$։T`@1 |P!7܀ `zb ލwx{)oHzקAQ5',*)!(k/P ЁS\vG͋@ ʏι^:ap:np^[.*lSkE[.WaQ&~h閛muhxӐY_*+T|Π_&CsC,:x7+SN=洗E<#c2s'ΟiV,AOjAN!b^Vz5iΣICK^ծ2TY=ӹjRa"Ce2(Cܹ8h=L ~%;=Ws^* zsG[OzGrz -TˮKtx:SެTfUF.U!$Gώ}*xث W<@ĺ]og лYyi\8aNm z-41AyOV"5`=wnaNEW^_:}i] V-vBaTA/Y-)d_Ot8B^%S+n 2&>Kk_˽5^jt^>2'ai5z@Arz^B*'4=8bU 5 oYCUEBfѯY5_R+Y+doZdMUӨޜTdbrQ["Gߗ=]~.:-Y|/1C[a$tIHygRrHUn(CIb߉nXG}GFh AAΈ3{emG׏1nz%w.dzÒY=}^o:=vdQf^$gZ75_m[et1["j v>xǦ`0Ķqj{WЀ/{`c}=:Ld ȼXd |JVBum{`ܰ۫k{*fZzޙSxPoVۍ+,;Xd999)呍tmg{-Uy6Ϧ_"\l2q?၏>peHb2jբC(@ LD )ZV^<ϝ6%٩WM^Н\z" x f UZf\S68hL r|!@_rcs7O_+Gx\ox%$nJW; }TBFW-ȚA&Pb)'^=5} nX9kA_vٲ|ș3/ \VBF 艓;ƆHH ,W6A CƿHUto9TQEP_tn|%IQyqH>k* Ztp9X,|S$fQTY;չ_L77_{J'j>bVOt]D0Ԉckm?2 PTœ-kGfr"al`hhWr kx0Iu@`EU=8 NKz Լy\d ~֌,DV C|3 SC S8ruD" u9 Z=llBɢ!3!NrAl4kZ[p?T%@Xt^8i"hw,j'Me~?x%jKkPq+E:2Mإyh3$_'DK`F>Szt6OX*J .[tbY/cJc'C;٘U9ZJh\ 0̌7m2Big7'q횑%+¿0 3Qb-aMXkZ=mY {]T8;G}Uۜ&1 A$e\nb,>c^IOm$;'t(Ax|p3'kG6P4!=фآZ)CN&vwzsVs33at &2@kUw}aZ5/hʕ⢨$ݽo@Y[:_swr|tƾd(pNǒ > xK%4g6I>6CS=4 -e䘇;FaQ, gŵc;:F^I[ ԣڡnoso(QzrptӹUq,Mb5#k$QՅ s-PH|ԓۓՈG7%0䱅Vy6:-^oԥiGO]BH$ouݑbeO-Zŀ,T3׬ J[sxDB}_N%(ܛj [kb"+=~ro)h%^,7ҽG/@5-BKVk<iWn J Rn{6Á{Rڀ…B6#j&ϣrmKwo@9 g) jiXp76/C('[hnn ^ Oj|aF}]iqc JQ)7a ;1b1/6"=u^owzKm(@7ǚ%+{13K/uEAIĀE4i+41ɵ1F`L,1ڻE2]n yS2MsYxpZr-IFMןz7ep7іg[\` hzl[8緟I~.q ( z+ca $e?0' JI %-2?I2뀬--B~'9-@o E^i"ZVS̲#*~&xVe0TC_ez'=裟j^5N" I( =,m)-$xXޜE?Z Co8V(NBBlܡk% ǩ7n\˝x{2.v,\PL6{ vCmf!j3DB?@]\|oܚLdpJ搝e)WrD)kR8r k"kΟg#>58Q۷OCl)7>iKpxX=*ur/>@91-dCfW2fww Yq-+Zp " K*ioYV*uB(;x|eqFQ(7}\lz:_ ځݞvξD 8`r`0@W%YLؤ]EPbm&2iDEˑ%{B&ú0" qƅ9q:zGFI:|{NjҥNk@mRH]y` qK$:.r-Jz{LTTtqþ?Xspd{~?dF}禤ЪAl^bq}ί6$jVJ,LHعUUfv":3ff%3 Qo\aȖšq}iȂXW?u8P NVK\`+lW.Mz5DX<m|—2->!FH˕~jױ! ݃O6KFCk jif+BVWPC~iqt8[!qw1bLB}YJL;ؕѨJդz󯝔~s}O hc_O]=Y@1iH!djB6UcY sFkxx+Ky2aV9,ޯP/z<ǎyok98 56@~4ȊDJ{əb`:x̥Vt);2WJƠ)fЌ>=X]IDAT,Bd׶q!`FvOoVKyIT,}"Ӂ7XMѭ.ҫ-␭ WtI,9:Ia j =  J䥔;Ɔxg%4iZ 9}"m(6XB,YW #db{P8׬r8J-r;:(KԮ Zҹ6`Ͷr5X_mcdɚѣ( 5Y.Cɹ.0B/7OY[9^PAU \g珤g_ VRr,BXb6&>%8 a-9UO?+b0,T)9|nOpg\;~1v7r`_ZvTlNbO7,{*i55>1A6ze\_qttԵxBkbP#}_~ϻ븃6:R%[|0)P-j^d[eUFg1b_-DeUl'DiݔR]Vmpo}V`ڗDա0I`bܚ2bun;KreZ޿"^V]s>dǥK`:`ISs7tR<M]Eub@Y x~:;{m\e*eVrҥGb*WUuku$| H8mOY O&K6='"w?^(>\ [g yI좨*dyPf__\rUMDΡ#\|0A)r5њI%~E3YQm m>5 ;h >;vV[rd4gB9H`q02ӅQƅ &&RBRPY6Q.Nvy`>OQ`.Vu tkj_-Ulh".j4p)GFDsVWFY#I핿X7z':t)8r!d)_ z^h}3~aXa3iF-XSjuwt=灍[6Ɂ)ƹ f'ˮ,v08>zT>bꄊ7npY; X"_!j%p Nd#brj]+Y@6j 0 V Բ>0V$V( Q(/!ilթԪλN{oP>Z} /ӆB:n^^Ď_$yeǓh \:NDh7kOmѴUv;yP=ȠbmϜI|_{%I@fA,%$P8 t]\0!77P&ShQB,wAI1dYG|$=(+yo#'pFΛ4,#'ɣ\lHit [.~U˯FnlCJJxdK   8mf-V]prAwvTAدR롦}OQ*}º|`&,W9"HGG+ΒIY-8.`]H.0z@{\5pznT{^x&wVO˝^Όbd#Y^mE(/7z&szo`~m%<'nT.Iю-e הۻc QOQJ-Q#}~@"2uePՃY$d*qCkcpFAkh^o~^eZV!yCD~ !~˄ 7N8~(Njq2w?AQ缒aͤbp bt-ZaqуӀ .YR|c(O-Y P\YMu?<*@?0M|S21yECw@ٝ9HP>K[GVē=4 ҝQO_i>O{;W1^?a@S#?/z[ 6}SK0tB+Z MW/}%EH[`lXgɊyQco2bNtIe"9Ig:OzgxޭpvI.y 5o_Zq6},R>>v9ͦξ04t2QXȁ/zeA]:qb:Q AR".Xi_]P @0=z%4Pkj 1dVsKh,j2AɅAm1MoejRp{(=Rӊ|#؄Mp{\A_VĊgմv 0d&L,je^;=o_ffT̽Yꕶ F@v`w:Eű.X+!_'B=0>4zЪ݂b3鸑 wW>!'?dm3X=)"}8vsQW픛^˗ֲ Qy,s`3*Qܦ\>Tjn[TmamY~M;t>)"6VxғF(\o\ҽ kvNh3#Xaf6a-|+^kg/">рrA btC>lg(>"eE<`9UC (2Xt~-k1p?{ySZ)A%zb;;Y6iC;em ?)I٩gz)QzO,sC2RXtx3jS i{xl S3٩IaKdiWϿztgz-͜A!Ў/ר>=7ݿOl-//DI9do_zQ$,M7YpIENDB`perfbook_html/node452.html0000644000175000017500000000742711672746163015660 0ustar paulmckpaulmck E.8 Simplicity Avoids Formal Verification


E.8 Simplicity Avoids Formal Verification

The complexity of the dynticks interface for preemptible RCU is primarily due to the fact that both irqs and NMIs use the same code path and the same state variables. This leads to the notion of providing separate code paths and variables for irqs and NMIs, as has been done for hierarchical RCU [McK08a] as indirectly suggested by Manfred Spraul [Spr08b].



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img87.png0000644000175000017500000000136011672746004015233 0ustar paulmckpaulmckPNG  IHDRF*J0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fnIDATX혱@ƿ$f7aMB QvU] rpNrpBNDt:llb6h'*T,lnr;!'?$;<|yY?che&]y\WS>,©t>=g ƛ9q\=K#HkA;)K#0j%B]́WЦc|T~PSt5t+H (h–%bbdL$Zx+U4O4LU]]}'s*m+&!K,.lr$b\z[6\bِ蒗'KvKUo4].)U.Z4Z>&-׻x =N!:g8Cg=5ƃ16=hB ',毇ΖEM؝7cxDv[3wOulS3Dڟt8g y-C#M95v y"/C?vpCzvǑxE5xMŖz\{+' 8Ś\+ k_hVYIENDB`perfbook_html/img162.png0000644000175000017500000004722011672745761015323 0ustar paulmckpaulmckPNG  IHDR7w<{PLTEb``^\\\ZZURSTRRMJKZWWFCC# b`ahffvstommmkkXUV856iffKHHC@@A>>@<=wuv.*+-**|zzvttrppmjkFXtRNS@f IDATx û.-kgtv'\ $Ɛ\B8/s! 0o]x -hBʺ(𾏠Y_*]3V ql[h+;}.$denK{EL~3ka \ ;b>^|BöADOkg56;#Vӵqr<۫3OyCk-B$]E/h=ժO>G@M6>ݶRyThyb%Rۨ[*qL!l.彤)55_qNqm4{CMFgV3џXkkQGX5:KX<5FNj%oɥ=0Nji-Wـ[u BA#Ps8=;/g5V O⌙vbwP=]PVaW (}/F'՜nwc[s'{ 4 0فt|eI.N?qlh+*xYhcaDVxOIrN57Sgak^VFA` "AF`tŴ,ml>\sSUe5r+<sjEKnfVK8]3 #+Sh'020pfW4vղޝݹ[j*^]Jy:p4)FAZZ]Ȧ .C1tJGQ.rC3=[+zHWl"݄DA,wϪ !JJݜk*8F[^olxSS6GUWhnUmkcZ>el@k:}YB}>}+kZ RfWw*کۃEAe3.H,f:7ڛęûH馳]9]}̢LOQQve`Ⱦ%n H99'EOk/Sh,nE{SzTn' O 4YR7 IQ5oD<қ>°хm\SN:%ON+;;ڂ*W]9E sO">* z@-c5c>-m͎UYM+(Z'ҽ|{hϹ*eHM*'g`,O؟Ay类3k})GTNdOa]z."6<nm+KY 8Gk|j,uҧBFJ׺`~:o*J8;IɊt̨kՀ= mwFQ4SwcynsWt8Zz'w~JPkJ .wC[_'a|}<*RP]'H:ګ ]c ,!;HJ%8'D͌J m4ȝO, |ԗvF9R!v2vUG%Ӱ4!.Mx.3d=˸/{vX^a|+k |m]>="Q0x.9+xH\W0|fz+:Yg[ ~v2qs0?ߺ-fعuз4~TDzQo{p#PN{@ӏȯ $Z٥B-Pt_#3'9wB-e@7EgV :pT F෺;!}VTJ݇(ONNcd%.~WIi6"qrΡPr'<(7yHQ0W@D3UMGOz;mHC'C0tn§mBQٰQ.}num6lthH$\p5Yg 6Xn}c)iVl9hk_Ft6*><Ps\Q1KDxI瞁t`N՗?uS!Aق;M1%_ rg}Wm ȡ`b xN}3@e|-x:fncoht3V 3ɒuO.BK%TLx h$VRԹkQ`Φh>k]oO{T=:>s'ЇP"jF^{R-^ToVǨ9Ы?+pUS>JZё*-xvj| *2E*]*+hVښ<ޑJgtjS*] H e *@c lz@pґ~VYվᆮh[x#}7i k+ /+gU mia S^Zbf^1%9ctt$LtP ;ėzp朞pom%0z==)cE f/K.8d zy7@ ЏS,T󥦎)Fz\gj-D);%"X.ҕzzm< m!yIV{xkhv\L[ 5`/C9B:=žtt?{U Y%$ن,'tQ4xn:}4$Av>g59UռC+:}62 89\kj5p޽D,9-l4>>4GA3ݳ R 4\TQp\\DYFw4jh+_Ӯs䆤Rሾ85wH2D ilYV.&jJwtCGA0葅0=4+GnZP<\hHMd2xI 0(sޔ7!ab]J]ܬ&Itv)Vkaw[ܓT+rYԄQVi5FBk -}j|E82ui*?W90FU3t.7kT}ƨ!A2Fe\"(:ևcɳ(V@AR@]9p:/}ꕛ Z 1TbH6c@ƞ!;%:jrfEZrY#PSBن Jn"łTH@_DoAJNYm6;@`9?PH;#?)lFȲz竪s""0Pӽ=~kMs'=_PI>fD`ߥud/1+9XFKQ&yhLYhPܮMw H65vn- 5륜FǛRXVa) ?$+]eQ:|Fosv>_ CnD<4i?}+x{ݑg<ڪxMx(Y/Gֈro?Jw0ʿ?h`0t2Fٛn7~Ki#f?4l4+ BԲ`W%2It=:p#K⡅ ^AR}IU&(e-72(;ZkJ_.ys/omFWÒw>л 8b#]XőO\fhNs4)-1g|B˰ܪ݊AjL0,мp#פ`$g#-pXGeٮ9FH5sQ6A (VxcJ01f-kku3&52^"O򪷻._*fj.8Q~FxZ!N6HN\ 1-TAːj\qd O( )dZ%wE uyHug}jS⭚%V2- &mP75N銀KN;;gFM\`R62Hѩ;Ng͢4Uz("(ȁB{Ows69mtuRՈwRRӱ4j@61U9g sp>:1n)@iD.ۣuxG'  1gVH2bڤc~:E{b+RѮ Ci%E|A _ VCEUY0T9I"4{Q+OvGLLs.E$K0Qp#>z zи$aVXMl;eF׷#vhBdI]7_7dVaꛀc: ?$]D:wVS@Q[|`9 8*Pߺ?X{QUU7{T1טV u-K я߬BAeH|<(H4UDvv]4*]u:ώ3.E8ި ڪ|:)ZTӼwwN%X!0̚TY|g[@z)f^qS XO.DO;fGJ"ͳ9-9XYOoƠo›çvĿl8rl?F769U#ؕ|KQ.h.%x«1вe| vbSDE%(mNźa.tiqcԉ/~K\p#a8 mshQHrǑ>у~NEIBӹm)-9)-9XYo)-I@hJvP+g; =UL3.(}#N[ asp\'wZׂ!";O !B|jb$˟t_'0T;ԷcyE # -G?(y{: y?ꉻR>=Ɛ畕{$ç; QdTH IDATV*Ɏ[ƅ8:.@'g+:LoƦ:pNNT(oZ`l*wwP]c_He/콎~(L*U"01ƼT'|©>ǥkA ڰ/z6 Umobb‰ vzMxqQaU:]˪0Z8o±t^ڎ7% nzۘm.LagL( Jnig$(SW&PvT+o\DH^}s]qOF}1$ :)hDux\c7+轙PACi/n0Vյ'܉XMO jՔ3N>4E~k 0x`lW@l p FV2҂]k5 h5|)Rc1uX`p5nXKW&Nn*\rܬJ ?Xܞg-]q }t}[?~ v9֌kw&- nQy ]xE,Zzq_ \试?ST3_SSU%||l%J#oϫ~V'_D6&: A@ch*Tx+oΕ .T&}og$'H4M#J|deDֽ &=T+D&uš@Cm=#qۋԄ VFɻ`yeBHtkڄPUkE X@`*0;0A\濂hꪺܟei34Z"Ff ^%]H1O*ғvK qo<~vZ搠- 1*y8XQxrqj>8 3(C $:gp [͢E9zޱ~)ndw6&<4Pi>ȶX#,Z]$å6qs 34U7<*lBd"ܶj<|wTu2Z'7l{ѵ{ qG`)jEr3sRtVno3t1V,/NŌ<ٮ8:`^aW,ͷO:m &6LVQ-T\RAIgƨҺ(9mĶFΙ)TP VQ1#!X -cl)^fֽ']wk(jy8*#pPs t2TDjewj$44,%[.!^'J53C;}z,FN[`(;߲ÜJ?(~{t雏!7j&(S07j&8nXMl}(kup8+߿cJ/U { UP :_}`5B#SM}c>U z*Il:Ңïo))7-}Fx |ZorRp>Am\}V{oGrR:վYAǿIgk?d sWFIIUC}ZwND>5{NLmgi:ȱ`KF2HS-mfCkr(aQ`^5nЏIUfDi4 A JU3BiJJFߺ}*p0LH+B1ׯO17CT? M V5FB;Tis2X;B8u%t dVލ]xr Pَ` Ȓ۰0hFL|7I!wcW\<~OlŽկg2JWwkh?a'QLkbW(jlGO)0z&-PY\Q/o`Z;8KcWIu&hd<wn5jY ƨ4@>`cHH7CUs~RA }D2PozAu'z _GGEQx[ ϸݒbQcToF- `?*n5Vw3EiZC/|'9_\3>EQM35S!T$qr4'qE :a'kqV*TM/9҉Sto9N=xXKPj3UWkD\j cҽMAVa[(%Iǽ ?\s9lTǾ|ʁx)|_~[Gs77>~ ]oN-v*x&ܱS=6>!:I;޸~?Qk~bur1wJpd(Zw˧Ua] &4n/-8 ӵ2BU[2( N5YN>ד5Mj2ގ8j5[y ׷',~M6H/LtS0azB]]tQn+|N1:%5qE{i+|dWʋ[5Fa:â(ƭ=;\J(OrT&b:c'A7 Lbt8y^|b} *k7+'QeF򝥧hT0N zgQfԾgq7]"c?Fq2[7a6o{4QomDž_Huzn w9$^uqM봜pZG翨+y?t=($~3q{k捉c˛Q4&bstnM~$Ipe`'g>n)US]Xs>Uq_E_qMb5e:XeKS.@o'&_U7 k%et&o u| rK?z(R+5p 3:-?)'eT!Oq!{[N)'3~r5ArIptV|'ޯ)'%nMkݶeޏefDi?V(EYY$g~"#9I14‹ ˛[AH[Z|Bdșc%붋g#}vXS?4 )-ޅ@ľD\_ZUO 8B[e@eX !f,A/̻X@|V!Z)z4 N(qçZ-Mmx?v:Lˠq@Vo/43UL/-9-/uW~nA1ؠh@Wrq_ rRt'ZVdte}ûכ^U-=A7*K!Mmu)(Π+SXx#MC _bצ'-!hy4BoݧY[tה/mw>(Td9+#i >z4HI[zדn41O'%Y΢lI+RdF1JxX]x ]1nݴCy~oIj/)[).Pw-RtP_Ecb%Y t ;Ae7 ƭBo'Tnm'KQ]g/C {;>7Y{9p;7w7CpEq/Ouω)PN^8'=Dj]!o/7⓷ᱲ#w=ӗ@뚛Zw17t)bojopƧj Tm=Gу[w{~ R(=~^uqM.QΛ;/GXtʗÒ+1fR;ߟ6߈l`gd=sO`l)^ddddLh MVFO@FJN칹}𸑃D/a8ݮ8/g;O!N- '!w ~໹?|wsgdĠ x73ʲjFTUF+ނY_O5`x3܅fT TI>?+IœwѦj/i;4KaR[4|;fpD&fILY? e) EB~[bǑb8 e 0=ȁb@JC4;%wC.u݆[_)(LR4EKa]'Pd[܃팶ܲp^ B7=`,U/ zNQcG=}VzRo0sbrㆬqp?5J\Mh?kM=0')֌kIa6 :זq- b\7ZMMVT9 |wōo)y˗qcrrS8~Tߊ9oddxFrHNКv8;bb~@ozPFbz:>1vamt,s_+_ 䌧0:S;ֹNY/N%"hkP^EQ"' 8n8(si~);u)5N,6~N&0z:eFu}SRû%ML}4jwNUJ[b,WghDjl7VkwUcN/r_=b7H hsﹾ! q:#{B*f=, FoM {fw`c-M74ɪ&7lї,w}F,qcܐM6dgo'{o||{F#&lQ0NX U™鑝/awݾ`ͭ=9Wն`Ɋ;?: w%<,}6Dꞛ;θy9qJ8<z`m|S⎛j_㦖OUKGQ_z\o+ # ?jΝe[oo~,QUя6(|'zCmɗ_̫m> (ZϹ۟'LvƛUgmMW:wꙀ5\ ::?w;_nq3)9iaWfw{=K+="j,DoER9#ߢom;oɎs'G;5#K4yv O߈mq#Nf7ТдpáieZYiaNB_nN6b-f׶;kfUxW/ǁtyMRC3»R-R2#4\{|N|yW=d"`: t֢7Jw1 Yxd+ߛ /W{AŗXO2g߀`5^ )T&'Svo!&TzrWdz!m&1S.cxFy y$<+O'@[2{S*'dHFFN@?1SƸb̼nÌ|uqR$x 𓻿KfAqt7nA9{l1<"ībO *Eǹq bq*){Fm.EGW?l/T\%W?lߑW/:I^N]Q7UJ=)|td?Wv[I3. pxKSFy@* {`=>ZkZg=N~^q+qIcRX1tdvo9&CE/geHncuTmO;Y8a@326p>/(٢?B$V]WmAkYvkxn2l\+-#ofnuH,B=[h=@Mku>غ81/,Co4nhl1AڞrX:xMs[$'kF5@?.nb~$|+m1c`#!3b^?x^gy[tGX[<ΰ(w ]踇˒Voko4F8Z}xo(v?wZF IDATYr؍{2`g^Oba| FǝWL)ec>s:v):.ԣ_)oK<&y:o#&=6`E\rҐ|{i0o ̸myMҗd{I13338rاP4Zfj0GV@kd4TӇ J̸  3X)TƎ?QEjVʶ$n LV5% s.| ]` gbu5RsVjXY`Qc KW\+CB\FE@?98 ;oy㖑s@!bqedrOT?X&e{ ^N`Yۘ#_ CȦ@X폴d?9 n"[*.P8wg3v>gjE'G[-a1z%,dYRę sȰox#+71=Sz%?`iYy>; ȘF[> lg̿\L#-Kv#Iő^ ~:)SQ_"83;n>/r=;No^cADv7p~I&~/II7sBN} @v8NK |55mIDnf\c Q?:0Dpo9aDAJE;t9p{\̳UIβ$=^ Eyt8,z_(Yk~_mjmǨ+lP:I``% ы?,2NǓos`o(:uS|)wX_8o4##v}qeq>W+|xWbM|8ncG9a< 8u|fPyk@9X"DX\k&['g< ^/efx > +!?k,^㚃%RIt~r t~M /+9X^{1WpC7#ɽ%-"ɕ7noyI1p$9$K\&##7@QŞo~Xܽ` z9|ko~PoD<"`y0nޥT b6ߓWKGz15RD]aom-nzm![? rSZ|sQ8&oYsSVxGy3>i:#]W޵5t.ݜޅtB'ۏҰ vBy d'sntet3 JD io. ]y☼dm΍Y#]q'pj/w1=[rG9b{#sƿ'Ǩ52H:V2&Pά d> 8*_!~O5#EHoqy3-%]o͜c\h3[yտ3wv}Ucۚd4+U+'k}8^Nf^;}9}+ @~mqiC{@Y%HQ8wНϜ|n#?;lz 2=Y%7;bYt'3}95J~{R`Ur_S*7UH7(e~ =~L}-R{@~$r6{`Js;%Z8~#K|=n0"aj,OzkշϷ'{* ptU0n尼r&!+[RҦ{f;] 5Xu4~j+gaƟNғY4<2 E  '(e{Fxt5́긅`uq"!+Aow&и䟴Ҧ_f>dO2gǧpY޸7_)ݜ3~<]v:X؟#dI\XX6pڱwmDJqj} _ B8"sIyI1[X |Ӗ/.\yD􋁡EymJ7Ra) ;3D)8?R<8[FFȷ)|Sqķ"o"|+H!-; ~$O[tþH*'"C!Q姅''87i7P"Q煀 PVrWBRpdkgFF'.@ݱAEbk|Pp~r !ZōO%"w?{Y |{jT~nfJToĿmō0]@:& 5S~JzʺRȷ~ [o<[TQ7U豁&omXBi0ggՈngų_wf#%. ӟ -\}2=wlubxq+S$# 8ۆE]aƓ8n:ncum}A6>eL yʬ_OyYـp/wxO ky/bw(Oky ~hK9oO 10.3.3 RCU Linux-Kernel API


10.3.3 RCU Linux-Kernel API

This section looks at RCU from the viewpoint of its Linux-kernel API. Section [*] presents RCU's wait-to-finish APIs, and Section [*] presents RCU's publish-subscribe and version-maintenance APIs. Finally, Section [*] presents concluding remarks.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img86.png0000644000175000017500000000107311672746120015232 0ustar paulmckpaulmckPNG  IHDRC(^0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDATX혱NP(HE6 1Hoĸ8@IG]J4 XhZi/_喓i@ljB缠}ȕeN+B b 5`爑3Fci0ϰRLW`Ƚ^RgG6D7mUE'3ȍwxa625KXun >e~W< G\*.M u?:zFaJǴFbs¸d٥\z"w o)XWN  (Et1z\|ӼlMD5 C.4.2 Invalidate Queues and Invalidate Acknowledge


C.4.2 Invalidate Queues and Invalidate Acknowledge

Figure [*] shows a system with invalidate queues. A CPU with an invalidate queue may acknowledge an invalidate message as soon as it is placed in the queue, instead of having to wait until the corresponding line is actually invalidated. Of course, the CPU must refer to its invalidate queue when preparing to transmit invalidation messages -- if an entry for the corresponding cache line is in the invalidate queue, the CPU cannot immediately transmit the invalidate message; it must instead wait until the invalidate-queue entry has been processed.

Figure: Caches With Invalidate Queues
\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBfIQ}}

Placing an entry into the invalidate queue is essentially a promise by the CPU to process that entry before transmitting any MESI protocol messages regarding that cache line. As long as the corresponding data structures are not highly contended, the CPU will rarely be inconvenienced by such a promise.

However, the fact that invalidate messages can be buffered in the invalidate queue provides additional opportunity for memory-misordering, as discussed in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/node173.html0000644000175000017500000000427011672746162015650 0ustar paulmckpaulmck 12.1 Tracing


12.1 Tracing



Paul E. McKenney 2011-12-16
perfbook_html/img24.png0000644000175000017500000001047111672746006015227 0ustar paulmckpaulmckPNG  IHDR3PLTE^\\MJK# b``mkkXUV856C@@wuv.*+ݗN-tRNS@fIDATx]ڪ* bӞbifVZ߿e*r˚^z}#LJQի HoKZ\}uZ}O Ep] l[wzO[6@]nG^ФiV(ilEV,>Q}SvQ ('~zzpBv$ă42Vq P=z>$e,kCoe7օՅWIo SS4i ܈ɀ ՋV[QQv)֙>4ISwXmߪ.ܛؔx`b̓r `t̊>k`܍Oyc5Xkص;.IlBYAh]F񈢨Jnx/`z^92 _JVm20# 9~[%/:˭6y\ M`I8M,X[:^O/O&Ko}d.!Ж"X׃ElhV]c_7-krR }d&- =HҚ#CG9'9'CiHANA;-Z+tZs9 \ D*k5MzUdon4EP\)"l#; t<*?]~Q"O#*F2#wz'b82Z:қ:FT`Crܒ1졀"bLxO3͆3Eh`eYt*|N tf ;RQ(5[D- Fv{M.G@[F[菎Q8l$*㵑g1o͠cGtLX dbMN:).l6ZJvgS$`m8~ސa:X<y Cm\I}B ?YW֤i~X/̑|?=JKL<[웚="k%B*kt+@U.>*+r<^Oɜ3Σxhnk xT!juxFGСcsZ^ ɿq* ilϢ:E񚴴h?QK? DkB}Y~E/x76%DQ} Qf^ѦG "ꤧ^S fMO<{YݥF 4-[VM3\ş7=YecrHystnNy4ԵW1.] y$#=xqu$ =F#6 1_2wؓ!qXYĦRlq8(^Adh νDR7&}~w٫o r|Sc$~b'd5R3O,A_[5&(K~O2-;)Ḷ*>]B7É0؝$+u{X8q|P.E˰%MqAx[ M{G͘|y9(K5cPo5?1rn3c:u|ġ jW'G-N $/yTm(@zА+/G -HDO2C)9 hLL&=cN$Z |ґM˙j݈hK+mjK2W6@|-o)yU*h=0AyV#uMk,ɥu~gϟMNZu2daMV?{@ |̪W,"htwiXuEdDPWUeM%зŐ:E%d0OW=W彟&_u)E+Kow9J)~n@ o%V90WTT6LXɃ_WesjB+QM"Z+{|Cw?{ǧ%зQZ O\SMLƗ iK*:⩧st4 ݋}%=Ib舨EK*%|ӊFrpho@(^K98:/ {;Q칣ZnC-6-7o4U.-eϛ(yvg A_AپK^ޤYp(g'h)]ތuW|8 DToF&m*cK1cv.գ*GF --#.ݳYԕVf$v)2"iW6DjJ>q_yŝ,]U92DL@22ZQۻ6Z};O ͊jA״¦2Uye{N{?T_#gM{d:Kd?<yC7CÕ}zg\'$>ỜN uY%O%-⵲b\yX[tv>zڲ~s) [S |g&8(~8A(BazMbϴedΜW=4 ^zᴽt]hGQ/'h֝ e1eZr{ۍm{Df!oTIݣ:*CU&Y+/BU]סxb]dyMx^YfK0.̷65ޒootjs[~> X7.KįEtqf2u IoUHr2tz PBU?vąY%9oE\|jnqgƪ 兹bӳ*xF~IJXt@\B?-R3qW[h5%(ρ+꫼e"ZO*`o4W/o2C4$CRqyP3S sR'WqK!htkc5=rWz@|r1w(yn.쏳疏aS΢y<;Qb߹Ǭ{ffȩk31 <ȘF"NfJN֯a_v"Ѱ4M"5yrpf#ߵM IndkBN ʩqi%c.ʾDG{6o JM"c!$=>~B6TM_A۔Dxp8[;1T`\WYr 8t>Ŷ 6yk:[՗Q=zK*XBN.XQtQ3ZI%MeQoW8ӥ6|Gyۏ>Ӷ& 1V Z:]r j䵔*)Irqx"Vj5I]6mknY]H{I _H'!+0~Wܺ,msUr }l'觑[JOkHn0WW ^+F΢oK4qEn[#ΌklDLֿ/E %& pR&H^ʼ2CgZ(BG/׿HAuWߞXpsiO2* EDB/+b?YW*,ˋ$㨨 <tOp^Vɑ$ 50GE݆{rK>R=UFEFbb6 EJF_VY':u~TW#։ c Y9r^iiN(yR:5<@=r#w߸NZF D_") 5#}0rDM.Rn*7I?}D_")Ś1n Y92F3HNdˍQTjM^;,yFziȿIENDB`perfbook_html/node35.html0000644000175000017500000001474111672746161015570 0ustar paulmckpaulmck 4.3 Hardware Free Lunch?


4.3 Hardware Free Lunch?

The major reason that concurrency has been receiving so much focus over the past few years is the end of Moore's-Law induced single-threaded performance increases (or ``free lunch'' [Sut08]), as shown in Figure [*] on page [*]. This section briefly surveys a few ways that hardware designers might be able to bring back some form of the ``free lunch''.

However, the preceding section presented some substantial hardware obstacles to exploiting concurrency. One severe physical limitation that hardware designers face is the finite speed of light. As noted in Figure [*] on page [*], light can travel only about an 8-centimeters round trip in a vacuum during the duration of a 1.8 GHz clock period. This distance drops to about 3 centimeters for a 5 GHz clock. Both of these distances are relatively small compared to the size of a modern computer system.

To make matters even worse, electrons in silicon move from three to thirty times more slowly than does light in a vacuum, and common clocked logic constructs run still more slowly, for example, a memory reference may need to wait for a local cache lookup to complete before the request may be passed on to the rest of the system. Furthermore, relatively low speed and high power drivers are required to move electrical signals from one silicon die to another, for example, to communicate between a CPU and main memory.

There are nevertheless some technologies (both hardware and software) that might help improve matters:

  1. 3D integration,
  2. Novel materials and processes,
  3. Substituting light for electrons,
  4. Special-purpose accelerators, and
  5. Existing parallel software.

Each of these is described in one of the following sections.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node27.html0000644000175000017500000001260011672746161015561 0ustar paulmckpaulmck 4.1.2 Memory References


4.1.2 Memory References

In the 1980s, it often took less time for a microprocessor to load a value from memory than it did to execute an instruction. In 2006, a microprocessor might be capable of executing hundreds or even thousands of instructions in the time required to access memory. This disparity is due to the fact that Moore's Law has increased CPU performance at a much greater rate than it has increased memory performance, in part due to the rate at which memory sizes have grown. For example, a typical 1970s minicomputer might have 4KB (yes, kilobytes, not megabytes, let alone gigabytes) of main memory, with single-cycle access. In 2008, CPU designers still can construct a 4KB memory with single-cycle access, even on systems with multi-GHz clock frequencies. And in fact they frequently do construct such memories, but they now call them ``level-0 caches''.

Although the large caches found on modern microprocessors can do quite a bit to help combat memory-access latencies, these caches require highly predictable data-access patterns to successfully hide memory latencies. Unfortunately, common operations, such as traversing a linked list, have extremely unpredictable memory-access patterns -- after all, if the pattern was predictable, us software types would not bother with the pointers, right?

Figure: CPU Meets a Memory Reference
\resizebox{3in}{!}{\includegraphics{cartoons/ref}}

Therefore, as shown in Figure [*], memory references are often severe obstacles for modern CPUs.

Thus far, we have only been considering obstacles that can arise during a given CPU's execution of single-threaded code. Multi-threading presents additional obstacles to the CPU, as described in the following sections.

Paul E. McKenney 2011-12-16
perfbook_html/img150.png0000644000175000017500000000042611672745767015323 0ustar paulmckpaulmckPNG  IHDR$!0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDATc```g Xk |&^. y.8`aXZX@ $ ( hd@Nb^ `+<& !Jkx'@,t2Cg 8lAIENDB`perfbook_html/img46.png0000644000175000017500000003012511672746031015227 0ustar paulmckpaulmckPNG  IHDRx \EPLTEb``\ZZMJK# hffmkkXUV856iffC@@A>>wuv.*+-**|zzrppm˒DtRNS@f IDATx]ՃڀG3LUZ*^cԝىD.UUEl@Um9u=DZ +7 ~h"P)Z,;Gd^"1ERM_aMݩU) $9Irt0O2㘆Xb5><u]׺=ĦB@o2I,D`Sm=_ʨ1{WC~CF7"c"δm#E#|GcH3OTepm KiiUyL蠭9^kWB%y 2ucLGh{(n&iES MmMɈ'ZJ$1n4L]J' EUڈٟMh8\9JF9 j4Gcl)VBd_JL926D` kMBWrDmk ['@Kx'[΅+scQÂcA Z~ZV}Q޳n>9u|ƍ5n0fl{)=S5vTv)4 jtַ)zI@39@֑(#TQ䈩aVLgZӼ2"]y5=laHJyc#Ui09i~Z͕5A%c)֎3A ղ,3ܧ"r6F~R=$aV<4mK e{~H?,=z~!r9F tWruxp, Pڍ 1Ty^X[4>M{  O`]clR+'9\JwMr@cMh}A)Th\sT $f AFCthF.X^^(;.j%ʨѴ_طGߎQgv(%sNJRd|A?wK,J܆1T'M2So݄cqZA~QT%0e:_@A^IU@\͗Kmk_^eĜI)aBTӾkAaѦc$ 4?(K!E̝J}摿p- b*{ 4x+ح+ˬ*9ZWGNmcأyqlh%Bs8Sp "9oey[ZY(KZlO`HߢR k#/m >,!t+r3[#nւ9_' P`ulvwR洵wkί2#! ǡ,m15u=zLD3T'꺻J QU4)H ΫNMC̩[X9v$.ڛtv$W,L&4heJV[,.,k'^a CtmO@.%Z=?ZZ } Gcpqb,j|(ӿފ*"~ ' ΆbT&W.m !0).Xi7RV+wEIQ65nnHtN]|a%v2!ȎK]K8Ek`MdPv}paC&I Lx/ve/Zcm;EŲW*VR NbBDBXx܆7*j]4YN2Αu)զyC⦪ n7lIDWtߍv#j:c1/,@(1*Ajy0ۇa1~B.a wdp̱=G aAZRp}ݼDHMY1B- E=HV(E}ݜ*SIv`>R0X4 VRAkK窸AgR쁨F;|X>l6:bce M a郬c;XYN_a*5f,Hz=L4 @aio>YN]' ݈Wb^J|:I92hrP 6zLN$v&am/ _C ib#ru@vO$ ۫cӑȄsQѯ7YkFZfRl2 貪BRt8^4 tIM( )+* y>lM>22nٸKa +*ڱU){\:t¯A& Z@I!x!R bmNޤ4mF-Jd]:KӽefJ0` KB"OpFKYYKܻe_F?:)?߸r[}I; 'J W8Ht؇8pm30l`ᨥ ]{ۘ) K&V]ш8e*3 JW^ $ ֬\&!FY῕#=er~tirQR\`tLY.?K l"ҿnr0Mڿ ܦ۔)`oW.!(Bkܠ,we0x`?R~*>oI3-t-.Xn`L3Ux\zw%͆V cuUxz$?[2RZL%2-l ]Wl^RnJ.}Y3*q23%,!+0_;9sW|*ƎD2Z+gڱ/chP;eQ ?FLbr8!3MqY3**|aqψR/dٔ:ߐ3 a ȴz $gTb7DgH`.ڽGfh`_crcDH)1bE`Т1g@/ + /_B#VڽwK4C/'Qx^"WtϨbrs(4)ʌM8٘5xFx~76݁=;31QΊir~zjlddlbǤu0)[gBP5OpMQɘL@ l̉J٘㣮ŹFǣfos"̥r'hXڱ9 ů i24!/uIDZn2LK j( t-~º$ F~5<d]Y&,_\_\F%DpcF,O#gw 6ă~CKy0C )[6wJvtY. 抁>`>2]qLtuEt1P\~,\(()ĸ HkCLwZiծM=z\˾&eމsuXee!ޒϫM|e%JXʌt&4MޯǥOE\ uXxF#/u;n]ӸFF偣͍%*]s03*)d#uAn|,>[՘{0+ t,-l3MeQjdy2&;;; d[&Ε?9%zx)2G6?i>S{csb (Pi31|j׻|v:xL R"Ȋ6Yb+f~!uVLs]s4->I5=h5+~+Y.뻬7Ij/~cV\s*7vCjs?aȧEbyyڭ"ħ nM=zJREDs-KX%sRJYg!~։0.ؗB]?=85jF{_<Êo_}(C4 B]QxzA-Z͊-~$ER 3:m:DdfDf73H?;/2LO:FK32jPݿXNAtE&f~u8oGe{C(m9 UG:fWE wU270ni0Z `blPtV2%9SZzZBFpan_b vEʦˢ{5Q%郷2x#BkZ|o>y߲29$H:֊&o7 eqw_n]$&xH\ZZyq0#S'1ru\Ff:7+P=t}?Q"ahaYuHUeؑ4ukj\c# G (DRV]: 0Z\>uA]2VNi 0V/Za:DaJJFTDHLwgLZs&n" _~%$(DjE@$بk+h'&=3぀S_ pSr1t+ _ᤦ˝];èGMk赪~_U@ C!٘GMTFic25 Z'}>ٻp*[Ghcr5Yr.1S:mEqspd~$ԋ>c1B3Q<}' @ Yp\ ;/fwZ,:((OʲyɏIOш"o0/\nn v{^b^$y!eyɑ[d^ZVFb^yzyh@y*{ZT\)Q!<^$fT ɇ]\˼`K݁aP>jCx<ˍ: !UrC7)]уc\i݊ >+BJҿ\ >NQñ^Xd [?"{sE~$-.c{AX(M~-动lq$牬rE@)߫-^?ZAŌyrE$jVw[Ai;yRsuNGsEqUY(1qz71F,WPkrEX+^pk.5?\?9W5L/ʥkV'W"W劐e\d +bO sEksEn"]+ei{rEJ<抸b&Vؘ, 1G}j܏haӽL/>5GuO fvGY\?0sܧ@k懲ھXmFn7t_9 fX2R+M5ߌɷT1džY *A2i{#?cryY漥Ij{35 Y ~4uԑK QOMU1Gؗ|U[81ok:]8UX.U{}㍆Gi}G~4ȹ&O-bnxΕqs++dC=&?+o;z\~q9ZP[@`:2!j>a{S-ȣ@!4evɽ@W0-P HĜ`Ϛ|y!l`^Z3\C0żJ"0/9żJ"+}HMl5sr˥107v~G~$%%jse < ZG~ΫK/@pu!-Iu|8~Qji!zdK V5P!J%tmPh` D1(fDeZz9Ԭ*GFjh݁(ձ_Xw7oY,JGf KxW#LKa@q'6TR:mfJ2 WGwZ-l)K9WnPjWNoA˼s ӯy^oc'˃8xYK4 BR݀`X~9KlI4[@뜶4E9[4J x,ZJ1Ev6Z؞C*>wz!EЏ:.{{=xa dΕ1}'sH5K%Do,4;9W;Mei1L$*(\}66RRDŞhgml~ {'1N +9Tdp!cٖ% |R r`9T&ϓ:1%n~tL`01hV=b;{ZR6*װ6viU!B,c'̈́Al )&ډ1ЧENr㘮e,^!V4)+QS,c'̈́VHWg$Ϩ/wl#LFW ȞC1YXWͮ4w``NXCL^FUsг޲:IZM;.O* l)E ZXkc'V@("{69P?`hŷ 2>n{aOuT8<|IxAፗv b%PTj+;$oS ܟSWJH熕0,?˻|R)ޡ[y܇ P꿨]d S(:ןZT} WBr}]8%dP+]iIHA*"4*71("y͍&k!sE 2OiwKF۷v._9"'i!j3"xG,_'6>lL9mE.m\懖-|#6YrIDAT)7K--J{wH kV}f;M%ޯUĎL'Mz UD&6&LvCGD"@xA2[Li!hȺ۬S 9i-ƒ&iQ" [Dp-$Q)Kk#8 ԮĆxPۗ+'okfn`qk*@&]yjڠfո;'Wfڍ^(նA9B7ZIқJ ʑZI,hL% Lh-$=k&fIݻz|02yp,|Fq2s>F%o/Eхs㘫H a1Ã3xGTѱQd(U0ӻ2=܁ueG`UDo*C:sx~~}S3%Cŧ/R)&뉙h D/ɮu!̙fV D~C4j~Ҝ=+LS{N2MNBvœh%LO ~]Gl&ϣ`&z&9֓t[ՑD{'"~԰sTMQlsH&KiL]yIOOW"u DS lV #6&1O,FK}]Ie&_(8+S jGM93\(Jl4װk.|ֳ9h ^oYYoy;w  9j%\HsP(4q߯67-qpG{\[QG򍠕uyB6:O'o xCQgsL\(oӕb%WZ㵚5]:)RZNH*mZX[@{5J)I%#RY9SZYy<>pl*6W̃opY|6(Ij{KX4-~ G|*V lK\QE-M/tQeZ$ W0QKDӂ[!1>x(!M S[8.ѴD>?Ɖ#e'jy[f4-SP4FMKO򶦥KTMˣiy3Q:Rg(%y,'O|y,Ds|~xxeǷ<'-+QUmS兹g5-x:уxHj V_āբ,,>x.P8cD]5-BE=,{@x< K.KPc EM5-\Pl񟇴,%T.TJK:!>@8^/-qZM@j*Q ״p ]/څ! Ya¯Rwc[xrilgL%g&pM _rBϳOrW ֈ- Y6lyR\FjeOGqayn ?uIx(>åcp1LH{k:פ|%w-* c+tMu:ٕۀ0$ lKP^Nf^ט*_W HÞ~e"X oZ6N~?Wwv|'@Tذx/9[H x5[jge⯻3 *Noa"K=Nlf"$*9[zX QI\aOT C&5&L4eaQ9@WT/%p&S;pkFf-lREcS֓ lLH03""-G~H,䃛+9U+3J -c]%'$,L]E-P]@唾e; WWD-_܇WW>x0 OZry.Ѵ\%n=FM i蝤iܼ%2򆚖mM M G!fˈJl󶦅=՗{7wWtTĉ-?:9S[MՏ~7{LgpTZ q`=fJ̧Dd{`#TR:BC2po^8]?C ->g ~N4&\ rЩ> >Q ;u> ZJ |h[0JhhWƤ+Zw@g\}@[Q:@~51g˚׋b0Ɯ-_]Rv&ꜢLT~Qm\KIK7Y-}3u=xpO2KoAw8PcYOdcJ. wp&\]e?j,m<WW(;r=<n녒+/neE'0e6{3gesQ Lyy3]8'TENjoe8k3Qn_ڳ c잭]`x,WJ3Q[:g恤},>} 1 sǻӏ-wcrZ ]FǖvҒ]󾆴x_Zŧ +<5zzv*<|{j.`n_cf. 5hg}(s!=z.+̚b3Еia)l+[ -frebbK&3G[5v\\x WVwWZn׷p|8Tbdn6[x <-.K?`CoaXs-`w#x?@覡'XR6Й4O޹y<8?;^MiIENDB`perfbook_html/node377.html0000644000175000017500000001611311672746163015656 0ustar paulmckpaulmck D.3.3.2 rcu_init_one()


D.3.3.2 rcu_init_one()

Figure: rcu_init_one() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __init rcu_init_one...
... - 1];
32 }
33 rnp->level = i;
34 }
35 }
36 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_init_one(), which does boot-time initialization for the specified rcu_state structure.

Recall from Section [*] that the ->levelcnt[] array in the rcu_state structure is compile-time initialized to the number of nodes at each level of the hierarchy starting from the root, with an additional element in the array initialized to the maximum possible number of CPUs, NR_CPUS. In addition, the first element of the ->level[] array is compile-time initialized to reference to the root rcu_node structure, which is in turn the first element of the ->node[] array in the rcu_state structure. This array is further laid out in breadth-first order. Keeping all of this in mind, the loop at lines 8-10 initializes the rest of the ->level[] array to reference the first rcu_node structure of each level of the rcu_node hierarchy.

Line 11 then invokes rcu_init_levelspread(), which fills in the ->levelspread[] array, as was described in Section [*]. The auxiliary arrays are then fully initialized, and thus ready for the loop from lines 15-35, each pass through which initializes one level of the rcu_node hierarchy, starting from the leaves.

Line 13 computes the number of CPUs per rcu_node structure for the current level of the hierarchy, and line 14 obtains a pointer to the first rcu_node structure on the current level of the hierarchy, in preparation for the loop from lines 15-34, each pass through which initializes one rcu_node structure.

Lines 16-18 initialize the rcu_node structure's spinlock and its CPU masks. The qsmaskinit field will have bits set as CPUs come online later in boot, and the qsmask field will have bits set when the first grace period starts. Line 19 sets the ->grplo field to the number of the this rcu_node structure's first CPU and line 20 sets the ->grphi to the number of this rcu_node structure's last CPU. If the last rcu_node structure on a given level of the hierarchy is only partially full, lines 21 and 22 set its ->grphi field to the number of the last possible CPU in the system.

Lines 24-26 initialize the ->grpnum, ->grpmask, and ->parent fields for the root rcu_node structure, which has no parent, hence the zeroes and NULL. Lines 28-31 initialize these same fields for the rest of the rcu_node structures in the hierarchy. Line 28 computes the ->grpnum field as the index of this rcu_node structure within the set having the same parent, and line 29 sets the corresponding bit in the ->grpmask field. Finally, lines 30-31 places a pointer to the parent node into the ->parent field. These three fields will used to propagate quiescent states up the hierarchy.

Finally, line 33 records the hierarchy level in ->level, which is used for tracing when traversing the full hierarchy.

Paul E. McKenney 2011-12-16
perfbook_html/img223.png0000644000175000017500000000614411672746150015312 0ustar paulmckpaulmckPNG  IHDRJbvxZNHPLTE^\\MJK# b``ywwommmkkcaaXUV856KHHC@@744wuv.*+vttiVUtRNS@f IDATx] E\6r3T,,+WmSxp)u+\eݏoGjko-TЯ5J%<6JU5[ n%ǵ;NϤmKcS`RSbJԽTQswwf& 6ɷ:gP\kƬ(Iy%*$A2H#VM:׈߄Ezdos8y;f(d:èJ]*C(c 0 Y 9U8q8crq>> {Iպ-UXq;SJLQSX(*-XUO,8"K%VCS:0HdfSnS 㾶عbwc+i7$O1;',MߎXՐ=}-;7Qb?x@đm@1ce.vxπк*9D7^*2˸B KB?lm$ ϑ#ؑ˷g,cGh<;'=+/T ?U0r=7\%0 T/X'9 ,$z3AP18J@Nty9.u .ʹ :D]xt-s܎B8S-ACXDs`ph (2;'CiH,Uv+-1^pJˤ*(m7;d>  ZhjDn"2"frX!{x`J-`mK3,2[>BL<^Od܌Dq6p 'I1z =4\WF.CQ'Trm-NU%ZYZ"lqt i.VR[چC'"IL6sqx G:׌\>ٽ Ez_aW'ܓŐhG' $.W \rlK2J2$^)svx_1Wn~錜螃U?a-9pp.L8O klLwnۅ R=^MvRmtciช Џ8ɛ6y#DhpSRk7Nz ? fbA6y _w>Hv +lO]M F Q过L+ܕL8SF[Ӣ(٠{d]Y#,'*77Ww1Hvs9C\*ۦ[[_Z5fV9G,*9kqjܩN2bBzPUC䁜~7WSf7ҧ46'N5 TM7VS4%8-9)~TV4*ۃṴ,nj D d' ^/zK_z,z9\9xkt= 猂sX"+xOg]8>/%0K}J^üRgKCؽ$KH%r zċ Ao_:6nǟJ QZaefMYlk25$g G@ ;-^R?/V_*O78%q@)f=9;J6zPGw^r7e{cKΘ]D:wwS&MhIS,p:1-y Gr3{wXDÖJב ~NBBK K%wJ 焈we wj [tc[jyn>lj @nʢY ORGOwhpW1DwZG|VB6̅ωܒpi8Lcnm:]bUϏFv74t?ħ' /0@Gor;$$hCpXX"|+PB0yWCXpey@{xuLPn,@!_ ly#}_4ߡr?U먎Lq7KPLTEMJKKHIPMM+'(# b``mkka__XUV856C@@@<=wuv.*+rppStRNS@f2IDAThZ& Dbj+;v'/{! BAΘto1"S4ؙ'hJ L7CBv3H_ q۷=V8]?bbFpf7rA6T*UA!frcos)|!lrM'oomwJ8a'[1)[4sE4EwJ%2l9祴R-,Qn䤮G߉ϙk49 z).9愭wL=' ۩㐆RyEM ^$ciHl)؁tZDs;waDƌ +h3PXKU7CbŰ,\{oŮ$ϧPlAJI!!IۥȲ?i*^SgC{[+nj CrX2m hHNK1RGa6Y '5L;bXnlu[O6p\C"EoB$ipl2'B:'q>ɌSqSS7C J+}TU:wu WsdOWea`w$Xzf:-o eYqc.l]_eYbU\jvoʋ,1w.KT0+X f&ߛͻ,$KA M޼z%hݼ(I,}F]Kִ89ɣ/[:+ Œr097ٔ6CX!!U7 $][n6\{kN+.ru|qZi9Ƙj¹{:WmO Kس{^8^sk?ʺ,vy|ПpimQ˒m/E tT's)3蛥8Ssr@qWWu \ ε-ZY/Ԧ[/QS].y\老m_Sh5bSǮ>(WC!CP}WkHЅbDQbs,٭Ǫ]1t9^17Ǽaf?+ IENDB`perfbook_html/labels.pl0000644000175000017500000032354411672746164015413 0ustar paulmckpaulmck# LaTeX2HTML 2008 (1.71) # Associate labels original text with physical files. $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-init-percpu-data/; $external_labels{$key} = "$URL/" . q|node380.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:QRCU_Initialization_Process/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_Nested_Interrupt_Handlers/; $external_labels{$key} = "$URL/" . q|node449.html|; $noresave{$key} = "$nosave"; $key = q/cite_Shavit95/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-check-quiescent-state/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Software_Layers_and_Performance__Productivity__and_Generality/; $external_labels{$key} = "$URL/" . q|node9.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Performance_of_RCU_vs._Reference_Counting/; $external_labels{$key} = "$URL/" . q|node142.html|; $noresave{$key} = "$nosave"; $key = q/cite_MichaelScott2006Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:The_Right_Tool_for_the_Job:_How_to_Choose_/; $external_labels{$key} = "$URL/" . q|node50.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Code-Locking_Hash_Table_Search/; $external_labels{$key} = "$URL/" . q|node86.html|; $noresave{$key} = "$nosave"; $key = q/sec:Composite_Capabilities/; $external_labels{$key} = "$URL/" . q|node19.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Applying_Specialized_Parallel_Counters/; $external_labels{$key} = "$URL/" . q|node71.html|; $noresave{$key} = "$nosave"; $key = q/defer:Starvation-Free_Counter-Based_RCU/; $external_labels{$key} = "$URL/" . q|node158.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:whymb:Memory_Barrier_Example_2/; $external_labels{$key} = "$URL/" . q|node312.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Per-CPU_Data/; $external_labels{$key} = "$URL/" . q|node366.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Multistage_SRCU_Deadlocks/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/defer:RCU_Based_on_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node163.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Introduction_to_Preemptible_RCU_and_dynticks/; $external_labels{$key} = "$URL/" . q|node439.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Alternatives_to_Parallel_Programming/; $external_labels{$key} = "$URL/" . q|node10.html|; $noresave{$key} = "$nosave"; $key = q/cite_SETIatHOME2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Alternative_Approach:_More_Capable_Tools/; $external_labels{$key} = "$URL/" . q|node436.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Update_Using_Per-Thread_Reference-Count_Pair/; $external_labels{$key} = "$URL/" . q|node159.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Design_Criteria/; $external_labels{$key} = "$URL/" . q|node83.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_has_Publish-Subscribe_and_Version-Maintenance_APIs/; $external_labels{$key} = "$URL/" . q|node151.html|; $noresave{$key} = "$nosave"; $key = q/cite_JonathanCorbet2006lockdep/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:CPU-Stall_Detection/; $external_labels{$key} = "$URL/" . q|node399.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Cache-Coherence_Protocols/; $external_labels{$key} = "$URL/" . q|node295.html|; $noresave{$key} = "$nosave"; $key = q/cite_Inman85/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulMcKenney2005i/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Noting_New_Grace_Periods/; $external_labels{$key} = "$URL/" . q|node385.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-online-cpu/; $external_labels{$key} = "$URL/" . q|node381.html|; $noresave{$key} = "$nosave"; $key = q/sec:analysis:Differential_Profiling/; $external_labels{$key} = "$URL/" . q|node178.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Summary/; $external_labels{$key} = "$URL/" . q|node459.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Lists/; $external_labels{$key} = "$URL/" . q|node181.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Brief_Overview_of_Classic_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node344.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator_Cache_Performance/; $external_labels{$key} = "$URL/" . q|node99.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Demonstration_of_Exclusive_Locks/; $external_labels{$key} = "$URL/" . q|node46.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Parallel-Fastpath_Design_Patterns/; $external_labels{$key} = "$URL/" . q|node90.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_record-gp-stall-check-time/; $external_labels{$key} = "$URL/" . q|node399.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_with_Grace-Period_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node418.html|; $noresave{$key} = "$nosave"; $key = q/sec:easy:Rusty_Scale_for_API_Design/; $external_labels{$key} = "$URL/" . q|node245.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Explicit_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node215.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulMcKenney2005d/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Data_for_Quiescent-State-Based_RCU/; $external_labels{$key} = "$URL/" . q|node163.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Handling_Offline_and_Holdout_CPUs/; $external_labels{$key} = "$URL/" . q|node396.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Guarantees/; $external_labels{$key} = "$URL/" . q|node213.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Execution_Diagram_for_Parallel_Shell_Execution/; $external_labels{$key} = "$URL/" . q|node42.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Parable:_dynticks_and_Preemptible_RCU/; $external_labels{$key} = "$URL/" . q|node438.html|; $noresave{$key} = "$nosave"; $key = q/sec:Resource_Partitioning_and_Replication/; $external_labels{$key} = "$URL/" . q|node17.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:SRCU_Summary/; $external_labels{$key} = "$URL/" . q|node341.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:SRCU_Implementation_Strategy/; $external_labels{$key} = "$URL/" . q|node328.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Extra-Transactional_Accesses/; $external_labels{$key} = "$URL/" . q|node254.html|; $noresave{$key} = "$nosave"; $key = q/cite_z80Wikipedia/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Exclusive_Locks/; $external_labels{$key} = "$URL/" . q|node109.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:SRCU_API/; $external_labels{$key} = "$URL/" . q|node331.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Data_Structures_and_Kernel_Parameters/; $external_labels{$key} = "$URL/" . q|node363.html|; $noresave{$key} = "$nosave"; $key = q/cite_TatianaShpeisman2009CppTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney95b/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2008dynticksRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:Reference_Counting_and_Synchronization_Mechanisms/; $external_labels{$key} = "$URL/" . q|node116.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Memory-Barrier_Combinations/; $external_labels{$key} = "$URL/" . q|node196.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:NMIs_from_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node391.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:What_Makes_Parallel_Programming_Hard_/; $external_labels{$key} = "$URL/" . q|node14.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Reader-Writer_Locks/; $external_labels{$key} = "$URL/" . q|node110.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_Limit_Counter_Add_and_Subtract_Functions/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Towards_a_Greener_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node347.html|; $noresave{$key} = "$nosave"; $key = q/sec:deferRCU_is_a_Way_of_Providing_Type-Safe_Memory/; $external_labels{$key} = "$URL/" . q|node146.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:RCU_Desiderata/; $external_labels{$key} = "$URL/" . q|node345.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:SRCU_Cleanup/; $external_labels{$key} = "$URL/" . q|node338.html|; $noresave{$key} = "$nosave"; $key = q/cite_MauriceHerlihy2005-TM-manifesto.pldi/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Counter_Optimizations/; $external_labels{$key} = "$URL/" . q|node123.html|; $noresave{$key} = "$nosave"; $key = q/cite_AMDOpteron02/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Clock-Frequency_Trend_for_Intel_CPUs/; $external_labels{$key} = "$URL/" . q|node7.html|; $noresave{$key} = "$nosave"; $key = q/cite_GordonMoore03a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Linked_List_Abbreviated/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Caches_With_Store_Buffers/; $external_labels{$key} = "$URL/" . q|node301.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Pass_Through_a_Quiescent_State/; $external_labels{$key} = "$URL/" . q|node351.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Writes_See_Unnecessary_Stalls/; $external_labels{$key} = "$URL/" . q|node300.html|; $noresave{$key} = "$nosave"; $key = q/cite_Blundell2005DebunkTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Review_of_RCU_Fundamentals/; $external_labels{$key} = "$URL/" . q|node343.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:SRCU_Initialization/; $external_labels{$key} = "$URL/" . q|node338.html|; $noresave{$key} = "$nosave"; $key = q/tab:cpu:Performance_of_Synchronization_Mechanisms_on_4-CPU_1.8GHz_AMD_Opteron_844_System/; $external_labels{$key} = "$URL/" . q|node34.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Design_Tradeoffs/; $external_labels{$key} = "$URL/" . q|node183.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Reporting_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/cite_CorbetLWN/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Advanced_Synchronization/; $external_labels{$key} = "$URL/" . q|node187.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:RCU_Global_State/; $external_labels{$key} = "$URL/" . q|node367.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Just_Count_Atomically_/; $external_labels{$key} = "$URL/" . q|node52.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Approximate_Limit_Counters/; $external_labels{$key} = "$URL/" . q|node59.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Initialized_RCU_Data_Layout/; $external_labels{$key} = "$URL/" . q|node375.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_Limit_Counter_Initialization_Functions/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator-Cache_Free_Function/; $external_labels{$key} = "$URL/" . q|node98.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Protocol_Layering_and_Deadlock/; $external_labels{$key} = "$URL/" . q|node105.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Per-Thread-Variable-Based_Implementation/; $external_labels{$key} = "$URL/" . q|node57.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Read-Side_Critical_Sections/; $external_labels{$key} = "$URL/" . q|node370.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-offline-cpu/; $external_labels{$key} = "$URL/" . q|node382.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Caches_With_Invalidate_Queues/; $external_labels{$key} = "$URL/" . q|node306.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:MESI_Cache-Coherency_State_Diagram/; $external_labels{$key} = "$URL/" . q|node298.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:whymb:Memory_Barrier_Example_1/; $external_labels{$key} = "$URL/" . q|node311.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007whatisRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_ctrlblk/; $external_labels{$key} = "$URL/" . q|node406.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Initialization_and_Cleanup/; $external_labels{$key} = "$URL/" . q|node332.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Alternative_Approach:_Proof_of_Correctness/; $external_labels{$key} = "$URL/" . q|node435.html|; $noresave{$key} = "$nosave"; $key = q/codesample:advsync:What_Can_You_Count_On__3/; $external_labels{$key} = "$URL/" . q|node208.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator-Cache_Data_Structures/; $external_labels{$key} = "$URL/" . q|node96.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Eventually_Consistent_Implementation/; $external_labels{$key} = "$URL/" . q|node56.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Example:_Non-Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node425.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_read_unlock__/; $external_labels{$key} = "$URL/" . q|node417.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:RCU_State_Machine_and_Hierarchical_RCU_Data_Structures/; $external_labels{$key} = "$URL/" . q|node348.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007PreemptibleRCUPatch/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:applyrcu:RCU_and_Per-Thread-Variable-Based_Statistical_Counters/; $external_labels{$key} = "$URL/" . q|node167.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Ethernet_Bandwidth_vs._Intel_x86_CPU_Performance/; $external_labels{$key} = "$URL/" . q|node85.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_try_flip_waitzero___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Starting_a_Grace_Period/; $external_labels{$key} = "$URL/" . q|node387.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Per-Thread_Statistical_Counters_With_Lockless_Summation/; $external_labels{$key} = "$URL/" . q|node464.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Example_Ordering-Hostile_Architecture/; $external_labels{$key} = "$URL/" . q|node310.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Are_Memory_Barriers_Forever_/; $external_labels{$key} = "$URL/" . q|node324.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcutree_force-quiescent-state/; $external_labels{$key} = "$URL/" . q|node398.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-offline-cpu/; $external_labels{$key} = "$URL/" . q|node382.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Performance_Advantage_of_RCU_Over_Reader-Writer_Locking/; $external_labels{$key} = "$URL/" . q|node135.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Exact_Limit_Counters/; $external_labels{$key} = "$URL/" . q|node65.html|; $noresave{$key} = "$nosave"; $key = q/tab:count:Limit_Counter_Performance_on_Power_5/; $external_labels{$key} = "$URL/" . q|node72.html|; $noresave{$key} = "$nosave"; $key = q/cite_Volos2008TRANSACT/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:whymb:Memory_Barrier_Example_3/; $external_labels{$key} = "$URL/" . q|node313.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Hierarchical_RCU_Overview/; $external_labels{$key} = "$URL/" . q|node342.html|; $noresave{$key} = "$nosave"; $key = q/cite_PowerPC94/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Memory_Usage_of_QRCU_Model/; $external_labels{$key} = "$URL/" . q|node433.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Deadlock_Cycle/; $external_labels{$key} = "$URL/" . q|node104.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Noting_End_of_Old_Grace_Periods/; $external_labels{$key} = "$URL/" . q|node386.html|; $noresave{$key} = "$nosave"; $key = q/cite_MagedMichael04a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Initialization/; $external_labels{$key} = "$URL/" . q|node375.html|; $noresave{$key} = "$nosave"; $key = q/cite_HansJBoehm2009HOTPAR/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_Rajwar01a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Detect_a_Too-Long_Grace_Period/; $external_labels{$key} = "$URL/" . q|node359.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-init-levelspread/; $external_labels{$key} = "$URL/" . q|node376.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Simple_Reference-Count_API/; $external_labels{$key} = "$URL/" . q|node118.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:State_Variables_for_Simplified_Dynticks_Interface/; $external_labels{$key} = "$URL/" . q|node453.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_is_a_Way_of_Providing_Existence_Guarantees/; $external_labels{$key} = "$URL/" . q|node145.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_Usage/; $external_labels{$key} = "$URL/" . q|node133.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Data_Structure_Publication__Unsafe_/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:What_Can_You_Trust_/; $external_labels{$key} = "$URL/" . q|node193.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-init-one/; $external_labels{$key} = "$URL/" . q|node377.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Entering_and_Exiting_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node390.html|; $noresave{$key} = "$nosave"; $key = q/chp:defer:Deferred_Processing/; $external_labels{$key} = "$URL/" . q|node114.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:Atomic_Operations/; $external_labels{$key} = "$URL/" . q|node48.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Example_Child_Thread/; $external_labels{$key} = "$URL/" . q|node278.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-do-batch/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Scanning_Leaf_rcu-node_Structures/; $external_labels{$key} = "$URL/" . q|node397.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney92b/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Partitioning_Exercises/; $external_labels{$key} = "$URL/" . q|node74.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Data-Locking_Hash_Table_Search/; $external_labels{$key} = "$URL/" . q|node87.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Locking:_Workhorse_or_Hero_/; $external_labels{$key} = "$URL/" . q|node102.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Performance_Optimization/; $external_labels{$key} = "$URL/" . q|node13.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-needs-cpu_and_rcu-cpu-notify/; $external_labels{$key} = "$URL/" . q|node374.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Possible_Flaws_and_Changes/; $external_labels{$key} = "$URL/" . q|node400.html|; $noresave{$key} = "$nosave"; $key = q/cite_ScottGriffen2000/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Pipelined_CPUs/; $external_labels{$key} = "$URL/" . q|node26.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Nestable_RCU_Using_a_Free-Running_Counter/; $external_labels{$key} = "$URL/" . q|node162.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Bits_and_Bytes/; $external_labels{$key} = "$URL/" . q|node185.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Array-Based_Per-Thread_Eventually_Consistent_Counters/; $external_labels{$key} = "$URL/" . q|node56.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Data_Locking/; $external_labels{$key} = "$URL/" . q|node87.html|; $noresave{$key} = "$nosave"; $key = q/cite_DouglasEngelbart1968/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Hierarchical-Locking_Hash_Table_Search/; $external_labels{$key} = "$URL/" . q|node92.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Memory_Ordering_and_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node190.html|; $noresave{$key} = "$nosave"; $key = q/cite_CorbetRubiniKroahHartman/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Data_for_Free-Running_Counter_Using_RCU/; $external_labels{$key} = "$URL/" . q|node161.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulMcKenney2005j/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Hierarchical_RCU_Code_Walkthrough/; $external_labels{$key} = "$URL/" . q|node362.html|; $noresave{$key} = "$nosave"; $key = q/sec:Parallel_Access_Control/; $external_labels{$key} = "$URL/" . q|node16.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Work_Partitioning/; $external_labels{$key} = "$URL/" . q|node15.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Hardware_Free_Lunch_/; $external_labels{$key} = "$URL/" . q|node35.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_print-cpu-stall/; $external_labels{$key} = "$URL/" . q|node399.html|; $noresave{$key} = "$nosave"; $key = q/cite_ManfredSpraul2008dyntickIRQNMI/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Simple_Limit_Counter_Utility_Functions/; $external_labels{$key} = "$URL/" . q|node61.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Scanning_for_Holdout_CPUs/; $external_labels{$key} = "$URL/" . q|node397.html|; $noresave{$key} = "$nosave"; $key = q/cite_YossiLev2009SNZIrwlock/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/defer:Scalable_Counter-Based_RCU/; $external_labels{$key} = "$URL/" . q|node159.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney01e/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Processes_Created_Via_fork___Do_Not_Share_Memory/; $external_labels{$key} = "$URL/" . q|node44.html|; $noresave{$key} = "$nosave"; $key = q/cite_Martinez01a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_HMassalinPhD/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Memory-Mapping_Operations/; $external_labels{$key} = "$URL/" . q|node252.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Atomic_Limit_Counter_Read/; $external_labels{$key} = "$URL/" . q|node66.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Noting_End_of_Old_Grace_Periods/; $external_labels{$key} = "$URL/" . q|node386.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:RCU_Publish_and_Subscribe_Primitives/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Generic_RCU_State_Machine/; $external_labels{$key} = "$URL/" . q|node348.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_Callback_Flow/; $external_labels{$key} = "$URL/" . q|node407.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_Liveness/; $external_labels{$key} = "$URL/" . q|node446.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Why_Isn_t_Concurrent_Counting_Trivial_/; $external_labels{$key} = "$URL/" . q|node52.html|; $noresave{$key} = "$nosave"; $key = q/cite_MichaelLyons02a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Announce_a_Quiescent_State_to_RCU/; $external_labels{$key} = "$URL/" . q|node352.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Atomic_Operations/; $external_labels{$key} = "$URL/" . q|node28.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:MESI_State_Diagram/; $external_labels{$key} = "$URL/" . q|node298.html|; $noresave{$key} = "$nosave"; $key = q/cite_Garg90/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator_Cache_Schematic/; $external_labels{$key} = "$URL/" . q|node95.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Canonical_RCU_Replacement_Example/; $external_labels{$key} = "$URL/" . q|node127.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Read-Side_Using_Per-Thread_Reference-Count_Pair_and_Shared_Update/; $external_labels{$key} = "$URL/" . q|node160.html|; $noresave{$key} = "$nosave"; $key = q/cite_BryanGardiner2007/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_Limit_Counter_Value-Migration_Functions/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Per-Thread-Variable_API/; $external_labels{$key} = "$URL/" . q|node285.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007WhatIsRCUFundamentally/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Compound_Double-Ended_Queue/; $external_labels{$key} = "$URL/" . q|node78.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Safe_Insert_and_Lock-Free_Search/; $external_labels{$key} = "$URL/" . q|node315.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Modern_Computer_System_Cache_Structure/; $external_labels{$key} = "$URL/" . q|node294.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Barriers/; $external_labels{$key} = "$URL/" . q|node115.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Approximate_Limit_Counter_Implementation/; $external_labels{$key} = "$URL/" . q|node63.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Per-Thread_Variables/; $external_labels{$key} = "$URL/" . q|node285.html|; $noresave{$key} = "$nosave"; $key = q/_1/; $external_labels{$key} = "$URL/" . q|perfbook_html.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_has_a_Family_of_Wait-to-Finish_APIs/; $external_labels{$key} = "$URL/" . q|node150.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Online_a_CPU/; $external_labels{$key} = "$URL/" . q|node358.html|; $noresave{$key} = "$nosave"; $key = q/chp:Counting/; $external_labels{$key} = "$URL/" . q|node51.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:SRCU_Data_Structures/; $external_labels{$key} = "$URL/" . q|node337.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Review_of_Locking_Implementations/; $external_labels{$key} = "$URL/" . q|node209.html|; $noresave{$key} = "$nosave"; $key = q/cite_Gharachorloo95/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Kernel_dst-clone_API/; $external_labels{$key} = "$URL/" . q|node120.html|; $noresave{$key} = "$nosave"; $key = q/cite_LorinHochstein2005SC/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Ordering_With_Multiple_CPUs_on_One_Lock/; $external_labels{$key} = "$URL/" . q|node235.html|; $noresave{$key} = "$nosave"; $key = q/cite_RyanEccles2006HPCSNoviceNeeds/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Read-Side_Implementation/; $external_labels{$key} = "$URL/" . q|node339.html|; $noresave{$key} = "$nosave"; $key = q/sec:applyrcu:RCU_and_Counters_for_Removable_I_O_Devices/; $external_labels{$key} = "$URL/" . q|node171.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Memory_References/; $external_labels{$key} = "$URL/" . q|node27.html|; $noresave{$key} = "$nosave"; $key = q/cha:Partitioning_and_Synchronization_Design/; $external_labels{$key} = "$URL/" . q|node73.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Implementation_Using_Single_Global_Reference_Counter/; $external_labels{$key} = "$URL/" . q|node157.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Hashed_Double-Ended_Queue/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Simple_Counting/; $external_labels{$key} = "$URL/" . q|node118.html|; $noresave{$key} = "$nosave"; $key = q/cite_Reinders2007Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:How_Do_Languages_and_Environments_Assist_With_These_Tasks_/; $external_labels{$key} = "$URL/" . q|node20.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Atomic_Limit_Counter_Variables_and_Access_Functions/; $external_labels{$key} = "$URL/" . q|node66.html|; $noresave{$key} = "$nosave"; $key = q/cite_DougLea1997Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_Fundamentals/; $external_labels{$key} = "$URL/" . q|node125.html|; $noresave{$key} = "$nosave"; $key = q/cite_Ali-Reza-Adl-Tabatabai2009CppTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Existing_Parallel_Software/; $external_labels{$key} = "$URL/" . q|node39.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Avoiding_Deadlock_Via_Conditional_Locking/; $external_labels{$key} = "$URL/" . q|node104.html|; $noresave{$key} = "$nosave"; $key = q/cite_IntelItanium02v3/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/codesample:advsync:Naive_Lock_and_Unlock_Pseudocode/; $external_labels{$key} = "$URL/" . q|node209.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney04a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenneyN2745r2009/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:POWER___Power_PC/; $external_labels{$key} = "$URL/" . q|node320.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_try_flip_flag/; $external_labels{$key} = "$URL/" . q|node410.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Ordering_of_Parallel-Programming_Tasks/; $external_labels{$key} = "$URL/" . q|node19.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Read-Copy_Update_Implementations/; $external_labels{$key} = "$URL/" . q|node326.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Synchronization_Efficiency/; $external_labels{$key} = "$URL/" . q|node89.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Sleepable_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node327.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:QRCU_Global_Variables/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:RPC_Operations/; $external_labels{$key} = "$URL/" . q|node251.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator-Cache_Allocator_Function/; $external_labels{$key} = "$URL/" . q|node97.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Using_the_wait___Primitive/; $external_labels{$key} = "$URL/" . q|node44.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Per-Thread_Reference-Count_Pair_Data/; $external_labels{$key} = "$URL/" . q|node159.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Transactional_Memory/; $external_labels{$key} = "$URL/" . q|node249.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Using_RCU_to_Wait_for_NMIs_to_Finish/; $external_labels{$key} = "$URL/" . q|node147.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Guide_to_This_Book/; $external_labels{$key} = "$URL/" . q|node21.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Partitioning_Example_Discussion/; $external_labels{$key} = "$URL/" . q|node82.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Code_for_force-quiescent-state/; $external_labels{$key} = "$URL/" . q|node398.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:NMI_from_Dynticks_Idle_Mode/; $external_labels{$key} = "$URL/" . q|node355.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Atomic_Data_Structures/; $external_labels{$key} = "$URL/" . q|node242.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Note_That_a_CPU_is_in_Dynticks_Idle_Mode/; $external_labels{$key} = "$URL/" . q|node356.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Cleaning_Up_Safely/; $external_labels{$key} = "$URL/" . q|node335.html|; $noresave{$key} = "$nosave"; $key = q/cite_TheOpenGroup1997SUS/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:SMP_Barrier_Pairing/; $external_labels{$key} = "$URL/" . q|node226.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Update-Side_Implementation/; $external_labels{$key} = "$URL/" . q|node340.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_print-other-cpu-stall/; $external_labels{$key} = "$URL/" . q|node399.html|; $noresave{$key} = "$nosave"; $key = q/defer:Per-Thread_Lock-Based_RCU/; $external_labels{$key} = "$URL/" . q|node156.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:MESI_States/; $external_labels{$key} = "$URL/" . q|node296.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:whymb:Summary_of_Memory_Ordering/; $external_labels{$key} = "$URL/" . q|node314.html|; $noresave{$key} = "$nosave"; $key = q/fig:advsync:A_Variable_With_Multiple_Simultaneous_Values/; $external_labels{$key} = "$URL/" . q|node192.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:The_Effects_of_the_CPU_Cache/; $external_labels{$key} = "$URL/" . q|node236.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Lock-Based_Parallel_Double-Ended_Queue_Implementation/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKusick88/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Where_Can_RCU_s_APIs_Be_Used_/; $external_labels{$key} = "$URL/" . q|node152.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Process-Based_Parallel_Functional_Programming/; $external_labels{$key} = "$URL/" . q|node265.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:SRCU_Data-Structure_Diagram/; $external_labels{$key} = "$URL/" . q|node337.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Store_Forwarding/; $external_labels{$key} = "$URL/" . q|node302.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Simple_Limit_Counter_Implementation/; $external_labels{$key} = "$URL/" . q|node61.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:__Macho___NBS/; $external_labels{$key} = "$URL/" . q|node243.html|; $noresave{$key} = "$nosave"; $key = q/chp:Tools_of_the_Trade/; $external_labels{$key} = "$URL/" . q|node41.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_cpu-quiet/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_Interrupt_Handlers/; $external_labels{$key} = "$URL/" . q|node448.html|; $noresave{$key} = "$nosave"; $key = q/cite_WRichardStevens1992/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:What_are_Promela_and_Spin_/; $external_labels{$key} = "$URL/" . q|node424.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Publish-Subscribe_Mechanism/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_Recording_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Quiescent-State-Based_RCU_Read_Side/; $external_labels{$key} = "$URL/" . q|node163.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Lessons__Re_Learned/; $external_labels{$key} = "$URL/" . q|node451.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2009BloatwatchRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Combinatorial_Explosion/; $external_labels{$key} = "$URL/" . q|node427.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney2007PLOSTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Maintain_Multiple_Versions_of_Recently_Updated_Objects/; $external_labels{$key} = "$URL/" . q|node128.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Mapping_rcu-node_Hierarchy_Into_Array/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-init/; $external_labels{$key} = "$URL/" . q|node378.html|; $noresave{$key} = "$nosave"; $key = q/cite_LinusTorvalds2001a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Interrupt_Interface/; $external_labels{$key} = "$URL/" . q|node441.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Avoiding_Locks/; $external_labels{$key} = "$URL/" . q|node188.html|; $noresave{$key} = "$nosave"; $key = q/cite_Intel64IA32v3A2009/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Lock-Based_Existence_Guarantees/; $external_labels{$key} = "$URL/" . q|node112.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Compound_Parallel_Double-Ended_Queue_Implementation/; $external_labels{$key} = "$URL/" . q|node80.html|; $noresave{$key} = "$nosave"; $key = q/cite_Arcangeli03/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/defer:Summary_of_Toy_RCU_Implementations/; $external_labels{$key} = "$URL/" . q|node164.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Conclusion/; $external_labels{$key} = "$URL/" . q|node361.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Sequential-Program_Hash_Table_Search/; $external_labels{$key} = "$URL/" . q|node85.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:Update-Side_Implementation/; $external_labels{$key} = "$URL/" . q|node340.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Unfairness/; $external_labels{$key} = "$URL/" . q|node106.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:QRCU_Reader_Process/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Atomic_Counting_With_Release_Memory_Barrier/; $external_labels{$key} = "$URL/" . q|node120.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Locking_API/; $external_labels{$key} = "$URL/" . q|node279.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:Locked_After_Program_Sample_Output/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node189.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007rcubarrier/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_data/; $external_labels{$key} = "$URL/" . q|node407.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Hierarchical_RCU_State_With_BH/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-needs-cpu_and_rcu-cpu-notify/; $external_labels{$key} = "$URL/" . q|node374.html|; $noresave{$key} = "$nosave"; $key = q/fig:advsync:Software_Logic_Analyzer/; $external_labels{$key} = "$URL/" . q|node192.html|; $noresave{$key} = "$nosave"; $key = q/cite_PeterSewell2010weakmemory/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Free-Running_Counter_Using_RCU/; $external_labels{$key} = "$URL/" . q|node161.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Global_Reference-Count_Pair_Data/; $external_labels{$key} = "$URL/" . q|node158.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_Limit_Counter_Data/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/chp:Introduction/; $external_labels{$key} = "$URL/" . q|node4.html|; $noresave{$key} = "$nosave"; $key = q/cite_MathieuDesnoyers2009URCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Update_Side_Using_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node163.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Memory-Barrier_Examples/; $external_labels{$key} = "$URL/" . q|node230.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Offline_a_CPU/; $external_labels{$key} = "$URL/" . q|node357.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_cpu-quiet-msk/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney03a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_flipctr/; $external_labels{$key} = "$URL/" . q|node408.html|; $noresave{$key} = "$nosave"; $key = q/cite_GerryKane96a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Performance_Advantage_of_Preemptible_RCU_Over_Reader-Writer_Locking/; $external_labels{$key} = "$URL/" . q|node135.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:Read-Side_Acquisition/; $external_labels{$key} = "$URL/" . q|node339.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Shared_Update_Using_Per-Thread_Reference-Count_Pair/; $external_labels{$key} = "$URL/" . q|node160.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Reader-Writer_Locking/; $external_labels{$key} = "$URL/" . q|node257.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Deadlock/; $external_labels{$key} = "$URL/" . q|node104.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Converting_Reader-Writer_Locking_to_RCU:_Data/; $external_labels{$key} = "$URL/" . q|node141.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Lock-Based_Critical_Sections/; $external_labels{$key} = "$URL/" . q|node233.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:MESI_Protocol_Messages/; $external_labels{$key} = "$URL/" . q|node297.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Towards_a_More_Scalable_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Discussion/; $external_labels{$key} = "$URL/" . q|node458.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Compound_Double-Ended_Queue_Revisited/; $external_labels{$key} = "$URL/" . q|node80.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Caches_With_Store_Forwarding/; $external_labels{$key} = "$URL/" . q|node302.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Locking_Constraints/; $external_labels{$key} = "$URL/" . q|node229.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Implementation_of_Reference-Counting_Categories/; $external_labels{$key} = "$URL/" . q|node117.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Hashed_Double-Ended_Queue/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Simple_NBS/; $external_labels{$key} = "$URL/" . q|node240.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Locking:_Villain_or_Slob_/; $external_labels{$key} = "$URL/" . q|node102.html|; $noresave{$key} = "$nosave"; $key = q/chp:Data_Structures/; $external_labels{$key} = "$URL/" . q|node180.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Non-Atomic_Increment_Error_Trail/; $external_labels{$key} = "$URL/" . q|node425.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Recording_and_Recalling_Dynticks-Idle_Grace_Period/; $external_labels{$key} = "$URL/" . q|node395.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Costs_of_Operations/; $external_labels{$key} = "$URL/" . q|node34.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Data_Structures/; $external_labels{$key} = "$URL/" . q|node337.html|; $noresave{$key} = "$nosave"; $key = q/cite_DIS9075SQL92/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_check_callbacks___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/cite_HerbSutter2008EffectiveConcurrency/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Promela_Code_to_Test_Spinlocks/; $external_labels{$key} = "$URL/" . q|node431.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Miscellaneous_Functions/; $external_labels{$key} = "$URL/" . q|node383.html|; $noresave{$key} = "$nosave"; $key = q/defer:rcu_rcgp:RCU_Read_Side_Start/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/cite_SchmidtStalRohnertBuschmann2000v2Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_IntelXeonV3-96a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_IntelItanium02v2/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_ALPHA95/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_SpearMichaelScott2008InevitableSTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:RCU/; $external_labels{$key} = "$URL/" . q|node262.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Use_Cases/; $external_labels{$key} = "$URL/" . q|node349.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Alternative_Approach:_Divide_and_Conquer/; $external_labels{$key} = "$URL/" . q|node437.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_Usage_Summary/; $external_labels{$key} = "$URL/" . q|node148.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Staying_Alive/; $external_labels{$key} = "$URL/" . q|node103.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Atomic_Block_for_Complex_Promela_Assertion/; $external_labels{$key} = "$URL/" . q|node430.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Discussion/; $external_labels{$key} = "$URL/" . q|node263.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Signal-Theft_Limit_Counter_Implementation/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Testing/; $external_labels{$key} = "$URL/" . q|node360.html|; $noresave{$key} = "$nosave"; $key = q/cite_DavidECuller1999/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Lock-Based_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node155.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Abolish_Asynchronous_Grace-Period_APIs/; $external_labels{$key} = "$URL/" . q|node329.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_try_flip_waitmb___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/chp:Locking/; $external_labels{$key} = "$URL/" . q|node102.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_with_Read-Side_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node418.html|; $noresave{$key} = "$nosave"; $key = q/cite_MauriceHerlihy90a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Per-Thread_Statistical_Counters/; $external_labels{$key} = "$URL/" . q|node57.html|; $noresave{$key} = "$nosave"; $key = q/sec:deferRCU_is_a_Way_of_Waiting_for_Things_to_Finish/; $external_labels{$key} = "$URL/" . q|node147.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:A_Few_Simple_Rules/; $external_labels{$key} = "$URL/" . q|node210.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Noting_New_Grace_Periods/; $external_labels{$key} = "$URL/" . q|node385.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2008WhatIsRCUUsage/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_API_Usage_Constraints/; $external_labels{$key} = "$URL/" . q|node152.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Implementation/; $external_labels{$key} = "$URL/" . q|node336.html|; $noresave{$key} = "$nosave"; $key = q/cite_DonaldEPorter2007TRANSACT/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:After_Consumer_Function/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/cite_DaveDice2009ASPLOSRockHTM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Livelock_and_Starvation/; $external_labels{$key} = "$URL/" . q|node105.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_State_Machine_Timeline/; $external_labels{$key} = "$URL/" . q|node413.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-check-callbacks/; $external_labels{$key} = "$URL/" . q|node372.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Atomic_Counting_With_Check_and_Release_Memory_Barrier/; $external_labels{$key} = "$URL/" . q|node121.html|; $noresave{$key} = "$nosave"; $key = q/fig:cpu:System_Hardware_Architecture/; $external_labels{$key} = "$URL/" . q|node33.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Reader_Writer_Locking/; $external_labels{$key} = "$URL/" . q|node91.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Variables_Can_Have_More_Than_One_Value/; $external_labels{$key} = "$URL/" . q|node192.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Overview/; $external_labels{$key} = "$URL/" . q|node25.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Device_Operations/; $external_labels{$key} = "$URL/" . q|node212.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:State_Machine/; $external_labels{$key} = "$URL/" . q|node348.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Complex_Promela_Assertion/; $external_labels{$key} = "$URL/" . q|node430.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Atomic_Increment_Scalability_on_Nehalem/; $external_labels{$key} = "$URL/" . q|node52.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Hardware_Considerations/; $external_labels{$key} = "$URL/" . q|node186.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Memory-Barrier_Instructions_For_Specific_CPUs/; $external_labels{$key} = "$URL/" . q|node314.html|; $noresave{$key} = "$nosave"; $key = q/cite_Herlihy93a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Array-Based_Implementation/; $external_labels{$key} = "$URL/" . q|node55.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Comparison_of_RCU_to_Reader-Writer_Locking_as_Function_of_Critical-Section_Duration/; $external_labels{$key} = "$URL/" . q|node135.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Grace-Period_State_Machine/; $external_labels{$key} = "$URL/" . q|node412.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:MIPS_per_Die_for_Intel_CPUs/; $external_labels{$key} = "$URL/" . q|node8.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Performance/; $external_labels{$key} = "$URL/" . q|node292.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Approximate_Limit_Counter_Variables/; $external_labels{$key} = "$URL/" . q|node63.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Interrupts_from_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node392.html|; $noresave{$key} = "$nosave"; $key = q/cite_IntelXeonV2b-96a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:rcuimpl:SRCU_Update_and_Read-Side_Critical_Sections/; $external_labels{$key} = "$URL/" . q|node334.html|; $noresave{$key} = "$nosave"; $key = q/cite_Dove90/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Measuring_Reader-Writer_Lock_Scalability/; $external_labels{$key} = "$URL/" . q|node47.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-init-one/; $external_labels{$key} = "$URL/" . q|node377.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:NMIs_From_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node455.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_Safety/; $external_labels{$key} = "$URL/" . q|node445.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Demonstration_of_Different_Exclusive_Locks/; $external_labels{$key} = "$URL/" . q|node46.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Example_Memory-Barrier_Sequences/; $external_labels{$key} = "$URL/" . q|node309.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-process-callbacks/; $external_labels{$key} = "$URL/" . q|node373.html|; $noresave{$key} = "$nosave"; $key = q/cite_Kung80/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Simple_Limit_Counter_Variable_Relationships/; $external_labels{$key} = "$URL/" . q|node61.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:__rcu_read_unlock___Implementation/; $external_labels{$key} = "$URL/" . q|node417.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Discussion/; $external_labels{$key} = "$URL/" . q|node131.html|; $noresave{$key} = "$nosave"; $key = q/cite_ARMv7A:2010/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:3D_Integration/; $external_labels{$key} = "$URL/" . q|node36.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Example_1:_Maintaining_Multiple_Versions_During_Deletion/; $external_labels{$key} = "$URL/" . q|node129.html|; $noresave{$key} = "$nosave"; $key = q/cite_Knuth73/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Update_Using_Global_Reference-Count_Pair/; $external_labels{$key} = "$URL/" . q|node158.html|; $noresave{$key} = "$nosave"; $key = q/cite_BOINC2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Invalidate_Queues_and_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node307.html|; $noresave{$key} = "$nosave"; $key = q/tab:cpu:Performance_of_Synchronization_Mechanisms_on_16-CPU_2.8GHz_Intel_X5550__Nehalem__System/; $external_labels{$key} = "$URL/" . q|node462.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Determining_Shape_of_RCU_Hierarchy/; $external_labels{$key} = "$URL/" . q|node368.html|; $noresave{$key} = "$nosave"; $key = q/fig:advsync:Parallel_Hardware_is_Non-Causal/; $external_labels{$key} = "$URL/" . q|node191.html|; $noresave{$key} = "$nosave"; $key = q/cite_Beck85/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Peculiarities/; $external_labels{$key} = "$URL/" . q|node429.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU/; $external_labels{$key} = "$URL/" . q|node401.html|; $noresave{$key} = "$nosave"; $key = q/fig:applyrcu:RCU_and_Per-Thread_Statistical_Counters/; $external_labels{$key} = "$URL/" . q|node169.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_dyntick-save-progress-counter/; $external_labels{$key} = "$URL/" . q|node393.html|; $noresave{$key} = "$nosave"; $key = q/sec:Interacting_With_Hardware/; $external_labels{$key} = "$URL/" . q|node18.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Memory_Usage_of_Increment_Model/; $external_labels{$key} = "$URL/" . q|node427.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_Linux-Kernel_API/; $external_labels{$key} = "$URL/" . q|node149.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:So__What_is_RCU_Really_/; $external_labels{$key} = "$URL/" . q|node153.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Variable-Name-Typo_Fix_Patch/; $external_labels{$key} = "$URL/" . q|node451.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Beyond_Reader-Writer_Locks/; $external_labels{$key} = "$URL/" . q|node111.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:How_to_Use_Promela/; $external_labels{$key} = "$URL/" . q|node428.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Reader-Writer-Locking_Hash_Table_Search/; $external_labels{$key} = "$URL/" . q|node91.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Converting_Reader-Writer_Locking_to_RCU:_Search/; $external_labels{$key} = "$URL/" . q|node141.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Double-Ended_Queue/; $external_labels{$key} = "$URL/" . q|node76.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Organization_and_Initialization/; $external_labels{$key} = "$URL/" . q|node269.html|; $noresave{$key} = "$nosave"; $key = q/cite_OlegNesterov2006aQRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Matrix_Multiply_Efficiency/; $external_labels{$key} = "$URL/" . q|node89.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Existence_Guarantees_Enable_Per-Element_Locking/; $external_labels{$key} = "$URL/" . q|node145.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Checking_Dyntick_Progress_Counters/; $external_labels{$key} = "$URL/" . q|node457.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Memory-Barrier_Considerations/; $external_labels{$key} = "$URL/" . q|node418.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_State_Machine/; $external_labels{$key} = "$URL/" . q|node413.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Allocator_Pool_Schematic/; $external_labels{$key} = "$URL/" . q|node96.html|; $noresave{$key} = "$nosave"; $key = q/tab:count:Statistical_Counter_Performance_on_Power_5/; $external_labels{$key} = "$URL/" . q|node72.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Debugging/; $external_labels{$key} = "$URL/" . q|node260.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcutree_call-rcu/; $external_labels{$key} = "$URL/" . q|node371.html|; $noresave{$key} = "$nosave"; $key = q/cite_TPC/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_is_a_Poor_Man_s_Garbage_Collector/; $external_labels{$key} = "$URL/" . q|node144.html|; $noresave{$key} = "$nosave"; $key = q/sec:time:Time_Management/; $external_labels{$key} = "$URL/" . q|node247.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_Preemptible_RCU_and_dynticks/; $external_labels{$key} = "$URL/" . q|node443.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Read-Side_Primitives/; $external_labels{$key} = "$URL/" . q|node415.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_try_flip_state/; $external_labels{$key} = "$URL/" . q|node409.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_Exercises/; $external_labels{$key} = "$URL/" . q|node165.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Dyntick-Idle_Functions/; $external_labels{$key} = "$URL/" . q|node389.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:MESI_Protocol_Example/; $external_labels{$key} = "$URL/" . q|node299.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:call-rcu/; $external_labels{$key} = "$URL/" . q|node371.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-init/; $external_labels{$key} = "$URL/" . q|node378.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Read_and_Write_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node308.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Validating_NMI_Handlers/; $external_labels{$key} = "$URL/" . q|node450.html|; $noresave{$key} = "$nosave"; $key = q/cite_PostgreSQL2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_Molnar00a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node29.html|; $noresave{$key} = "$nosave"; $key = q/cite_Cheriton96a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Simple_Limit_Counter_Add__Subtract__and_Read/; $external_labels{$key} = "$URL/" . q|node61.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2008WhatIsRCUAPI/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Deletion_From_Linked_List/; $external_labels{$key} = "$URL/" . q|node129.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Data_Structures/; $external_labels{$key} = "$URL/" . q|node405.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:CPU_Cache_Structure/; $external_labels{$key} = "$URL/" . q|node294.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Threads_Created_Via_pthread-create___Share_Memory/; $external_labels{$key} = "$URL/" . q|node45.html|; $noresave{$key} = "$nosave"; $key = q/sec:analysis:Profiling/; $external_labels{$key} = "$URL/" . q|node177.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_State_Machine/; $external_labels{$key} = "$URL/" . q|node68.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Performance/; $external_labels{$key} = "$URL/" . q|node7.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcutree_rcu-process-callbacks/; $external_labels{$key} = "$URL/" . q|node373.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Forcing_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node394.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Double-Ended_Queue_Discussion/; $external_labels{$key} = "$URL/" . q|node81.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:RCU_Usage/; $external_labels{$key} = "$URL/" . q|node133.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Shared-Memory_Parallel_Functional_Programming/; $external_labels{$key} = "$URL/" . q|node264.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Protection/; $external_labels{$key} = "$URL/" . q|node184.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Productivity/; $external_labels{$key} = "$URL/" . q|node8.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:I_O_Operations/; $external_labels{$key} = "$URL/" . q|node31.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Concurrent_RCU_Deletion/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Validation_of_Preemptible_RCU/; $external_labels{$key} = "$URL/" . q|node419.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Hierarchical_RCU_State_With_Dynticks/; $external_labels{$key} = "$URL/" . q|node347.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Checking_for_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node393.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Just_Count_/; $external_labels{$key} = "$URL/" . q|node52.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Synchronization_Primitives/; $external_labels{$key} = "$URL/" . q|node268.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Ordering-Hostile_Architecture/; $external_labels{$key} = "$URL/" . q|node310.html|; $noresave{$key} = "$nosave"; $key = q/chp:Validation:_Debugging_and_Analysis/; $external_labels{$key} = "$URL/" . q|node172.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Atomic_Counting/; $external_labels{$key} = "$URL/" . q|node119.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Multithreaded_Transactions/; $external_labels{$key} = "$URL/" . q|node253.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Example_Parent_Thread/; $external_labels{$key} = "$URL/" . q|node278.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:I_O_Operations/; $external_labels{$key} = "$URL/" . q|node250.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Inefficiency/; $external_labels{$key} = "$URL/" . q|node107.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Read-Side_Primitives/; $external_labels{$key} = "$URL/" . q|node333.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Locking/; $external_labels{$key} = "$URL/" . q|node256.html|; $noresave{$key} = "$nosave"; $key = q/cite_Intelx86MemoryOrdering2007/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Using_RCU_to_Wait_for_Mythical_Preemptible_NMIs_to_Finish/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Examples_of_Memory_Barrier_Pairings/; $external_labels{$key} = "$URL/" . q|node227.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Read-Side_Using_Global_Reference-Count_Pair/; $external_labels{$key} = "$URL/" . q|node158.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Grace-Period_Interface/; $external_labels{$key} = "$URL/" . q|node442.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Signal-Theft_Limit_Counter_Read_Function/; $external_labels{$key} = "$URL/" . q|node69.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Variables_for_Simple_Dynticks_Interface/; $external_labels{$key} = "$URL/" . q|node453.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:What_Are_Memory_Barriers_/; $external_labels{$key} = "$URL/" . q|node214.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Interrupts_from_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node392.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:The_exec_System_Call/; $external_labels{$key} = "$URL/" . q|node261.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Array-Based_Per-Thread_Statistical_Counters/; $external_labels{$key} = "$URL/" . q|node55.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Invalidate_Queues_and_Invalidate_Acknowledge/; $external_labels{$key} = "$URL/" . q|node306.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:__rcu_advance_callbacks___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Simplicity_Avoids_Formal_Verification/; $external_labels{$key} = "$URL/" . q|node452.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Response_Time_of_RCU_vs._Reference_Counting/; $external_labels{$key} = "$URL/" . q|node142.html|; $noresave{$key} = "$nosave"; $key = q/Performance_Summary/; $external_labels{$key} = "$URL/" . q|node101.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Synchronization_Granularity/; $external_labels{$key} = "$URL/" . q|node84.html|; $noresave{$key} = "$nosave"; $key = q/cite_Olukotun96/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney93/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Grace-Period_State_Machine_Overview/; $external_labels{$key} = "$URL/" . q|node413.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_is_a_Bulk_Reference-Counting_Mechanism/; $external_labels{$key} = "$URL/" . q|node143.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Read-Copy_Update__RCU_/; $external_labels{$key} = "$URL/" . q|node124.html|; $noresave{$key} = "$nosave"; $key = q/cite_RobertLove2005/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:datastruct:Computational_Complexity_and_Performance/; $external_labels{$key} = "$URL/" . q|node182.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Data_Flow_For_Global_Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node52.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_try_flip_waitack___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:Effect_of_Locking_on_Snapshot_Collection/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/defer:RCU_Based_on_Free-Running_Counter/; $external_labels{$key} = "$URL/" . q|node161.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Example_2/; $external_labels{$key} = "$URL/" . q|node312.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:Sleepable_RCU_Wait-to-Finish_APIs/; $external_labels{$key} = "$URL/" . q|node150.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:POSIX_Reader-Writer_Locking/; $external_labels{$key} = "$URL/" . q|node47.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Approximate_Limit_Counter_Balancing/; $external_labels{$key} = "$URL/" . q|node63.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Readers_and_RCU_Grace_Period/; $external_labels{$key} = "$URL/" . q|node127.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Mapping_from_POSIX_to_Linux-Kernel_Primitives/; $external_labels{$key} = "$URL/" . q|node49.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Locking/; $external_labels{$key} = "$URL/" . q|node279.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:What_May_Not_Be_Assumed_About_Memory_Barriers_/; $external_labels{$key} = "$URL/" . q|node223.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Linear_Linked_List/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Response_Time_of_RCU_vs._Reader-Writer_Locking/; $external_labels{$key} = "$URL/" . q|node138.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Data_Dependency_Barriers/; $external_labels{$key} = "$URL/" . q|node224.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Non-Blocking_Synchronization/; $external_labels{$key} = "$URL/" . q|node239.html|; $noresave{$key} = "$nosave"; $key = q/cite_BovetCesati2005/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Read-Side_Using_Per-Thread_Reference-Count_Pair/; $external_labels{$key} = "$URL/" . q|node159.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:After_Producer_Function/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Nodes_in_the_Hierarchy/; $external_labels{$key} = "$URL/" . q|node365.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Historic_Parallel_Programming_Difficulties/; $external_labels{$key} = "$URL/" . q|node5.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Recording_and_Recalling_Dynticks-Idle_Grace_Period/; $external_labels{$key} = "$URL/" . q|node395.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_Counter_Flip_Operation/; $external_labels{$key} = "$URL/" . q|node404.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Store_Buffers_and_Memory_Barriers/; $external_labels{$key} = "$URL/" . q|node303.html|; $noresave{$key} = "$nosave"; $key = q/chp:Ease_of_Use/; $external_labels{$key} = "$URL/" . q|node244.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Entering_and_Exiting_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node390.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcutree_rcu-check-callbacks/; $external_labels{$key} = "$URL/" . q|node372.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Interrupts/; $external_labels{$key} = "$URL/" . q|node447.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Basic_Model/; $external_labels{$key} = "$URL/" . q|node444.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:POSIX_Thread_Creation_and_Destruction/; $external_labels{$key} = "$URL/" . q|node45.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Statistical_Counters/; $external_labels{$key} = "$URL/" . q|node53.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Data_Flow_For_Global_Combining-Tree_Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node464.html|; $noresave{$key} = "$nosave"; $key = q/cite_ThomasEHart2006a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Reader-Writer_Lock_Scalability/; $external_labels{$key} = "$URL/" . q|node47.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Grace-Period-Detection_Functions/; $external_labels{$key} = "$URL/" . q|node384.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Persistence/; $external_labels{$key} = "$URL/" . q|node258.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_hlist_Publication/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Per-Element_Locking_With_Lock-Based_Existence_Guarantees/; $external_labels{$key} = "$URL/" . q|node112.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Resource_Allocator_Caches/; $external_labels{$key} = "$URL/" . q|node93.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_try_flip___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Promela_Code_for_Spinlock/; $external_labels{$key} = "$URL/" . q|node431.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_mb_flag/; $external_labels{$key} = "$URL/" . q|node411.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007PreemptibleRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_MySQL2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Stores_Result_in_Unnecessary_Stalls/; $external_labels{$key} = "$URL/" . q|node300.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Summary_of_RCU_Fundamentals/; $external_labels{$key} = "$URL/" . q|node132.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:External_Interfaces/; $external_labels{$key} = "$URL/" . q|node369.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Right-_and_Left-Hand_Locks/; $external_labels{$key} = "$URL/" . q|node77.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Update-Side_Primitives/; $external_labels{$key} = "$URL/" . q|node334.html|; $noresave{$key} = "$nosave"; $key = q/cite_Bonwick01slab/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_Gamsa99/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/item:app:whymb:Need_Store_Buffer/; $external_labels{$key} = "$URL/" . q|node302.html|; $noresave{$key} = "$nosave"; $key = q/sec:debugging:Assertions/; $external_labels{$key} = "$URL/" . q|node174.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:SRCU_Safe_Cleanup/; $external_labels{$key} = "$URL/" . q|node335.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Kernel_fget_fput_API/; $external_labels{$key} = "$URL/" . q|node121.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulMcKenney2007QRCUpatch/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Deadlock_in_Lock-Based_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Example_1/; $external_labels{$key} = "$URL/" . q|node311.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Conceptual_Validation/; $external_labels{$key} = "$URL/" . q|node421.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Starting_a_Grace_Period/; $external_labels{$key} = "$URL/" . q|node387.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Hashed_Double-Ended_Queue_With_12_Elements/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Kernel_kref_API/; $external_labels{$key} = "$URL/" . q|node119.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Formal_Verification/; $external_labels{$key} = "$URL/" . q|node423.html|; $noresave{$key} = "$nosave"; $key = q/cite_MPIForum2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Flat_Classic_RCU_State/; $external_labels{$key} = "$URL/" . q|node344.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Example:_Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node426.html|; $noresave{$key} = "$nosave"; $key = q/cite_JohnKnickerbocker2008:3DI/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Insert_and_Lock-Free_Search/; $external_labels{$key} = "$URL/" . q|node315.html|; $noresave{$key} = "$nosave"; $key = q/cite_GeneAmdahl1967AmdahlsLaw/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_ManfredSpraul2008StateMachineRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Interrupts_From_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node456.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:RCU_Read-Side_Critical_Sections/; $external_labels{$key} = "$URL/" . q|node370.html|; $noresave{$key} = "$nosave"; $key = q/cite_WilsonCHsieh92a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcu_read_lock__/; $external_labels{$key} = "$URL/" . q|node416.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2009ProgrammingHard/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_Alexander79/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Where_Are_Memory_Barriers_Needed_/; $external_labels{$key} = "$URL/" . q|node238.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Initialization_Implementation/; $external_labels{$key} = "$URL/" . q|node338.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Parallel_Programming_Goals/; $external_labels{$key} = "$URL/" . q|node6.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Store_Buffers/; $external_labels{$key} = "$URL/" . q|node301.html|; $noresave{$key} = "$nosave"; $key = q/cite_WernerVogels:2009:EventuallyConsistent/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Thread_API/; $external_labels{$key} = "$URL/" . q|node271.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Classic_vs._Preemptible_RCU_Callback_Processing/; $external_labels{$key} = "$URL/" . q|node404.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Sequential_Program/; $external_labels{$key} = "$URL/" . q|node85.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Atomic_Limit_Counter_Utility_Functions/; $external_labels{$key} = "$URL/" . q|node66.html|; $noresave{$key} = "$nosave"; $key = q/defer:Lock-Based_RCU/; $external_labels{$key} = "$URL/" . q|node155.html|; $noresave{$key} = "$nosave"; $key = q/cite_Spraul01/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Atomic_Limit_Counter_Add_and_Subtract/; $external_labels{$key} = "$URL/" . q|node66.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Dynamic_Linking_and_Loading/; $external_labels{$key} = "$URL/" . q|node259.html|; $noresave{$key} = "$nosave"; $key = q/cite_RyanEccles2005HPCSNovice/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_OlegNesterov2006QRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_CSIRACMuseumVictoria/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_DBLomet1977SIGSOFT/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cha:app:Important_Questions/; $external_labels{$key} = "$URL/" . q|node266.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_is_a_Restricted_Reference-Counting_Mechanism/; $external_labels{$key} = "$URL/" . q|node142.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Non-Atomic_Increment_spin_Output/; $external_labels{$key} = "$URL/" . q|node425.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Task_Interface/; $external_labels{$key} = "$URL/" . q|node440.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Linux_Circular_Linked_List/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Scanning_for_Holdout_CPUs/; $external_labels{$key} = "$URL/" . q|node397.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2008HierarchicalRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/tab:app:whymb:Cache_Coherence_Example/; $external_labels{$key} = "$URL/" . q|node299.html|; $noresave{$key} = "$nosave"; $key = q/fig:cpu:Latency_Benefit_of_3D_Integration/; $external_labels{$key} = "$URL/" . q|node36.html|; $noresave{$key} = "$nosave"; $key = q/cite_HerlihyShavit2008Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Grace-Period_State_Machine_Walkthrough/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Promela_Code_for_Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node426.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Categories_of_Tasks_Required_of_Parallel_Programmers/; $external_labels{$key} = "$URL/" . q|node14.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Design_Patterns_and_Lock_Granularity/; $external_labels{$key} = "$URL/" . q|node84.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:RCU_Callback_List/; $external_labels{$key} = "$URL/" . q|node386.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Hardware_System_Architecture/; $external_labels{$key} = "$URL/" . q|node33.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Replacement_in_Linked_List/; $external_labels{$key} = "$URL/" . q|node130.html|; $noresave{$key} = "$nosave"; $key = q/cite_LaninShasha1986TSM/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_check_mb___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Store_Sequences_Result_in_Unnecessary_Stalls/; $external_labels{$key} = "$URL/" . q|node304.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:QRCU_Unordered_Summation/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/cite_Goetz2007Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:CPU_Hotplug/; $external_labels{$key} = "$URL/" . q|node379.html|; $noresave{$key} = "$nosave"; $key = q/cite_Dijkstra1971HOoSP/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Control_Dependencies/; $external_labels{$key} = "$URL/" . q|node225.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Read-Side_Using_Per-Thread_Reference-Count_Pair_and_Shared_Update_Data/; $external_labels{$key} = "$URL/" . q|node160.html|; $noresave{$key} = "$nosave"; $key = q/cite_OpenMPI2008/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Atomic_Increment_spin_Output/; $external_labels{$key} = "$URL/" . q|node426.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Entering_and_Exiting_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node454.html|; $noresave{$key} = "$nosave"; $key = q/chp:app:whymb:Why_Memory_Barriers_/; $external_labels{$key} = "$URL/" . q|node293.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:RCU_Publish-Subscribe_and_Version_Maintenance_APIs/; $external_labels{$key} = "$URL/" . q|node151.html|; $noresave{$key} = "$nosave"; $key = q/cite_Torvalds2.6kernel/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Double-Ended_Queue_With_Left-_and_Right-Hand_Locks/; $external_labels{$key} = "$URL/" . q|node77.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Buggy_Grace_Period_From_Broken_RCU/; $external_labels{$key} = "$URL/" . q|node402.html|; $noresave{$key} = "$nosave"; $key = q/defer:rcu_rcgp:RCU_Grace_Period_Start/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Saving_Dyntick_Progress_Counters/; $external_labels{$key} = "$URL/" . q|node457.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Atomic_Limit_Counter_Implementation/; $external_labels{$key} = "$URL/" . q|node66.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Hazard_Pointers/; $external_labels{$key} = "$URL/" . q|node241.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Hierarchical_RCU_State_4_096_CPUs/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Simple_Limit_Counter_Variables/; $external_labels{$key} = "$URL/" . q|node61.html|; $noresave{$key} = "$nosave"; $key = q/tab:defer:RCU_Wait-to-Finish_APIs/; $external_labels{$key} = "$URL/" . q|node150.html|; $noresave{$key} = "$nosave"; $key = q/codesample:advsync:What_Can_You_Count_On__2/; $external_labels{$key} = "$URL/" . q|node208.html|; $noresave{$key} = "$nosave"; $key = q/chp:applyrcu:Applying_RCU/; $external_labels{$key} = "$URL/" . q|node166.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:Linux-Kernel_Equivalents_to_POSIX_Operations/; $external_labels{$key} = "$URL/" . q|node49.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:Schematic_of_Real-World_Parallel_Allocator/; $external_labels{$key} = "$URL/" . q|node100.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:General_Approach/; $external_labels{$key} = "$URL/" . q|node404.html|; $noresave{$key} = "$nosave"; $key = q/cite_Butenhof1997pthreads/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_Snaman87/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Scanning_rcu-node_Structures_When_Applying_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node388.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Using_the_fork___Primitive/; $external_labels{$key} = "$URL/" . q|node44.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Example_2:_Maintaining_Multiple_Versions_During_Replacement/; $external_labels{$key} = "$URL/" . q|node130.html|; $noresave{$key} = "$nosave"; $key = q/defer:Scalable_Counter-Based_RCU_With_Shared_Grace_Periods/; $external_labels{$key} = "$URL/" . q|node160.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Checking_For_Dynticks_Quiescent_States/; $external_labels{$key} = "$URL/" . q|node457.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2006c/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Hashed_Double-Ended_Queue_After_Insertions/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Linux_Primitives_Supporting_Reference_Counting/; $external_labels{$key} = "$URL/" . q|node122.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcu_try_flip_idle___Implementation/; $external_labels{$key} = "$URL/" . q|node414.html|; $noresave{$key} = "$nosave"; $key = q/cite_LaiJiangshan2008NewClassicAlgorithm/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Coding_Tricks/; $external_labels{$key} = "$URL/" . q|node430.html|; $noresave{$key} = "$nosave"; $key = q/app:ack:Credits/; $external_labels{$key} = "$URL/" . q|node479.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Lock-Based_Parallel_Double-Ended_Queue_Data_Structure/; $external_labels{$key} = "$URL/" . q|node79.html|; $noresave{$key} = "$nosave"; $key = q/cite_IngoMolnar05a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_OpenGroup1997pthreads/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PanagiotisMetaxas1999PDCS/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_check-cpu-stall/; $external_labels{$key} = "$URL/" . q|node399.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Code_Locking/; $external_labels{$key} = "$URL/" . q|node86.html|; $noresave{$key} = "$nosave"; $key = q/defer:__Toy___RCU_Implementations/; $external_labels{$key} = "$URL/" . q|node154.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007BoostRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:debugging:Static_Analysis/; $external_labels{$key} = "$URL/" . q|node175.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Software_Design_Implications/; $external_labels{$key} = "$URL/" . q|node40.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:NMIs_From_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node455.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:How_Many_Readers_and_Updaters_Are_Really_Needed_/; $external_labels{$key} = "$URL/" . q|node434.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2009TMeverywhere/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Invalidate_Queues/; $external_labels{$key} = "$URL/" . q|node305.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Interrupt_from_Dynticks_Idle_Mode/; $external_labels{$key} = "$URL/" . q|node354.html|; $noresave{$key} = "$nosave"; $key = q/fig:count:Data_Flow_For_Per-Thread_Increment/; $external_labels{$key} = "$URL/" . q|node55.html|; $noresave{$key} = "$nosave"; $key = q/cite_DuaneSzafron1994PEMPDS/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:Read-Side_Release/; $external_labels{$key} = "$URL/" . q|node339.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:Read_Memory_Barriers_vs._Load_Speculation/; $external_labels{$key} = "$URL/" . q|node228.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Promela_Code_for_Non-Atomic_Increment/; $external_labels{$key} = "$URL/" . q|node425.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Enter_and_Leave_Dynticks_Idle_Mode/; $external_labels{$key} = "$URL/" . q|node353.html|; $noresave{$key} = "$nosave"; $key = q/cite_Blundell2006TMdeadlock/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Compound_Double-Ended_Queue/; $external_labels{$key} = "$URL/" . q|node78.html|; $noresave{$key} = "$nosave"; $key = q/defer:Simple_Counter-Based_RCU/; $external_labels{$key} = "$URL/" . q|node157.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Novel_Materials_and_Processes/; $external_labels{$key} = "$URL/" . q|node37.html|; $noresave{$key} = "$nosave"; $key = q/fig:locking:Per-Element_Locking_Without_Existence_Guarantees/; $external_labels{$key} = "$URL/" . q|node112.html|; $noresave{$key} = "$nosave"; $key = q/cite_Holzmann03a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2007QRCUspin/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:advsync:Modern_Computer_System_Cache_Structure/; $external_labels{$key} = "$URL/" . q|node190.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Kernel_Parameters/; $external_labels{$key} = "$URL/" . q|node368.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:questions:What_Does___After___Mean_/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/chp:Conflicting_Visions_of_the_Future/; $external_labels{$key} = "$URL/" . q|node248.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Example:_Locking/; $external_labels{$key} = "$URL/" . q|node431.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-online-cpu/; $external_labels{$key} = "$URL/" . q|node381.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutree:Start_a_New_Grace_Period/; $external_labels{$key} = "$URL/" . q|node350.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Generality/; $external_labels{$key} = "$URL/" . q|node9.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Advice_to_Hardware_Designers/; $external_labels{$key} = "$URL/" . q|node325.html|; $noresave{$key} = "$nosave"; $key = q/defer:Nestable_RCU_Based_on_Free-Running_Counter/; $external_labels{$key} = "$URL/" . q|node162.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Per-Thread_Lock-Based_RCU_Implementation/; $external_labels{$key} = "$URL/" . q|node156.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Reference_Counting/; $external_labels{$key} = "$URL/" . q|node116.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Miscellaneous_Functions/; $external_labels{$key} = "$URL/" . q|node383.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney98/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-init-percpu-data/; $external_labels{$key} = "$URL/" . q|node380.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Formal_Validation/; $external_labels{$key} = "$URL/" . q|node422.html|; $noresave{$key} = "$nosave"; $key = q/sec:locking:Types_of_Locks/; $external_labels{$key} = "$URL/" . q|node108.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:__rcu_read_lock___Implementation/; $external_labels{$key} = "$URL/" . q|node416.html|; $noresave{$key} = "$nosave"; $key = q/cite_WikipediaRCU/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_ElGhazawi2003UPC/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Cache_Structure/; $external_labels{$key} = "$URL/" . q|node294.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Promela_Example:_QRCU/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/cite_DanGrossman2007TMGCAnalogy/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_CSIRACUniversityMelbourne/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:Isolate_Grace-Period_Detection/; $external_labels{$key} = "$URL/" . q|node330.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Conceptual_RCU/; $external_labels{$key} = "$URL/" . q|node402.html|; $noresave{$key} = "$nosave"; $key = q/sec:analysis:Performance_Estimation/; $external_labels{$key} = "$URL/" . q|node179.html|; $noresave{$key} = "$nosave"; $key = q/fig:easy:Mandelbrot_Set/; $external_labels{$key} = "$URL/" . q|node246.html|; $noresave{$key} = "$nosave"; $key = q/codesample:advsync:What_Can_You_Count_On__1/; $external_labels{$key} = "$URL/" . q|node208.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Tracking_Dyntick_State/; $external_labels{$key} = "$URL/" . q|node364.html|; $noresave{$key} = "$nosave"; $key = q/fig:toolsoftrade:Demonstration_of_Same_Exclusive_Lock/; $external_labels{$key} = "$URL/" . q|node46.html|; $noresave{$key} = "$nosave"; $key = q/chp:Hardware_and_its_Habits/; $external_labels{$key} = "$URL/" . q|node24.html|; $noresave{$key} = "$nosave"; $key = q/cite_Hennessy95a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:questions:After_Program_Sample_Output/; $external_labels{$key} = "$URL/" . q|node267.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:POSIX_Locking/; $external_labels{$key} = "$URL/" . q|node46.html|; $noresave{$key} = "$nosave"; $key = q/cite_GOF95/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEdwardMcKenneyPhD/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_BuschmannHenneySchmidt2007v4Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_McKenney92a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:count:Parallel_Counting_Discussion/; $external_labels{$key} = "$URL/" . q|node72.html|; $noresave{$key} = "$nosave"; $key = q/fig:intro:Tradeoff_Between_Productivity_and_Generality/; $external_labels{$key} = "$URL/" . q|node9.html|; $noresave{$key} = "$nosave"; $key = q/cite_Mattson2005Textbook/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:RCU_Data_Structure_Publication/; $external_labels{$key} = "$URL/" . q|node126.html|; $noresave{$key} = "$nosave"; $key = q/sec:future:Time_Delays/; $external_labels{$key} = "$URL/" . q|node255.html|; $noresave{$key} = "$nosave"; $key = q/sec:easy:Shaving_the_Mandelbrot_Set/; $external_labels{$key} = "$URL/" . q|node246.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Testing/; $external_labels{$key} = "$URL/" . q|node420.html|; $noresave{$key} = "$nosave"; $key = q/app:primitives:Thread_Creation__Destruction__and_Control/; $external_labels{$key} = "$URL/" . q|node271.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Hierarchical_RCU_Grace_Period/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:POSIX_Process_Creation_and_Destruction/; $external_labels{$key} = "$URL/" . q|node44.html|; $noresave{$key} = "$nosave"; $key = q/chp:Answers_to_Quick_Quizzes/; $external_labels{$key} = "$URL/" . q|node460.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Memory-Barrier_Fix_Patch/; $external_labels{$key} = "$URL/" . q|node451.html|; $noresave{$key} = "$nosave"; $key = q/sec:advsync:If_B_Follows_A__and_C_Follows_B__Why_Doesn_t_C_Follow_A_/; $external_labels{$key} = "$URL/" . q|node191.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:POSIX_Multiprocessing/; $external_labels{$key} = "$URL/" . q|node43.html|; $noresave{$key} = "$nosave"; $key = q/cite_DaveDice2006DISC/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_DinakarGuniguntala2008IBMSysJ/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_ChistopherJRossbach2007a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:Output_for_Spinlock_Test/; $external_labels{$key} = "$URL/" . q|node431.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Data_for_Nestable_RCU_Using_a_Free-Running_Counter/; $external_labels{$key} = "$URL/" . q|node162.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutreewt:Code_for_rcu-implicit-dynticks-qs/; $external_labels{$key} = "$URL/" . q|node393.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:whymb:Why_smp-read-barrier-depends___is_Required/; $external_labels{$key} = "$URL/" . q|node315.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Make_Use_of_Existing_Parallel_Software/; $external_labels{$key} = "$URL/" . q|node12.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Overview_of_Preemptible_RCU_Algorithm/; $external_labels{$key} = "$URL/" . q|node403.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:Wait_For_Pre-Existing_RCU_Readers_to_Complete/; $external_labels{$key} = "$URL/" . q|node127.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:whymb:Example_3/; $external_labels{$key} = "$URL/" . q|node313.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Preemptible_RCU_Worst-Case_Scenario/; $external_labels{$key} = "$URL/" . q|node421.html|; $noresave{$key} = "$nosave"; $key = q/sec:app:rcuimpl:SRCU_API_and_Usage/; $external_labels{$key} = "$URL/" . q|node331.html|; $noresave{$key} = "$nosave"; $key = q/cite_JimGray2002SmokingHairyGolfBalls/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulEMcKenney2006b/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:rcu-init-levelspread/; $external_labels{$key} = "$URL/" . q|node376.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Overheads/; $external_labels{$key} = "$URL/" . q|node32.html|; $noresave{$key} = "$nosave"; $key = q/cite_DavidDice:2010:SCA:HTM:deque/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Converting_Reader-Writer_Locking_to_RCU:_Deletion/; $external_labels{$key} = "$URL/" . q|node141.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Hierarchical_Locking/; $external_labels{$key} = "$URL/" . q|node92.html|; $noresave{$key} = "$nosave"; $key = q/cite_JMStone93/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:defer:RCU_is_a_Reader-Writer_Lock_Replacement/; $external_labels{$key} = "$URL/" . q|node134.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:NMIs_from_Dyntick-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node391.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:Good_Grace_Period_From_Correct_RCU/; $external_labels{$key} = "$URL/" . q|node402.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Running_the_QRCU_Example/; $external_labels{$key} = "$URL/" . q|node433.html|; $noresave{$key} = "$nosave"; $key = q/tab:advsync:Ordering_With_Multiple_Locks/; $external_labels{$key} = "$URL/" . q|node234.html|; $noresave{$key} = "$nosave"; $key = q/sec:toolsoftrade:Scripting_Languages/; $external_labels{$key} = "$URL/" . q|node42.html|; $noresave{$key} = "$nosave"; $key = q/app:rcuimpl:rcutreewt:Handling_Offline_and_Holdout_CPUs/; $external_labels{$key} = "$URL/" . q|node396.html|; $noresave{$key} = "$nosave"; $key = q/cite_IBMzSeries04a/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:formal:Interrupts_From_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node456.html|; $noresave{$key} = "$nosave"; $key = q/sec:debugging:Tracing/; $external_labels{$key} = "$URL/" . q|node173.html|; $noresave{$key} = "$nosave"; $key = q/sec:intro:Multiple_Instances_of_a_Sequential_Application/; $external_labels{$key} = "$URL/" . q|node11.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Special-Purpose_Accelerators/; $external_labels{$key} = "$URL/" . q|node38.html|; $noresave{$key} = "$nosave"; $key = q/fig:analysis:QRCU_Updater_Process/; $external_labels{$key} = "$URL/" . q|node432.html|; $noresave{$key} = "$nosave"; $key = q/sec:analysis:Probability_and_Heisenbugs/; $external_labels{$key} = "$URL/" . q|node176.html|; $noresave{$key} = "$nosave"; $key = q/cite_AMDOpteron:2:2007/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/cite_SPARC94/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/fig:SMPdesign:Clock-Frequency_Trend_for_Intel_CPUs/; $external_labels{$key} = "$URL/" . q|node85.html|; $noresave{$key} = "$nosave"; $key = q/cite_PaulMcKenney05b/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Locking_Granularity_and_Performance/; $external_labels{$key} = "$URL/" . q|node89.html|; $noresave{$key} = "$nosave"; $key = q/fig:defer:Diverse_RCU_Read-Side_Nesting/; $external_labels{$key} = "$URL/" . q|node467.html|; $noresave{$key} = "$nosave"; $key = q/fig:app:rcuimpl:rcutree:Hierarchical_RCU_State/; $external_labels{$key} = "$URL/" . q|node346.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Dining_Philosophers_Problem/; $external_labels{$key} = "$URL/" . q|node75.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Parallel_Fastpath/; $external_labels{$key} = "$URL/" . q|node90.html|; $noresave{$key} = "$nosave"; $key = q/app:formal:Entering_and_Leaving_Dynticks-Idle_Mode/; $external_labels{$key} = "$URL/" . q|node454.html|; $noresave{$key} = "$nosave"; $key = q/cite_LukeDalessandro:2011:ASPLOS:HybridNOrecSTM:deque/; $external_labels{$key} = "$URL/" . q|node478.html|; $noresave{$key} = "$nosave"; $key = q/sec:cpu:Cache_Misses/; $external_labels{$key} = "$URL/" . q|node30.html|; $noresave{$key} = "$nosave"; $key = q/sec:SMPdesign:Data_Ownership/; $external_labels{$key} = "$URL/" . q|node88.html|; $noresave{$key} = "$nosave"; 1; # LaTeX2HTML 2008 (1.71) # labels from external_latex_labels array. 1; perfbook_html/node354.html0000644000175000017500000000573411672746163015660 0ustar paulmckpaulmck D.2.7.5 Interrupt from Dynticks Idle Mode


D.2.7.5 Interrupt from Dynticks Idle Mode

Interrupts from dynticks idle mode are handled by rcu_irq_enter() and rcu_irq_exit(). The rcu_irq_enter() function increments the per-CPU dynticks_nesting variable, and, if the prior value was zero, also increments the dynticks per-CPU variable (which must then have an odd-numbered value).

The rcu_irq_exit() function decrements the per-CPU dynticks_nesting variable, and, if the new value is zero, also increments the dynticks per-CPU variable (which must then have an even-numbered value).

Note that entering an irq handler exits dynticks idle mode and vice versa. This enter/exit anti-correspondence can cause much confusion. You have been warned.



Paul E. McKenney 2011-12-16
perfbook_html/img168.png0000644000175000017500000000401211672746000015304 0ustar paulmckpaulmckPNG  IHDRZ[cT0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fIDATxOU;۝d7`^4RQPa)B_jb"H a),ev]ԡApP97;37L6 M>o&o2o toUg[<`e->lwЄܛDnL¤ݪ;6 tY]foؠnD )э)^kBV| *(N'PYϢkv, tl s8XDAd f (DQ .K݄F,V*=Oc9ΧSh68DNr2hos :tjQ~;gԱ\h8y1}16*7NQ XnۧSN @BQW˜H吋IM̍T.& 猩n,SG6r֖WnJ6WDN%uZU5z .WIB+v/kHUttxL1N^5>P iShpک!W\ZqE\DDGnsh5(np߸ >pi.ʈKu󠏵~\uB|\yqQkTtϸYqh~f%4dܬmOB)w؄8#?&2uظ4.MQ(O\?%Y ANYTغJ%_ZA|>YQ.fPZ{;Meѷ&Z[,#=5/VzL~ ^>')++;{׽;bqI7:W; %E]v ge():|}0,y}Ѝ 18((piwn=\näGe|1{AM%܏g\lzR.a{Wqn]a2jrQ~q ur%(o!\FX.88e=w| ΀t]h]w{zg7Xn\ޏt:4]MtIS)Aa-Ka(*`qC#pSTV\.[sRqYhظ&Ĺ\tJ:'Eiwŕkr\f&&K[>q/C%%{([|[:w[nmJFK 4 ͞o;לB?nn\Ӿ)U(MRu6#esr;? IJgt; `۰^ƺ\4M[ўIUIgs>,W`]8{kGCg„On-E}4n:n |`*ܚE.2ܯLҪ#2>gj0~M&b=niZݷp࣪o6 [يBr[Z2vL "}n6OY?'˜`P:}_J nc,{,ps]iѺ'|gF(xDFHznϼcau 4[%k4--}gݿ%HnIlJNO$trA1'GB";0\n26E!op{eҀړ \6WvdZD/P+k \t,eq}[YV-:5 Hn l鋭>[tbrNwŕkr\è nI9I܉#IENDB`perfbook_html/node374.html0000644000175000017500000000755611672746163015666 0ustar paulmckpaulmck D.3.2.5 rcu_needs_cpu() and rcu_cpu_notify()


D.3.2.5 rcu_needs_cpu() and rcu_cpu_notify()

Figure: rcu_needs_cpu() and rcu_cpu_notify Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 int rcu_needs_cpu(int cpu)
2 {...
...ault:
25 break;
26 }
27 return NOTIFY_OK;
28 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_needs_cpu() and rcu_cpu_notify(), which are invoked by the Linux kernel to check on switching to dynticks-idle mode and to handle CPU hotplug, respectively.

Lines 1-5 show rcu_needs_cpu(), which simply checks if the specified CPU has either ``rcu'' (line 3) or ``rcu_bh'' (line 4) callbacks.

Lines 7-28 show rcu_cpu_notify(), which is a very typical CPU-hotplug notifier function with the typical switch statement. Line 16 invokes rcu_online_cpu() if the specified CPU is going to be coming online, and line 22 invokes rcu_offline_cpu() if the specified CPU has gone to be going offline. It is important to note that CPU-hotplug operations are not atomic, but rather happen in stages that can extend for multiple grace periods. RCU must therefore gracefully handle CPUs that are in the process of coming or going.



Paul E. McKenney 2011-12-16
perfbook_html/img22.png0000644000175000017500000000553711672746002015230 0ustar paulmckpaulmckPNG  IHDR{q3PLTEMJK# b``mkkXUV856C@@wuv.*++&tRNS@f IDATx\( &Jn^ڙͿggZ[.(Ш5 FJUV,5(7ߨsU%{*qnnUT R[wU4,5^`GIU\U6z}fv7:Xo򵊫b,n 4 +ߖ^HXyi hEäi\KFF=Ծ~>FXQ9ւz#4jR'?|HWj,Bn*ezFq617 yZ]3Un+qJO@yP!W߇Wec)*w뷩NQd9;e# ߀*|(M~Foǫk׆Rclm2#[KBX]Ƃ&v;/~tE(jmW2J26=$)'%ڞ琙"BN}@nr` iNQ۵X=WR{LkD zIz2b⤾`C&.rDP {WË+k$+>ϯXFXޘ&"F]Ge˒SuyK}tLB &TS-Okϲa][nU* +^]0 `k`R[v!wWތW;BH^M=!͓nꍭ E#àl%,4XvTj>xTIv)CupsQbALIǡ6>5R5P xUM ^Dr躬GΚM#;#lځ@A{1PZ0F#{vDiL=:ag۲Xa4R|f)*eېfpĝTpu[9b#Ԝ5Desr_xw"` s֋WՑ 9Q#N@ʛ EzͲJJ)@d@*><_dۛ,(RZHRM- S jɌx):^`cҕnI}H9! ֫꧙<*N E,}ǣkgHHBY&W(EXYx&\rfiT%KGDtAr#vfVB!j*F*$K<ЂD5ݳ\t(9v6p9GNl6X?HK[|n^t9Iǫ! 7Ao'zg D7[ݸmbQɌ>BR(n=`ؾrdz™lSL4J`9b}]yEvㆰDߏf"i'x lr;bWr%;Y!oo^롡-U GTy`d5.>G-8b[;]k࿜3^ah80߆I]b2BZm[#q@y=_ d~ږ aCoqø_xZ6W3!@q,:.4'qxm1b-K @.0330yº_,i]t,S{O〈vKMEY6C('pm8˦Fqt)'!>nFmB|A)}iobg!9 T~Hee|$ T{QNWIENDB`perfbook_html/node134.html0000644000175000017500000001472111672746162015647 0ustar paulmckpaulmck 10.3.2.1 RCU is a Reader-Writer Lock Replacement


10.3.2.1 RCU is a Reader-Writer Lock Replacement

Perhaps the most common use of RCU within the Linux kernel is as a replacement for reader-writer locking in read-intensive situations. Nevertheless, this use of RCU was not immediately apparent to me at the outset, in fact, I chose to implement something similar to brlock before implementing a general-purpose RCU implementation back in the early 1990s. Each and every one of the uses I envisioned for the proto-brlock primitive was instead implemented using RCU. In fact, it was more than three years before the proto-brlock primitive saw its first use. Boy, did I feel foolish!

The key similarity between RCU and reader-writer locking is that both have read-side critical sections that can execute in parallel. In fact, in some cases, it is possible to mechanically substitute RCU API members for the corresponding reader-writer lock API members. But first, why bother?

Advantages of RCU include performance, deadlock immunity, and realtime latency. There are, of course, limitations to RCU, including the fact that readers and updaters run concurrently, that low-priority RCU readers can block high-priority threads waiting for a grace period to elapse, and that grace-period latencies can extend for many milliseconds. These advantages and limitations are discussed in the following sections.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node159.html0000644000175000017500000002316511672746162015660 0ustar paulmckpaulmck 10.3.4.5 Scalable Counter-Based RCU


10.3.4.5 Scalable Counter-Based RCU

Figure: RCU Per-Thread Reference-Count Pair Data
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}

Figure: RCU Read-Side Using Per-Thread Reference-Count Pair
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcpl.h) shows the read-side primitives of an RCU implementation that uses per-thread pairs of reference counters. This implementation is quite similar to that shown in Figure [*], the only difference being that rcu_refcnt is now a per-thread variable (as shown in Figure [*]), so the rcu_read_lock() and rcu_read_unlock() primitives no longer perform atomic operations.

Quick Quiz 10.45: Come off it! We can see the atomic_read() primitive in rcu_read_lock()!!! So why are you trying to pretend that rcu_read_lock() contains no atomic operations??? End Quick Quiz

Figure: RCU Update Using Per-Thread Reference-Count Pair
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void flip_counter_and_wa...
... 24 spin_unlock(&rcu_gp_lock);
25 smp_mb();
26 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcpl.c) shows the implementation of synchronize_rcu(), along with a helper function named flip_counter_and_wait(). The synchronize_rcu() function resembles that shown in Figure [*], except that the repeated counter flip is replaced by a pair of calls on lines 22 and 23 to the new helper function.

The new flip_counter_and_wait() function updates the rcu_idx variable on line 5, executes a memory barrier on line 6, then lines 7-11 spin on each thread's prior rcu_refcnt element, waiting for it to go to zero. Once all such elements have gone to zero, it executes another memory barrier on line 12 and returns.

This RCU implementation imposes important new requirements on its software environment, namely, (1) that it be possible to declare per-thread variables, (2) that these per-thread variables be accessible from other threads, and (3) that it is possible to enumerate all threads. These requirements can be met in almost all software environments, but often result in fixed upper bounds on the number of threads. More-complex implementations might avoid such bounds, for example, by using expandable hash tables. Such implementations might dynamically track threads, for example, by adding them on their first call to rcu_read_lock().

Quick Quiz 10.46: Great, if we have $N$ threads, we can have $2N$ ten-millisecond waits (one set per flip_counter_and_wait() invocation, and even that assumes that we wait only once for each thread. Don't we need the grace period to complete much more quickly? End Quick Quiz

This implementation still has several shortcomings. First, the need to flip rcu_idx twice imposes substantial overhead on updates, especially if there are large numbers of threads.

Second, synchronize_rcu() must now examine a number of variables that increases linearly with the number of threads, imposing substantial overhead on applications with large numbers of threads.

Third, as before, although concurrent RCU updates could in principle be satisfied by a common grace period, this implementation serializes grace periods, preventing grace-period sharing.

Finally, as noted in the text, the need for per-thread variables and for enumerating threads may be problematic in some software environments.

That said, the read-side primitives scale very nicely, requiring about 115 nanoseconds regardless of whether running on a single-CPU or a 64-CPU Power5 system. As noted above, the synchronize_rcu() primitive does not scale, ranging in overhead from almost a microsecond on a single Power5 CPU up to almost 200 microseconds on a 64-CPU system. This implementation could conceivably form the basis for a production-quality user-level RCU implementation.

The next section describes an algorithm permitting more efficient concurrent RCU updates.

Paul E. McKenney 2011-12-16
perfbook_html/node335.html0000644000175000017500000001423311672746163015651 0ustar paulmckpaulmck D.1.2.4 Cleaning Up Safely


D.1.2.4 Cleaning Up Safely

Cleaning up SRCU safely can be a challenge, but fortunately many uses need not do so. For example, uses in operating-system kernels that are initialized at boot time need not be cleaned up. However, uses within loadable modules must clean up if the corresponding module is to be safely unloaded.

In some cases, such as the RCU torture module, only a small known set of threads are using the SRCU read-side primitives against a particular struct srcu_struct. In these cases, the module-exit code need only kill that set of threads, wait for them to exit, and then clean up.

In other cases, for example, for device drivers, any thread in the system might be using the SRCU read-side primitives. Although one could apply the method of the previous paragraph, this ends up being equivalent to a full reboot, which can be unattractive. Figure [*] shows one way that cleanup could be accomplished without a reboot.

Figure: SRCU Safe Cleanup
\begin{figure}{ \scriptsize
\begin{verbatim}1 int readside(void)
2 {
3 int ...
...ize_srcu(&ss);
22 cleanup_srcu_struct(&ss);
23 }\end{verbatim}
}\end{figure}

The readside() function overlaps an RCU and an SRCU read-side critical section, with the former running from lines 5-11 and the latter running from lines 10-13. The RCU read-side critical section uses Pure RCU [McK04] to guard the value of the nomoresrcu variable. If this variable is set, we are cleaning up, and therefore must not enter the SRCU read-side critical section, so we return -EINVAL instead. On the other hand, if we are not yet cleaning up, we proceed into the SRCU read-side critical section.

The cleanup() function first sets the nomoresrcu variable on line 19, but then must wait for all currently executing RCU read-side critical sections to complete via the synchronize_rcu() primitive on line 20. Once the cleanup() function reaches line 21, all calls to readside() that could possibly have seen nomorersrcu equal to zero must have already reached line 11, and therefore already must have entered their SRCU read-side critical section. All future calls to readside() will exit via line 8, and will thus refrain from entering the read-side critical section.

Therefore, once cleanup() completes its call to synchronize_srcu() on line 21, all SRCU read-side critical sections will have completed, and no new ones will be able to start. It is therefore safe on line 22 to call cleanup_srcu_struct() to clean up.

Paul E. McKenney 2011-12-16
perfbook_html/node65.html0000644000175000017500000000750211672746162015571 0ustar paulmckpaulmck 6.4 Exact Limit Counters


6.4 Exact Limit Counters

To solve the exact structure-allocation limit problem noted in the Quick Quiz on page [*], we need a limit counter that can tell exactly when its limits are exceeded. One way of implementing such a limit counter is to cause threads that have reserved counts to give them up. One way to do this is to use atomic instructions. Of course, atomic instructions will slow down the fastpath, but on the other hand, it would be silly not to at least give them a try.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img193.png0000644000175000017500000000327311672746076015327 0ustar paulmckpaulmckPNG  IHDR1R\9PLTE^\\MJK# b``ywwmkkXUV856C@@wuv.*+YtRNS@f0IDAThZ( 岀K$"3[uBx$*^[cekQi}{ CtiG5otIIF4rkHjy*zZh8ZnP9rATި X*4#5[0v+齲Gs2&ڒiFP YcQ4= J[ z'Cڅm&'Cz_,t.DX-J䳖c5Wה^FkHS W(*BYTcmӽs`TPJb81yAiM @{AqVBɥ#&]Q?6U̖Ol| Y޳j5(Tʇsn$wZ>PjludU.<(mia|87)'+M;;xjZwarĻcb,֜}hۃ-& ; ,eR2_3֣cr&[c*oż2rN&?'{u> Y[< J{^fC[: Lٔ~B" 0ubel~L&wkKJCtVu#zeeޱIqYq۸mD@#y3H`Z H"t܌pаЙ̺wQv=eRc xW޹k>p ߻p$gk u-睹{C}]nyp {l~[C"t2 E[ Uzdwܙk'8G@Xnn48"TsHHUR,I%̤8IP!z2䐦-H0CFEt)k0C9 R9GЦ kI=2jBs.sm:7/DFr}|ʳ 6/z>үxRxϰ){dzW;dl~y>LNU=q8F\~]~-4@V"L m|"U~+&NZ ۰BZ ղGq WYf^J&(9ei /b=hE\XPvÕR616ibcaΑ? ;1,(U8J]kX^ARKx*70[ $PwDۏC&0j2[Am]k2j{l;u'xlw _xlkںں=?폋~<aOsE(HgeN9@ vUj@tl(I3(s@~tNi~C UAK]W&c_ֿ4f n.O,.yT<;ѕ3}z:c‰F?>ۖ„{<'zؖ[[n8 (-z/ E]dz7}wbX[|~/ǰjh]dz7}H M0x_yT+ 9IENDB`perfbook_html/img249.png0000644000175000017500000001645711672746041015331 0ustar paulmckpaulmckPNG  IHDR&L*ZPLTE^\\MJK745ZWWFCCrpq# b``ywwvstmkkXUVNKL856iffC@@wuv.*+mjkCqtRNS@fIDATx} *&4]Tk ض9nf< BDU ^IE e gO\;Uf)y&w Iӕ\}iWZc[.`+uSz҇4V`YjUD͹1CvOӛwVQyz%P*SxU O-]WUĒVv1e45TqK+ťNj0eԗ}NurZɾV츬*4gz }mvFibh$5/Wm7Uy{"ΈPjYtPw_gc59T<7|A?r%,XJX̗g`n y?σ [bAi 7RKgi.d"˅y<PLm]MZ%;Do9z26>7h kdX9ƢúƙVy8;$k4WG']3!֦\opmC]YQ53`kZjZdh0!:@PE/PRytvk0itk603y毙MaJ1 tcgʽA`lJglGY涉ߛo,iՒ @dJ!'a37`Ix,S"}zm.oϭ}ɣyFniUAGώ&fZT,,kF&fcc5I W-mey+Ӌ5xVamQdQ5 ^Z9V)X c6< xZ\ɅNzԳhe'B M5ZtZ9IHJM 9)IRhQ q@z>P:/lVBťۤYł@%xIXe#BZ5tI"3~l=}_gjN#;#,׬4QDU'U89`Ti;[D4HUwɤ}XYKiGҟҕu0ԋ?[}4\Ŝ=$rQlᮭOB#T9;-\8@+Mv;qRGmz!ٞeq pݭH: bE*z~"OR8+u2^c 3zJC޹ShwR&Tײ[P UjՒ}[И/Oק;ʛ8ٺc˸C˜=]O!O&N\wBˌ*T ft qXn.JU*/  Å ov`ObYI .5wbdv\:ӣYH;ʮok`n+C%*5 xڒ\erUד eru>QʠdV;*S28(7sZ~Y+joB.K` c"+%cREJAqXk{b?x/&K-%$Ammm'.)V7>nJyަs%.lH*H ^dy(iM_O.o3`sȜZYƕ|?=F'N mAݕ ֚(H6lް[]6Ӝ\/*OKdaGh|FDh2F/?rv@{򫒫YafSZZ6;p;rQQX%>Qʼ{ړa)hb6軳Jxe-9gQKuqוln@~Jx$ O5VW_u4 o}`;ayl'[ƣ(V5 5`J6ۣ͊D.-u6;hҘrBӾo'36_b|Ok MO"֒^yGz/-LeLfvRyK2^P>X 6 2YUjy'51=4دFPHGI~ 9]dsmSu?Yz=6EKnu jҢX{@mտ4Ug~ YMc'}C ^JzR[TDuk^L\v6/]Ƽ׉X*bХvA~{{2xJ,Gھ @|HtcHt9wc1V*~mIS([ty%1HH0&韾j?o!]enVR%Y+h4tApVaYcETifO{-}@D~Ծ_%#׌*x}U cSn%SQS]͝c.$`*5FKw "~mL+q>AN~BlGE&%ژ{<.:#xɎ얂Ӫejl/zUt.٤) _̯*Y&avL8HcByr=5ۇvv/udYCF/4aJ^jNxyye|-`޷bjQ7k]$ngdX_HG'}{7P#&u\mq5w>kc _Baޥ+iޭ+DQӀbO6qIs^D2 HAIlMrcdF"jſ.K|A+7APn2gÿir-h;k!e*=}|;*S";>m3wPGߦ!F;eL%ejOȭnFrPh:߇UrQaG2[[/s}Nlsq.k4ݶg aI*Lkw hA.XޘCM~:S-òܫj}⮕ S w#q82[>&.}8e'նZbq.o+uL~5&Kƒg|Pj<{T&"WrgwV$n")XCi/j҇L<I,ό!lNO/Qz xh+'%W< ?yL6@tUlҧޒۛ@ЈcbmSbe *"^ӗLGT%L(1Жbɦ ip'ܓ ׉X\.3>f~VqX]g,εTD\;E6T3&͵Op\\hɾoeeӋ⧼>L槼2O*EpAtMdU>UI70.QZz+܆+Em`ᣳ9:#->8|`ျr-RKCɪFZyΧSo$[UH ;yxfaCz͐%yNb^ Lq1 A!0i|K(3'&ʇ9` 4'vqm账F[*?lQ@ ݴPh0"tetZz@7292qOEړdKQ4r\⨅/`ݦsii0͆MT&Yi0q@qi0;\@绯lÂZaݴe 0@KXm+Լy*'gt"$?Βvdmyh Fh*l~)DZ|pE8 vvB!lFY;$DQO.4@/o lV%zܵӇ 7D!+0ԇ {('&Y-58/jwb;/A1w m5m|zK BBUuH'=P.r34"eXlE_Ki\pIy8N̈́,L7n~^?=˾ƝZHs5:V> RwhEF CtqP yLDa+a4.GCV(74}w u$t,IDRET%Y֐4[S lf\5ҜޗJ O%hqtGI$jA`1K"UJ<>%(Ca׭kGԵ|Hi3^k͏."MЀ&[ eNw n.iuODhJɳe(z̊r?5W=(u>zJZC:̥c1B-%%lIzϾn)*Q Z 8 J PMqC].iB@KtAд8Lڿ->Wex,\n J׶UܣY>kӍoyfX˜[z틹 "6R`:$eP.Jy(`$qQS,r"~-Z? I*Ż,4iWdP):j+jq<"RIN-)Lo2" !@ AaȠ|80J*C8zɕyoSE:^`zP=~iO}M}S=HuHÖ͢SR;GI .]SMBw$MtrSrnJ1OѣDdcrNŶȣInܿ R%eFN?9&GS4`'7S clgӏoޔ_T~ `%17ziEB_~֔U3ϙeAM:$bjug#l6QC^fGӣY]AnR5? XL,˦ѩ}Q6= ^s)Vtl:岀daL .¸Ȳ[ڗZdGNG< %o!TNv@gȖ *<ږ*J~ӛ* ç򔹇 %jM"quhRvÞ3bTEH}5b_cf~w{j4T,ta"5\{Ziu1NF;v4-&s FZNa?:&|^RhZpۑ@Պ,H(DIos xׅg!tM$GiU~Kf ( ,@ˈGKTedCʧim>YN;JkQ9<󴶗-K5iL=UIt*"pRiZkOr/ڑ̖?NU~kwkT.nP7v*]b/i蛠?]&A1j5xTRiicJ,I8gQڻrLcjNI;r "V/k:o)^28<~ә((M04k&.}CW<#:x)4{ۆi[y7jZ=}/nB|7I[S&i4h$?ho&i+W놛sm=KI/E osmדm}^R.(ZOҾ 7EצxWb8]Lk}ӖuT & 芣J?,]'<aڑ7S: fK;?%7E̺belz[?[G|U8-dV.~k;Rf Z37jhX͈~xIpnY^8NJWe\KJG+ Tz7Vt8ǎ~FÿW{ V\.{k|橩>Wt}.q;}z`F~O:qmb)]Lm2J'c܎?e їt}n.P+FrV|t]4?"ߢtë|ωfO,o:o}ŪX{LH{E_>>/k/X{)bH)ѵiג7Ey>oaݴ}!>0Ywf:5eB|0C_0IɻO 6-y_ϛ|6Y4?Ea~]]`%]U}]p2c۾M`צ7 aH[ ] ]~gTtPvЅ_PbB@w>GlLB?V}ֈ+%?j2$3DCVXs:aT M.ϵ䜳g ^?,ʋV;\+Kil`2&Gh%OCPrdpQ==ߺ % 9E!rX_Ԋ.wp+cr>wَyzuXH4OryIOfgTu!ofMxK$(=^55`zeA\;swsWQBފ^|̉1הMqp_[x3Sljj}O^"ػr7N4I3v˪E.+R v/n:+!/rw8M!ij1cˋQ7ލigs|ݭUF{MyʕPE.PSB,W4RUCۄ3FDp?x*Ed- NWmOZU69ISpN8ad |W0ߚڬi8P ٴNiq&/5 GF+ږjBv7䣖cwlHuUY&DT-,s MXUP54 BLxI#?95$m#(`&bIP|ѭ5a,3+a_y{iŷAr/+̯jyhŻkXuQͬ t!.7+3x+w[cm5<ӑ]³_g._jXwփumMJN~p]3Lz,NS 'w 82M띆(5 7.(NCyv};Әo.=}sѢɡw y ܎*]W{u/pؼnf--|v`Gf=k\S:f2 oA.;@kH>p!AӴ_գA_Q^ݥD!\QoyUs%RHHPXkRnjJz4B] ڙeO-XNK\ RlÅxcEz5]=V|95ѓEس!M?c8:?9Cw<&'jރ/ۖΘv!]ȐJB)Ƒu?#nߣv&x1~g|/ջϠǭRτI2n4g)MÈ~?>7IZv !t8vm?Mi3`r`Y/aWĺDm,lͪ6AEGL{Idpӹm1Nt?k'$ݯ}u!+U E͉fmY_lk3)#1cY)&D s39bn(,'09oI.?/ ;X!qY$4v&vrǶ9{ tq+YǞ~r-w(*rgK]>GJv\" ˵szH(Djz_{M[/~nW/0^ϭjWw>B\ٺC}%thԶ>m[>>.ʫG&_߀gti7GΔ~3zԌτ2EiMXQV3ؙih.G~ ?euWoHIENDB`perfbook_html/perfbook_html.html0000644000175000017500000021454511672746161017332 0ustar paulmckpaulmck 2.1 <

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Edited by:

Paul E. McKenney





Paul E. McKenney 2011-12-16
perfbook_html/img126.png0000644000175000017500000001377111672746143015322 0ustar paulmckpaulmckPNG  IHDRE C7?PLTEMJKPMM# b``vstmkkXUV856C@@wuv.*+ܴ~YtRNS@fhIDATx]*11h4$$ܾ$lB< MonNƪ,^S?s늹'@D@3p2/ 'bQ+[\x#ioLK+pq+XQ;S8r iQ}R=4@{e;98i(Zhqqi.wѭ:oǴR]6@p 3pIjnB8ǀ6QiX 4)փ08XlB2=~i)PQBϿ%'-G8F*ը#46>G{.ïC zT5rMԻlO5Pr6rXgڙY}x"156D12i+LD~j8z7B}qNj(!r>S }9RjUÞ1-Ԉ`'K# k+7p-'aiPc$ܲ͠:(zAѣc ",{DR|lxB4(_Źs+ч1GTJIC5FR[\Ir@aMO5ݟ|8kiw;[*_&hF RZ/: K eut? R>[LT2h+C7SQ&nWٕF@ $a|6ǒ@8}2KP)x݌Gp=G|T+1qUS&4?Qt $b\zlebJ Z&*PKmh裄6P(i{y1B6Dohn{Tc4 )Ԋ{[=8Gv6R6ٙZ{iw, DZE_D ]Bˆ]FM(ԮgTڀ:Pz"kXmtAGQSxF}U+! ^ό=q٠^{)\/b:\nDM,b"+~:P1%%b0~'>J _621>3= ŗ&3{t2H(1D!r5ċ6 >J|s>]?N 3\Gb_j'xRS ج h]lXf'Zĸb*"3HF()e  Fx ?JoGG1¯51jCo+"o*{z40Tٍ۞s43)W 6bk$bSZh/-}# 6gYSncCϊ*i<=ic^ذR(\^"mG0 u;5"2* xZoY67rG qQWa(^c!˺x qh \V=:$xPex&COe"6Iݲ3uߤ66o"}٢ai#H]b?yM[ ^W A?T ?ڱOCmHN{oC4޾}iHnN I pJ--q}RR5R#a@o"Wʘ}1P)|1p%EV܁cpr5\_xDmkYS#"mlԶ\9Ԩs757QMM=:pԁ(<ڥH9/2pqڕC9q2#Q?M Q> M]#[oyH \;nr吳ea+bz˥P6Bf"GF8&26$ŌF|LZ(DvCӪ"ĸ9X%a@ۭ69h1dyZT7uiiɛ+HiXbĭ$[E-?A*kRSvW<Y2jlîLyѕ&[7ס ɫ(0XL.RX#[i Q3;yp c1)-2PT j 7RMM+?9Eԋzn 󉏯T.K(-xxU ;6 Cb+M|'h(m=dϞ]\Rz'G6}?>o1>ʖ[_bcֆYqY;ٲ], Q-xK vW^XыD"Y/.\:+V9$V]6p&֘M,3Zߓ\j" y'ytdX,ޤ lt ܲY`Ic)7QPҍpXCQa֘cJRB(`Fn1ڋ}Åm2+3}rܴsﻷ`ER*T0y闊(wq^HF!%`K`P](~g5b#LA8FoNvQS |XqVx;KJY؉$5|2 wa }EwҦxL`15 j:K-u_n:g{O%0Eg #[Pp{td#ѷbsHS%ED p"lHUX2-Уq ZZaN;YmՉI>Q(fS}В_nӀ? 6b\ΘK07tE-綺ۗq( & E b/3(+Zqk,'/T\r nz;^fƲE{!)ȲT~Y(i?wcOo`=!~ِ3gf]׳b twmj\%ϜYZAA(8):>:VE9'LJv&2؃ s&N b֍vhS:$P=6ǜ|- n;2;0()'϶Ɣ[›tECΗ̊N4+hژԋoV\ C&S| E%Ȩy*C2Eg*[ ~CQ?"ʓ4#m ^@qEz@vm[`^Bo%ݐuB/x?ЧWgUUs/֜W *G7ʗa;XQk0+{+CcEIi:as!L\ٯ芊R`[[3n(]t+`nZnXهmcmP28xmU`֔`:݊[mܘ6rVi emFHq[!td־'XUT lqʁMBÖ2"iJ~)x>\ÖArI'4}؅ NL X/lעj **WdfGh#:nzUv!mk#L0Uq 6P\JDt|'i߀ߛ#N8+}*8VT|,lk#-0PڶM.p贆 ] {өMK)G'3Fa-^ۦ♣O$/PI֋`zcu= ;;*S|nb0$p`M|P{ә)ZW7vp܋)SD=>[QQRCBtŽ|D}N+&)^,8Y|Dc 1q{{^zR07>Ύg[W6l^4 r#`NA@o@q;>/G{QE˴ޠ$Tɳ^. ^{3o'Kϼ4TFP*x[&R =Q߻j>ZDf׆庲/ x굹LlJ&u"+!+ tGjyxf6֦T2=UKT 5L)RŔzؕC"[ýa Hn(1D+C+tѤTZUìm^JHm0YX2~*s5/ڑ%^zqǀ4:`ϭo@O׉+'VC+PqNwtVMS5 0o3]T@[9کx[Fbt2?"$`"QDxpV g~1 2xPqsH k73(<*EIJDvbJ XKaU2DS))II\63dݘJ43.F(>ݚO,J @U>744wuv.*+rppQz7tRNS@fpIDATx\ ( dTՙn٧bBQo+ݺ PAU7YI'ҳཋNUzz#HSlHHfq"p|J7P7Xuؚmn76eEA$Ʒ\-pG[쁴188]~TqY.*욧ŋJ|ݓӒ0M5 t< S.ɪy9j>"tۊ\]ъT_yc êp06= ޟ8D`|5">{,oF]^hcAY4T{fxml(nbY {dutC|_ݪAdp8cS~r,ޚI&{DV^v$[\vUY!I{E DZfSȀL;[sQ5xvz{%Q; xT!ID1.;hd]`'h}3*ܛ̗2N\mi dzmG]Mω9=7uay|(U4PВKG BXWזK\!NhӬj$B'.gî /Z^~{Yw<¦^o-1M#o ӈ3=X:mkGcFBaccCMlA × (?@geؘ2XZZ\'*!۲XI|T ? }'zzlwD-jPLH=*^@Rp qpOސ i.XbRÅa]w}i{͆JE!)ƕS?B6R&,*s޽4Yטtـ&RCf$7Ŗ†*%Փ?]Pu 1n/yv]=nH^Nݢ%ər|GߨXjhȏ8D>-MSQ(=F~=:<4uB`:O<̊/V"]3摃:)5ImWZaSA:'b*&9osهdkj0C!{rՋa86 S O H+GF6^qByofH3_1K-~:)g6z^[< dGrOiszeno[[HT&H0sPS$ב&2K B*>$HΆ0گl+4}H m$(rk􌁸o9yA?n949ɹe :js!;Dn9ekՉ`$ۚ #yb 4ufҐ98a,H+*V:=!3j>:mfQ LV:Gq?^paKn =mяaǙ4wu'vrVXP>:H }Oʑvע;z|wT؊#w&:Mƹyz"} jap@ƏEn} zr"ʔ(&G ׋eG(zI?|rwMry _f)\Y#Een!" =Gr ~%f,hb 8e`螌=xoHN*87Kv#9M,bbBNz1c_XtTr\6j" q)3@u*VWC0Kv2TXAةva?f#xa竟Rl`7C'i>@Tj O e0+A';OEwxOa2?5ɘ{g:xZUv3w#ʧ>?}ݒ{jƋWeLC*~FgGdNו>W2uhLNşsɤj7<# ٙX? >g]tMc^DIENDB`perfbook_html/node475.html0000644000175000017500000021652011672746164015662 0ustar paulmckpaulmck F.15 Chapter 

F.15 Chapter [*]

Quick Quiz [*].1: 
Why is sleeping prohibited within Classic RCU read-side critical sections?
 
Answer:
Because sleeping implies a context switch, which in Classic RCU is a quiescent state, and RCU's grace-period detection requires that quiescent states never appear in RCU read-side critical sections.

Quick Quiz [*].2: 
Why not permit sleeping in Classic RCU read-side critical sections by eliminating context switch as a quiescent state, leaving user-mode execution and idle loop as the remaining quiescent states?
 
Answer:
This would mean that a system undergoing heavy kernel-mode execution load (e.g., due to kernel threads) might never complete a grace period, which would cause it to exhaust memory sooner or later.

Quick Quiz [*].3: 
Why is it OK to assume that updates separated by synchronize_sched() will be performed in order?
 
Answer:
Because this property is required for the synchronize_sched() aspect of RCU to work at all. For example, consider a code sequence that removes an object from a list, invokes synchronize_sched(), then frees the object. If this property did not hold, then that object might appear to be freed before it was removed from the list, which is precisely the situation that synchronize_sched() is supposed to prevent!

Quick Quiz [*].4: 
Why must line 17 in synchronize_srcu() (Figure [*]) precede the release of the mutex on line 18? What would have to change to permit these two lines to be interchanged? Would such a change be worthwhile? Why or why not?
 
Answer:
Suppose that the order was reversed, and that CPU 0 has just reached line 13 of synchronize_srcu(), while both CPU 1 and CPU 2 start executing another synchronize_srcu() each, and CPU 3 starts executing a srcu_read_lock(). Suppose that CPU 1 reaches line 6 of synchronize_srcu() just before CPU 0 increments the counter on line 13. Most importantly, suppose that CPU 3 executes srcu_read_lock() out of order with the following SRCU read-side critical section, so that it acquires a reference to some SRCU-protected data structure before CPU 0 increments sp->completed, but executes the srcu_read_lock() after CPU 0 does this increment.

Then CPU 0 will not wait for CPU 3 to complete its SRCU read-side critical section before exiting the ``while'' loop on lines 15-16 and releasing the mutex (remember, the CPU could be reordering the code).

Now suppose that CPU 2 acquires the mutex next, and again increments sp->completed. This CPU will then have to wait for CPU 3 to exit its SRCU read-side critical section before exiting the loop on lines 15-16 and releasing the mutex. But suppose that CPU 3 again executes out of order, completing the srcu_read_unlock() prior to executing a final reference to the pointer it obtained when entering the SRCU read-side critical section.

CPU 1 will then acquire the mutex, but see that the sp->completed counter has incremented twice, and therefore take the early exit. The caller might well free up the element that CPU 3 is still referencing (due to CPU 3's out-of-order execution).

To prevent this perhaps improbable, but entirely possible, scenario, the final synchronize_sched() must precede the mutex release in synchronize_srcu().

Another approach would be to change to comparison on line 7 of synchronize_srcu() to check for at least three increments of the counter. However, such a change would increase the latency of a ``bulk update'' scenario, where a hash table is being updated or unloaded using multiple threads. In the current code, the latency of the resulting concurrent synchronize_srcu() calls would take at most two SRCU grace periods, while with this change, three would be required.

More experience will be required to determine which approach is really better. For one thing, there must first be some use of SRCU with multiple concurrent updaters.

Quick Quiz [*].5: 
Wait a minute! With all those new locks, how do you avoid deadlock?
 
Answer:
Deadlock is avoided by never holding more than one of the rcu_node structures' locks at a given time. This algorithm uses two more locks, one to prevent CPU hotplug operations from running concurrently with grace-period advancement (onofflock) and another to permit only one CPU at a time from forcing a quiescent state to end quickly (fqslock). These are subject to a locking hierarchy, so that fqslock must be acquired before onofflock, which in turn must be acquired before any of the rcu_node structures' locks.

Also, as a practical matter, refusing to ever hold more than one of the rcu_node locks means that it is unnecessary to track which ones are held. Such tracking would be painful as well as unnecessary.

Quick Quiz [*].6: 
Why stop at a 64-times reduction? Why not go for a few orders of magnitude instead?
 
Answer:
RCU works with no problems on systems with a few hundred CPUs, so allowing 64 CPUs to contend on a single lock leaves plenty of headroom. Keep in mind that these locks are acquired quite rarely, as each CPU will check in about one time per grace period, and grace periods extend for milliseconds.

Quick Quiz [*].7: 
But I don't care about McKenney's lame excuses in the answer to Quick Quiz 2!!! I want to get the number of CPUs contending on a single lock down to something reasonable, like sixteen or so!!!
 
Answer:
OK, have it your way, then! Set CONFIG_RCU_FANOUT=16 and (for NR_CPUS=4096) you will get a three-level hierarchy with with 256 rcu_node structures at the lowest level, 16 rcu_node structures as intermediate nodes, and a single root-level rcu_node. The penalty you will pay is that more rcu_node structures will need to be scanned when checking to see which CPUs need help completing their quiescent states (256 instead of only 64).

Quick Quiz [*].8: 
OK, so what is the story with the colors?
 
Answer:
Data structures analogous to rcu_state (including rcu_ctrlblk) are yellow, those containing the bitmaps used to determine when CPUs have checked in are pink, and the per-CPU rcu_data structures are blue. The data structures used to conserve energy (such as rcu_dynticks) will be colored green.

Quick Quiz [*].9: 
Given such an egregious bug, why does Linux run at all?
 
Answer:
Because the Linux kernel contains device drivers that are (relatively) well behaved. Few if any of them spin in RCU read-side critical sections for the many milliseconds that would be required to provoke this bug. The bug nevertheless does need to be fixed, and this variant of RCU does fix it.

Quick Quiz [*].10: 
But doesn't this state diagram indicate that dyntick-idle CPUs will get hit with reschedule IPIs? Won't that wake them up?
 
Answer:
No. Keep in mind that RCU is handling groups of CPUs. One particular group might contain both dyntick-idle CPUs and CPUs in normal mode that have somehow managed to avoid passing through a quiescent state. Only the latter group will be sent a reschedule IPI; the dyntick-idle CPUs will merely be marked as being in an extended quiescent state.

Quick Quiz [*].11: 
But what happens if a CPU tries to report going through a quiescent state (by clearing its bit) before the bit-setting CPU has finished?
 
Answer:
There are three cases to consider here:

  1. A CPU corresponding to a non-yet-initialized leaf rcu_node structure tries to report a quiescent state. This CPU will see its bit already cleared, so will give up on reporting its quiescent state. Some later quiescent state will serve for the new grace period.
  2. A CPU corresponding to a leaf rcu_node structure that is currently being initialized tries to report a quiescent state. This CPU will see that the rcu_node structure's ->lock is held, so will spin until it is released. But once the lock is released, the rcu_node structure will have been initialized, reducing to the following case.
  3. A CPU corresponding to a leaf rcu_node that has already been initialized tries to report a quiescent state. This CPU will find its bit set, and will therefore clear it. If it is the last CPU for that leaf node, it will move up to the next level of the hierarchy. However, this CPU cannot possibly be the last CPU in the system to report a quiescent state, given that the CPU doing the initialization cannot yet have checked in.

So, in all three cases, the potential race is resolved correctly.

Quick Quiz [*].12: 
And what happens if all CPUs try to report going through a quiescent state before the bit-setting CPU has finished, thus ending the new grace period before it starts?
 
Answer:
The bit-setting CPU cannot pass through a quiescent state during initialization, as it has irqs disabled. Its bits therefore remain non-zero, preventing the grace period from ending until the data structure has been fully initialized.

Quick Quiz [*].13: 
And what happens if one CPU comes out of dyntick-idle mode and then passed through a quiescent state just as another CPU notices that the first CPU was in dyntick-idle mode? Couldn't they both attempt to report a quiescent state at the same time, resulting in confusion?
 
Answer:
They will both attempt to acquire the lock on the same leaf rcu_node structure. The first one to acquire the lock will report the quiescent state and clear the appropriate bit, and the second one to acquire the lock will see that this bit has already been cleared.

Quick Quiz [*].14: 
But what if all the CPUs end up in dyntick-idle mode? Wouldn't that prevent the current RCU grace period from ever ending?
 
Answer:
Indeed it will! However, CPUs that have RCU callbacks are not permitted to enter dyntick-idle mode, so the only way that all the CPUs could possibly end up in dyntick-idle mode would be if there were absolutely no RCU callbacks in the system. And if there are no RCU callbacks in the system, then there is no need for the RCU grace period to end. In fact, there is no need for the RCU grace period to even start.

RCU will restart if some irq handler does a call_rcu(), which will cause an RCU callback to appear on the corresponding CPU, which will force that CPU out of dyntick-idle mode, which will in turn permit the current RCU grace period to come to an end.

Quick Quiz [*].15: 
Given that force_quiescent_state() is a three-phase state machine, don't we have triple the scheduling latency due to scanning all the CPUs?
 
Answer:
Ah, but the three phases will not execute back-to-back on the same CPU, and, furthermore, the first (initialization) phase doesn't do any scanning. Therefore, the scheduling-latency hit of the three-phase algorithm is no different than that of a single-phase algorithm. If the scheduling latency becomes a problem, one approach would be to recode the state machine to scan the CPUs incrementally, most likely by keeping state on a per-leaf-rcu_node basis. But first show me a problem in the real world, then I will consider fixing it!

Quick Quiz [*].16: 
But the other reason to hold ->onofflock is to prevent multiple concurrent online/offline operations, right?
 
Answer:
Actually, no! The CPU-hotplug code's synchronization design prevents multiple concurrent CPU online/offline operations, so only one CPU online/offline operation can be executing at any given time. Therefore, the only purpose of ->onofflock is to prevent a CPU online or offline operation from running concurrently with grace-period initialization.

Quick Quiz [*].17: 
Given all these acquisitions of the global ->onofflock, won't there be horrible lock contention when running with thousands of CPUs?
 
Answer:
Actually, there can be only three acquisitions of this lock per grace period, and each grace period lasts many milliseconds. One of the acquisitions is by the CPU initializing for the current grace period, and the other two onlining and offlining some CPU. These latter two cannot run concurrently due to the CPU-hotplug locking, so at most two CPUs can be contending for this lock at any given time.

Lock contention on ->onofflock should therefore be no problem, even on systems with thousands of CPUs.

Quick Quiz [*].18: 
Why not simplify the code by merging the detection of dyntick-idle CPUs with that of offline CPUs?
 
Answer:
It might well be that such merging may eventually be the right thing to do. In the meantime, however, there are some challenges:

  1. CPUs are not allowed to go into dyntick-idle mode while they have RCU callbacks pending, but CPUs are allowed to go offline with callbacks pending. This means that CPUs going offline need to have their callbacks migrated to some other CPU, thus, we cannot allow CPUs to simply go quietly offline.
  2. Present-day Linux systems run with NR_CPUS much larger than the actual number of CPUs. A unified approach could thus end up uselessly waiting on CPUs that are not just offline, but which never existed in the first place.
  3. RCU is already operational when CPUs get onlined one at a time during boot, and therefore must handle the online process. This onlining must exclude grace-period initialization, so the ->onofflock must still be used.
  4. CPUs often switch into and out of dyntick-idle mode extremely frequently, so it is not reasonable to use the heavyweight online/offline code path for entering and exiting dyntick-idle mode.

Quick Quiz [*].19: 
Why not simply disable bottom halves (softirq) when acquiring the rcu_data structure's lock? Wouldn't this be faster?
 
Answer:
Because this lock can be acquired from functions called by call_rcu(), which in turn can be invoked from irq handlers. Therefore, irqs must be disabled when holding this lock.

Quick Quiz [*].20: 
How about the qsmask and qsmaskinit fields for the leaf rcu_node structures? Doesn't there have to be some way to work out which of the bits in these fields corresponds to each CPU covered by the rcu_node structure in question?
 
Answer:
Indeed there does! The grpmask field in each CPU's rcu_data structure does this job.

Quick Quiz [*].21: 
But why bother setting qs_pending to one when a CPU is coming online, given that being offline is an extended quiescent state that should cover any ongoing grace period?
 
Answer:
Because this helps to resolve a race between a CPU coming online just as a new grace period is starting.

Quick Quiz [*].22: 
Why record the last completed grace period number in passed_quiesc_completed? Doesn't that cause this RCU implementation to be vulnerable to quiescent states seen while no grace period was in progress being incorrectly applied to the next grace period that starts?
 
Answer:
We record the last completed grace period number in order to avoid races where a quiescent state noted near the end of one grace period is incorrectly applied to the next grace period, especially for dyntick and CPU-offline grace periods. Therefore, force_quiescent_state() and friends all check the last completed grace period number to avoid such races.

Now these dyntick and CPU-offline grace periods are only checked for when a grace period is actually active. The only quiescent states that can be recorded when no grace period is in progress are self-detected quiescent states, which are recorded in the passed_quiesc_completed, passed_quiesc, and qs_pending. These variables are initialized every time the corresponding CPU notices that a new grace period has started, preventing any obsolete quiescent states from being applied to the new grace period.

All that said, optimizing grace-period latency may require that gpnum be tracked in addition to completed.

Quick Quiz [*].23: 
What is the point of running a system with NR_CPUS way bigger than the actual number of CPUs?
 
Answer:
Because this allows producing a single binary of the Linux kernel that runs on a wide variety of systems, greatly easing administration and validation.

Quick Quiz [*].24: 
Why not simply have multiple lists rather than this funny multi-tailed list?
 
Answer:
Because this multi-tailed approach, due to Lai Jiangshan, simplifies callback processing.

Quick Quiz [*].25: 
So some poor CPU has to note quiescent states on behalf of each and every offline CPU? Yecch! Won't that result in excessive overheads in the not-uncommon case of a system with a small number of CPUs but a large value for NR_CPUS?
 
Answer:
Actually, no it will not!

Offline CPUs are excluded from both the qsmask and qsmaskinit bit masks, so RCU normally ignores them. However, there are races with online/offline operations that can result in an offline CPU having its qsmask bit set. These races must of course be handled correctly, and the way they are handled is to permit other CPUs to note that RCU is waiting on a quiescent state from an offline CPU.

Quick Quiz [*].26: 
So what guards the earlier fields in this structure?
 
Answer:
Nothing does, as they are constants set at compile time or boot time. Of course, the fields internal to each rcu_node in the ->node array may change, but they are guarded separately.

Quick Quiz [*].27: 
I thought that RCU read-side processing was supposed to be fast! The functions shown in Figure [*] have so much junk in them that they just have to be slow! What gives here?
 
Answer:
Appearances can be deceiving. The preempt_disable(), preempt_enable(), local_bh_disable(), and local_bh_enable() each do a single non-atomic manipulation of local data. Even that assumes CONFIG_PREEMPT, otherwise, the preempt_disable() and preempt_enable() functions emit no code, not even compiler directives. The __acquire() and __release() functions emit no code (not even compiler directives), but are instead used by the sparse semantic-parsing bug-finding program. Finally, rcu_read_acquire() and rcu_read_release() emit no code (not even compiler directives) unless the ``lockdep'' lock-order debugging facility is enabled, in which case they can indeed be somewhat expensive.

In short, unless you are a kernel hacker who has enabled debugging options, these functions are extremely cheap, and in some cases, absolutely free of overhead. And, in the words of a Portland-area furniture retailer, ``free is a very good price''.

Quick Quiz [*].28: 
Why not simply use __get_cpu_var() to pick up a reference to the current CPU's rcu_data structure on line 13 in Figure [*]?
 
Answer:
Because we might be called either from call_rcu() (in which case we would need __get_cpu_var(rcu_data)) or from call_rcu_bh() (in which case we would need __get_cpu_var(rcu_bh_data)). Using the ->rda[] array of whichever rcu_state structure we were passed works correctly regardless of which API __call_rcu() was invoked from (suggested by Lai Jiangshan [Jia08]).

Quick Quiz [*].29: 
Given that rcu_pending() is always called twice on lines 29-32 of Figure [*], shouldn't there be some way to combine the checks of the two structures?
 
Answer:
Sorry, but this was a trick question. The C language's short-circuit boolean expression evaluation means that __rcu_pending() is invoked on rcu_bh_state only if the prior invocation on rcu_state returns zero.

The reason the two calls are in this order is that ``rcu'' is used more heavily than is ``rcu_bh'', so the first call is more likely to return non-zero than is the second.

Quick Quiz [*].30: 
Shouldn't line 42 of Figure [*] also check for in_hardirq()?
 
Answer:
No. The rcu_read_lock_bh() primitive disables softirq, not hardirq. Because call_rcu_bh() need only wait for pre-existing ``rcu_bh'' read-side critical sections to complete, we need only check in_softirq().

Quick Quiz [*].31: 
But don't we also need to check that a grace period is actually in progress in __rcu_process_callbacks in Figure [*]?
 
Answer:
Indeed we do! And the first thing that force_quiescent_state() does is to perform exactly that check.

Quick Quiz [*].32: 
What happens if two CPUs attempt to start a new grace period concurrently in Figure [*]?
 
Answer:
One of the CPUs will be the first to acquire the root rcu_node structure's lock, and that CPU will start the grace period. The other CPU will then acquire the lock and invoke rcu_start_gp(), which, seeing that a grace period is already in progress, will immediately release the lock and return.

Quick Quiz [*].33: 
How does the code traverse a given path through the rcu_node hierarchy from root to leaves?
 
Answer:
It turns out that the code never needs to do such a traversal, so there is nothing special in place to handle this.

Quick Quiz [*].34: 
C-preprocessor macros are so 1990s! Why not get with the times and convert RCU_DATA_PTR_INIT() in Figure [*] to be a function?
 
Answer:
Because, although it is possible to pass a reference to a particular CPU's instance of a per-CPU variable to a function, there does not appear to be a good way pass a reference to the full set of instances of a given per-CPU variable to a function. One could of course build an array of pointers, then pass a reference to the array in, but that is part of what the RCU_DATA_PTR_INIT() macro is doing in the first place.

Quick Quiz [*].35: 
What happens if a CPU comes online between the time that the last online CPU is notified on lines 25-26 of Figure [*] and the time that register_cpu_notifier() is invoked on line 27?
 
Answer:
Only one CPU is online at this point, so the only way another CPU can come online is if this CPU puts it online, which it is not doing.

Quick Quiz [*].36: 
Why call cpu_quiet() on line 41 of Figure [*], given that we are excluding grace periods with various locks, and given that any earlier grace periods would not have been waiting on this previously-offlined CPU?
 
Answer:
A new grace period might have started just after the ->onofflock was released on line 40. The cpu_quiet() will help expedite such a grace period.

Quick Quiz [*].37: 
But what if the rcu_node hierarchy has only a single structure, as it would on a small system? What prevents concurrent grace-period initialization in that case, given the code in Figure [*]?
 
Answer:
The later acquisition of the sole rcu_node structure's ->lock on line 16 excludes grace-period initialization, which must acquire this same lock in order to initialize this sole rcu_node structure for the new grace period.

The ->onofflock is needed only for multi-node hierarchies, and is used in that case as an alternative to acquiring and holding all of the rcu_node structures' ->lock fields, which would be incredibly painful on large systems.

Quick Quiz [*].38: 
But does line 25 of Figure [*] ever really exit the loop? Why or why not?
 
Answer:
The only way that line 25 could exit the loop is if all CPUs were to be put offline. This cannot happen in the Linux kernel as of 2.6.28, though other environments have been designed to offline all CPUs during the normal shutdown procedure.

Quick Quiz [*].39: 
Suppose that line 26 got executed seriously out of order in Figure [*], so that lastcomp is set to some prior grace period, but so that the current grace period is still waiting on the now-offline CPU? In this case, won't the call to cpu_quiet() fail to report the quiescent state, thus causing the grace period to wait forever for this now-offline CPU?
 
Answer:
First, the lock acquisitions on lines 16 and 12 would prevent the execution of line 26 from being pushed that far out of order. Nevertheless, even if line 26 managed to be misordered that dramatically, what would happen is that force_quiescent_state() would eventually be invoked, and would notice that the current grace period was waiting for a quiescent state from an offline CPU. Then force_quiescent_state() would report the extended quiescent state on behalf of the offlined CPU.

Quick Quiz [*].40: 
Given that an offline CPU is in an extended quiescent state, why does line 28 of Figure [*] need to care which grace period it is dealing with?
 
Answer:
It really does not need to care in this case. However, because it does need to care in many other cases, the cpu_quiet() function does take the grace-period number as an argument, so some value must be supplied.

Quick Quiz [*].41: 
But this list movement in Figure [*] makes all of the going-offline CPU's callbacks go through another grace period, even if they were ready to invoke. Isn't that inefficient? Furthermore, couldn't an unfortunate pattern of CPUs going offline then coming back online prevent a given callback from ever being invoked?
 
Answer:
It is inefficient, but it is simple. Given that this is not a commonly executed code path, this is the right tradeoff. The starvation case would be a concern, except that the online and offline process involves multiple grace periods.

Quick Quiz [*].42: 
Why not just expand note_new_gpnum() inline into check_for_new_grace_period() in Figure [*]?
 
Answer:
Because note_new_gpnum() must be called for each new grace period, including both those started by this CPU and those started by other CPUs. In contrast, check_for_new_grace_period() is called only for the case where some other CPU started the grace period.

Quick Quiz [*].43: 
But there has been no initialization yet at line 15 of Figure [*]! What happens if a CPU notices the new grace period and immediately attempts to report a quiescent state? Won't it get confused?
 
Answer:
There are two cases of interest.

In the first case, there is only a single rcu_node structure in the hierarchy. Since the CPU executing in rcu_start_gp() is currently holding that rcu_node structure's lock, the CPU attempting to report the quiescent state will not be able to acquire this lock until initialization is complete, at which point the quiescent state will be reported normally.

In the second case, there are multiple rcu_node structures, and the leaf rcu_node structure corresponding to the CPU that is attempting to report the quiescent state already has that CPU's ->qsmask bit cleared. Therefore, the CPU attempting to report the quiescent state will give up, and some later quiescent state for that CPU will be applied to the new grace period.

Quick Quiz [*].44: 
Hey! Shouldn't we hold the non-leaf rcu_node structures' locks when munging their state in line 37 of Figure [*]???
 
Answer:
There is no need to hold their locks. The reasoning is as follows:

  1. The new grace period cannot end, because the running CPU (which is initializing it) won't pass through a quiescent state. Therefore, there is no race with another invocation of rcu_start_gp().
  2. The running CPU holds ->onofflock, so there is no race with CPU-hotplug operations.
  3. The leaf rcu_node structures are not yet initialized, so they have all of their ->qsmask bits cleared. This means that any other CPU attempting to report a quiescent state will stop at the leaf level, and thus cannot race with the current CPU for non-leaf rcu_node structures.
  4. The RCU tracing functions access, but do not modify, the rcu_node structures' fields. Races with these functions is therefore harmless.

Quick Quiz [*].45: 
Why can't we merge the loop spanning lines 36-37 with the loop spanning lines 40-44 in Figure [*]?
 
Answer:
If we were to do so, we would either be needlessly acquiring locks for the non-leaf rcu_node structures or would need ugly checks for a given node being a leaf node on each pass through the loop. (Recall that we must acquire the locks for the leaf rcu_node structures due to races with CPUs attempting to report quiescent states.)

Nevertheless, it is quite possible that experience on very large systems will show that such merging is in fact the right thing to do.

Quick Quiz [*].46: 
What prevents lines 11-12 of Figure [*] from reporting a quiescent state from a prior grace period against the current grace period?
 
Answer:
If this could occur, it would be a serious bug, since the CPU in question might be in an RCU read-side critical section that started before the beginning of the current grace period.

There are several cases to consider for the CPU in question:

  1. It remained online and active throughout.
  2. It was in dynticks-idle mode for at least part of the current grace period.
  3. It was offline for at least part of the current grace period.

In the first case, the prior grace period could not have ended without this CPU explicitly reporting a quiescent state, which would leave ->qs_pending zero. This in turn would mean that lines 7-8 would return, so that control would not reach cpu_quiet() unless check_for_new_grace_period() had noted the new grace period. However, if the current grace period had been noted, it would also have set ->passed_quiesc to zero, in which case lines 9-10 would have returned, again meaning that cpu_quiet() would not be invoked. Finally, the only way that ->passed_quiesc could be invoked would be if rcu_check_callbacks() was invoked by a scheduling-clock interrupt that occurred somewhere between lines 5 and 9 of rcu_check_quiescent_state() in Figure [*]. However, this would be a case of a quiescent state occurring in the current grace period, which would be totally legitimate to report against the current grace period. So this case is correctly covered.

In the second case, where the CPU in question spent part of the new quiescent state in dynticks-idle mode, note that dynticks-idle mode is an extended quiescent state, hence it is again permissible to report this quiescent state against the current grace period.

In the third case, where the CPU in question spent part of the new quiescent state offline, note that offline CPUs are in an extended quiescent state, which is again permissible to report against the current grace period.

So quiescent states from prior grace periods are never reported against the current grace period.

Quick Quiz [*].47: 
How do lines 22-23 of Figure [*] know that it is safe to promote the running CPU's RCU callbacks?
 
Answer:
Because the specified CPU has not yet passed through a quiescent state, and because we hold the corresponding leaf node's lock, we know that the current grace period cannot possibly have ended yet. Therefore, there is no danger that any of the callbacks currently queued were registered after the next grace period started, given that they have already been queued and the next grace period has not yet started.

Quick Quiz [*].48: 
Given that argument mask on line 2 of Figure [*] is an unsigned long, how can it possibly deal with systems with more than 64 CPUs?
 
Answer:
Because mask is specific to the specified leaf rcu_node structure, it need only be large enough to represent the CPUs corresponding to that particular rcu_node structure. Since at most 64 CPUs may be associated with a given rcu_node structure (32 CPUs on 32-bit systems), the unsigned long mask argument suffices.

Quick Quiz [*].49: 
How do RCU callbacks on dynticks-idle or offline CPUs get invoked?
 
Answer:
They don't. CPUs with RCU callbacks are not permitted to enter dynticks-idle mode, so dynticks-idle CPUs never have RCU callbacks. When CPUs go offline, their RCU callbacks are migrated to an online CPU, so offline CPUs never have RCU callbacks, either. Thus, there is no need to invoke callbacks on dynticks-idle or offline CPUs.

Quick Quiz [*].50: 
Why would lines 14-17 in Figure [*] need to adjust the tail pointers?
 
Answer:
If any of the tail pointers reference the last callback in the sublist that was ready to invoke, they must be changed to instead reference the ->nxtlist pointer. This situation occurs when the sublists immediately following the ready-to-invoke sublist are empty.

Quick Quiz [*].51: 
But how does the code in Figure [*] handle nested NMIs?
 
Answer:
It does not have to handle nested NMIs, because NMIs do not nest.

Quick Quiz [*].52: 
Why isn't there a memory barrier between lines 8 and 9 of Figure [*]? Couldn't this cause the code to fetch even-numbered values from both the ->dynticks and ->dynticks_nmi fields, even though these two fields never were zero at the same time?
 
Answer:
First, review the code in Figures [*], [*], and [*], and note that dynticks and dynticks_nmi will never have odd values simultaneously (see especially lines 6 and 17 of Figure [*], and recall that interrupts cannot happen from NMIs).

Of course, given the placement of the memory barriers in these functions, it might appear to another CPU that both counters were odd at the same time, but logically this cannot happen, and would indicate that the CPU had in fact passed through dynticks-idle mode.

Now, let's suppose that at the time line 8 fetches ->dynticks, the value of ->dynticks_nmi was at odd number, and that at the time line 9 fetches ->dynticks_nmi, the value of ->dynticks was an odd number. Given that both counters cannot be odd simultaneously, there must have been a time between these two fetches when both counters were even, and thus a time when the CPU was in dynticks-idle mode, which is a quiescent state, as required.

So, why can't the && on line 13 of Figure [*] be replaced with an ==? Well, it could be, but this would likely be more confusing than helpful.

Quick Quiz [*].53: 
Why wait the extra couple jiffies on lines 12-13 in Figure [*]?
 
Answer:
This added delay gives the offending CPU a better chance of reporting on itself, thus getting a decent stack trace of the stalled code. Of course, if the offending CPU is spinning with interrupts disabled, it will never report on itself, so other CPUs do so after a short delay.

Quick Quiz [*].54: 
What prevents the grace period from ending before the stall warning is printed in Figure [*]?
 
Answer:
The caller checked that this CPU still had not reported a quiescent state, and because preemption is disabled, there is no way that a quiescent state could have been reported in the meantime.

Quick Quiz [*].55: 
Why does print_other_cpu_stall() in Figure [*] need to check for the grace period ending when print_cpu_stall() did not?
 
Answer:
The other CPUs might pass through a quiescent state at any time, so the grace period might well have ended in the meantime.

Quick Quiz [*].56: 
Why is it important that blocking primitives called from within a preemptible-RCU read-side critical section be subject to priority inheritance?
 
Answer:
Because blocked readers stall RCU grace periods, which can result in OOM. For example, if a reader did a wait_event() within an RCU read-side critical section, and that event never occurred, then RCU grace periods would stall indefinitely, guaranteeing that the system would OOM sooner or later. There must therefore be some way to cause these readers to progress through their read-side critical sections in order to avoid such OOMs. Priority boosting is one way to force such progress, but only if readers are restricted to blocking such that they can be awakened via priority boosting.

Of course, there are other methods besides priority inheritance that handle the priority inversion problem, including priority ceiling, preemption disabling, and so on. However, there are good reasons why priority inheritance is the approach used in the Linux kernel, so this is what is used for RCU.

Quick Quiz [*].57: 
Could the prohibition against using primitives that would block in a non-CONFIG_PREEMPT kernel be lifted, and if so, under what conditions?
 
Answer:
If testing and benchmarking demonstrated that the preemptible RCU worked well enough that classic RCU could be dispensed with entirely, and if priority inheritance was implemented for blocking synchronization primitives such as semaphores, then those primitives could be used in RCU read-side critical sections.

Quick Quiz [*].58: 
How is it possible for lines 38-43 of __rcu_advance_callbacks() to be executed when lines 7-37 have not? Won't they both be executed just after a counter flip, and never at any other time?
 
Answer:
Consider the following sequence of events:

  1. CPU 0 executes lines 5-12 of rcu_try_flip_idle().
  2. CPU 1 executes __rcu_advance_callbacks(). Because rcu_ctrlblk.completed has been incremented, lines 7-37 execute. However, none of the rcu_flip_flag variables have been set, so lines 38-43 do not execute.
  3. CPU 0 executes lines 13-15 of rcu_try_flip_idle().
  4. Later, CPU 1 again executes __rcu_advance_callbacks(). The counter has not been incremented since the earlier execution, but the rcu_flip_flag variables have all been set, so only lines 38-43 are executed.

Quick Quiz [*].59: 
What problems could arise if the lines containing ACCESS_ONCE() in rcu_read_unlock() were reordered by the compiler?
 
Answer:

  1. If the ACCESS_ONCE() were omitted from the fetch of rcu_flipctr_idx (line 14), then the compiler would be within its rights to eliminate idx. It would also be free to compile the rcu_flipctr decrement as a fetch-increment-store sequence, separately fetching rcu_flipctr_idx for both the fetch and the store. If an NMI were to occur between the fetch and the store, and if the NMI handler contained an rcu_read_lock(), then the value of rcu_flipctr_idx would change in the meantime, resulting in corruption of the rcu_flipctr values, destroying the ability to correctly identify grace periods.
  2. Another failure that could result from omitting the ACCESS_ONCE() from line 14 is due to the compiler reordering this statement to follow the decrement of rcu_read_lock_nesting (line 16). In this case, if an NMI were to occur between these two statements, then any rcu_read_lock() in the NMI handler could corrupt rcu_flipctr_idx, causing the wrong rcu_flipctr to be decremented. As with the analogous situation in rcu_read_lock(), this could result in premature grace-period termination, an indefinite grace period, or even both.
  3. If ACCESS_ONCE() macros were omitted such that the update of rcu_read_lock_nesting could be interchanged by the compiler with the decrement of rcu_flipctr, and if an NMI occurred in between, any rcu_read_lock() in the NMI handler would incorrectly conclude that it was protected by an enclosing rcu_read_lock(), and fail to increment the rcu_flipctr variables.

It is not clear that the ACCESS_ONCE() on the fetch of rcu_read_lock_nesting (line 7) is required.

Quick Quiz [*].60: 
What problems could arise if the lines containing ACCESS_ONCE() in rcu_read_unlock() were reordered by the CPU?
 
Answer:
Absolutely none! The code in rcu_read_unlock() interacts with the scheduling-clock interrupt handler running on the same CPU, and is thus insensitive to reorderings because CPUs always see their own accesses as if they occurred in program order. Other CPUs do access the rcu_flipctr, but because these other CPUs don't access any of the other variables, ordering is irrelevant.

Quick Quiz [*].61: 
What problems could arise in rcu_read_unlock() if irqs were not disabled?
 
Answer:

  1. Disabling irqs has the side effect of disabling preemption. Suppose that this code were to be preempted in the midst of line 17 between selecting the current CPU's copy of the rcu_flipctr array and the decrement of the element indicated by rcu_flipctr_idx. Execution might well resume on some other CPU. If this resumption happened concurrently with an rcu_read_lock() or rcu_read_unlock() running on the original CPU, an increment or decrement might be lost, resulting in either premature termination of a grace period, indefinite extension of a grace period, or even both.
  2. Failing to disable preemption can also defeat RCU priority boosting, which relies on rcu_read_lock_nesting to determine which tasks to boost. If preemption occurred between the update of rcu_read_lock_nesting (line 16) and of rcu_flipctr (line 17), then a grace period might be stalled until this task resumed. But because the RCU priority booster has no way of knowing that this particular task is stalling grace periods, needed boosting will never occur. Therefore, if there are CPU-bound realtime tasks running, the preempted task might never resume, stalling grace periods indefinitely, and eventually resulting in OOM.

Of course, both of these situations could be handled by disabling preemption rather than disabling irqs. (The CPUs I have access to do not show much difference between these two alternatives, but others might.)

Quick Quiz [*].62: 
Suppose that the irq disabling in rcu_read_lock() was replaced by preemption disabling. What effect would that have on GP_STAGES?
 
Answer:
No finite value of GP_STAGES suffices. The following scenario, courtesy of Oleg Nesterov, demonstrates this:

Suppose that low-priority Task A has executed rcu_read_lock() on CPU 0, and thus has incremented per_cpu(rcu_flipctr, 0)[0], which thus has a value of one. Suppose further that Task A is now preempted indefinitely.

Given this situation, consider the following sequence of events:

  1. Task B starts executing rcu_read_lock(), also on CPU 0, picking up the low-order bit of rcu_ctrlblk.completed, which is still equal to zero.
  2. Task B is interrupted by a sufficient number of scheduling-clock interrupts to allow the current grace-period stage to complete, and also be sufficient long-running interrupts to allow the RCU grace-period state machine to advance the rcu_ctrlblk.complete counter so that its bottom bit is now equal to one and all CPUs have acknowledged this increment operation.
  3. CPU 1 starts summing the index==0 counters, starting with per_cpu(rcu_flipctr, 0)[0], which is equal to one due to Task A's increment. CPU 1's local variable sum is therefore equal to one.
  4. Task B returns from interrupt, resuming its execution of rcu_read_lock(), incrementing per_cpu(rcu_flipctr, 0)[0], which now has a value of two.
  5. Task B is migrated to CPU 2.
  6. Task B completes its RCU read-side critical section, and executes rcu_read_unlock(), which decrements per_cpu(rcu_flipctr, 2)[0], which is now -1.
  7. CPU 1 now adds per_cpu(rcu_flipctr, 1)[0] and per_cpu(rcu_flipctr, 2)[0] to its local variable sum, obtaining the value zero.
  8. CPU 1 then incorrectly concludes that all prior RCU read-side critical sections have completed, and advances to the next RCU grace-period stage. This means that some other task might well free up data structures that Task A is still using!

This sequence of events could repeat indefinitely, so that no finite value of GP_STAGES could prevent disrupting Task A. This sequence of events demonstrates the importance of the promise made by CPUs that acknowledge an increment of rcu_ctrlblk.completed, as the problem illustrated by the above sequence of events is caused by Task B's repeated failure to honor this promise.

Therefore, more-pervasive changes to the grace-period state will be required in order for rcu_read_lock() to be able to safely dispense with irq disabling.

Quick Quiz [*].63: 
Why can't the rcu_dereference() precede the memory barrier?
 
Answer:
Because the memory barrier is being executed in an interrupt handler, and interrupts are exact in the sense that a single value of the PC is saved upon interrupt, so that the interrupt occurs at a definite place in the code. Therefore, if the rcu_dereference() were to precede the memory barrier, the interrupt would have had to have occurred after the rcu_dereference(), and therefore the interrupt would also have had to have occurred after the rcu_read_lock() that begins the RCU read-side critical section. This would have forced the rcu_read_lock() to use the earlier value of the grace-period counter, which would in turn have meant that the corresponding rcu_read_unlock() would have had to precede the first "Old counters zero [0]" rather than the second one. This in turn would have meant that the read-side critical section would have been much shorter -- which would have been counter-productive, given that the point of this exercise was to identify the longest possible RCU read-side critical section.

Quick Quiz [*].64: 
What is a more precise way to say "CPU 0 might see CPU 1's increment as early as CPU 1's last previous memory barrier"?
 
Answer:
First, it is important to note that the problem with the less-precise statement is that it gives the impression that there might be a single global timeline, which there is not, at least not for popular microprocessors. Second, it is important to note that memory barriers are all about perceived ordering, not about time. Finally, a more precise way of stating above statement would be as follows: "If CPU 0 loads the value resulting from CPU 1's increment, then any subsequent load by CPU 0 will see the values from any relevant stores by CPU 1 if these stores preceded CPU 1's last prior memory barrier."

Even this more-precise version leaves some wiggle room. The word "subsequent" must be understood to mean "ordered after", either by an explicit memory barrier or by the CPU's underlying memory ordering. In addition, the memory barriers must be strong enough to order the relevant operations. For example, CPU 1's last prior memory barrier must order stores (for example, smp_wmb() or smp_mb()). Similarly, if CPU 0 needs an explicit memory barrier to ensure that its later load follows the one that saw the increment, then this memory barrier needs to be an smp_rmb() or smp_mb().

In general, much care is required when proving parallel algorithms.

Paul E. McKenney 2011-12-16
perfbook_html/node378.html0000644000175000017500000001550711672746163015665 0ustar paulmckpaulmck D.3.3.3 __rcu_init()


D.3.3.3 __rcu_init()

Figure: __rcu_init() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1  ...

Figure [*] shows the __rcu_init() function and its RCU_DATA_PTR_INIT() helper macro. The __rcu_init() function is invoked during early boot, before the scheduler has initialized, and before more than one CPU is running.

The RCU_DATA_PTR_INIT() macro takes as arguments a pointer to an rcu_state structure and the name of a set of rcu_data per-CPU variables. This macro scans the per-CPU rcu_data structures, assigning the ->mynode pointer of each rcu_data structure to point to the corresponding leaf rcu_node structure. It also fills out the specified rcu_state structure's ->rda[] array entries to each point to the corresponding rcu_data structure. Line 3 picks up a pointer to the first leaf rcu_node structure in local variable rnp (which must be declared by the invoker of this macro), and line 4 sets local variable j to the corresponding leaf-node number of zero. Each pass through the loop spanning lines 5-10 performs initialization for the corresponding potential CPU (as specified by NR_CPUS). Within this loop, line 6 checks to see if we have moved beyond the bounds of the current leaf rcu_node structure, and, if so, line 7 advances to the next structure. Then, still within the loop, line 8 sets the ->mynode pointer of the current CPU's rcu_data structure to reference the current leaf rcu_node structure, and line 9 sets the current CPU's ->rda[] element (within the rcu_state structure) to reference the current CPU's rcu_data structure.

Quick Quiz D.34: C-preprocessor macros are so 1990s! Why not get with the times and convert RCU_DATA_PTR_INIT() in Figure [*] to be a function? End Quick Quiz

The __rcu_init() function first invokes rcu_init_one() on the rcu_state structure on line 19, then invokes RCU_DATA_PTR_INIT() on the rcu_state structure and the rcu_data set of per-CPU variables. It then repeats this for rcu_bh_state and rcu_bh_data on lines 21-22. The loop spanning lines 24-26 invokes rcu_cpu_notify() for each CPU that is currently online (which should be only the boot CPU), and line 27 registers a notifier so that rcu_cpu_notify() will be invoked each time a CPU comes online, in order to inform RCU of its presence.

Quick Quiz D.35: What happens if a CPU comes online between the time that the last online CPU is notified on lines 25-26 of Figure [*] and the time that register_cpu_notifier() is invoked on line 27? End Quick Quiz

The rcu_cpu_notify() and related functions are discussed in Section [*] below.

Paul E. McKenney 2011-12-16
perfbook_html/node470.html0000644000175000017500000001363611672746163015657 0ustar paulmckpaulmck F.10 Chapter 

F.10 Chapter [*]

Quick Quiz [*].1: 
Can a similar algorithm be used when deleting elements?
 
Answer:
Yes. However, since each thread must hold the locks of three consecutive elements to delete the middle one, if there are $N$ threads, there must be $2N+1$ elements (rather than just $N+1$ in order to avoid deadlock.

Quick Quiz [*].2: 
Yetch! What ever possessed someone to come up with an algorithm that deserves to be shaved as much as this one does???
 
Answer:
That would be Paul.

He was considering the Dining Philosopher's Problem, which involves a rather unsanitary spaghetti dinner attended by five philosophers. Given that there are five plates and but five forks on the table, and given that each philosopher requires two forks at a time to eat, one is supposed to come up with a fork-allocation algorithm that avoids deadlock. Paul's response was ``Sheesh! Just get five more forks!''.

This in itself was OK, but Paul then applied this same solution to circular linked lists.

This would not have been so bad either, but he had to go and tell someone about it!

Quick Quiz [*].3: 
Give an exception to this rule.
 
Answer:
One exception would be a difficult and complex algorithm that was the only one known to work in a given situation. Another exception would be a difficult and complex algorithm that was nonetheless the simplest of the set known to work in a given situation. However, even in these cases, it may be very worthwhile to spend a little time trying to come up with a simpler algorithm! After all, if you managed to invent the first algorithm to do some task, it shouldn't be that hard to go on to invent a simpler one.

Paul E. McKenney 2011-12-16
perfbook_html/node208.html0000644000175000017500000001532311672746162015650 0ustar paulmckpaulmck 14.2.4.7 Semantics Sufficient to Implement Locking

14.2.4.7 Semantics Sufficient to Implement Locking

Suppose we have an exclusive lock (spinlock_t in the Linux kernel, pthread_mutex_t in pthreads code) that guards a number of variables (in other words, these variables are not accessed except from the lock's critical sections). The following properties must then hold true:

  1. A given CPU or thread must see all of its own loads and stores as if they had occurred in program order.
  2. The lock acquisitions and releases must appear to have executed in a single global order.14.2
  3. Suppose a given variable has not yet been stored to in a critical section that is currently executing. Then any load from a given variable performed in that critical section must see the last store to that variable from the last previous critical section that stored to it.

The difference between the last two properties is a bit subtle: the second requires that the lock acquisitions and releases occur in a well-defined order, while the third requires that the critical sections not ``bleed out'' far enough to cause difficulties for other critical section.

Why are these properties necessary?

Suppose the first property did not hold. Then the assertion in the following code might well fail!



a = 1;
b = 1 + a;
assert(b == 2);


Quick Quiz 14.7: How could the assertion b==2 on page [*] possibly fail? End Quick Quiz

Suppose that the second property did not hold. Then the following code might leak memory!



spin_lock(&mylock);
if (p == NULL)
  p = kmalloc(sizeof(*p), GFP_KERNEL);
spin_unlock(&mylock);


Quick Quiz 14.8: How could the code on page [*] possibly leak memory? End Quick Quiz

Suppose that the third property did not hold. Then the counter shown in the following code might well count backwards. This third property is crucial, as it cannot be strictly with pairwise memory barriers.



spin_lock(&mylock);
ctr = ctr + 1;
spin_unlock(&mylock);


Quick Quiz 14.9: How could the code on page [*] possibly count backwards? End Quick Quiz

If you are convinced that these rules are necessary, let's look at how they interact with a typical locking implementation.

Paul E. McKenney 2011-12-16
perfbook_html/img195.png0000644000175000017500000001260711672746055015327 0ustar paulmckpaulmckPNG  IHDR6PLTEMJK# b``mkkXUV856C@@wuv.*+itRNS@fIDATx] Aq}$ ΖRҧͺZf3)0ؒlo6/ٟT?G (y^l$c $46Jsq` eiRYN,"'Ștw'oRoRob%'$F]i"x$r].qX')֗M@@)P?isNj3k?4lTޝZ9V–jJ &.X?9͜tDNSm紬ţsjcl6slj9̩ƦqU@MN͕&+bEQAv"Uw,!cWbV ?8/с^Kw>klo[v-RYT<#klr\id9Z9evWQ-*+ZRx;UMn ~d.Q}EG0kR?qELZHuG=S{"8h-YaNLԖ\yV2099fPUw(ۮOT0G'^~Owo+2yHSbkGlj3FˇOP1O|O? y?w{Igq(?Xc{|>ɝ$Aw|>8]ys6% YG=7dKי]jة'D$@.ȦE?6=;? |><ap+'l@|;r|R.{p6y!Aqmy8~H|qmy|%Ÿ[|?mU~k/Q%?1ًrh1u<?+|fdhSƗ1&:pm=ݖхYwA^,aJQ(,J.GSa'1ݪpAAz1khpBc?ǖ $Sz$L9ɺSWu%QM `Ci4{Ź.q!BA 0fl}z%`ӔxVD|C…nӽs>~F{"%҈CYŏ9:~ qO1G|?)~p7u4p1Q~<<&~V? jI#@n|_ 9aHt-5kke=݊uRO1T|uGsFğßs-d-y$)&Dʺa(Ɋ>(.bɂKib/^VsCQٵ_vt/&3^5g1kszGSr݂Î큮q9˩qʥ?%__| QY,w0R7G*M;K e3lewbsE> X&DShn%8 k/^%݀zJ30Y4wH+ ( k wh+,zk,ǭKϮ)~YBrXa5NhihN ݹ5eMNrE0^S2u<+;xXRG{);πit|gb(>UvFﲐ3m&61B9U6wWgNwENlq wNqg4'wknJb? `@F6:+ )wd;wqwN>+/5g r`AwBI;l;|ڜp/#۸CY;*4S! ΛC x&.S;ܛC(u"+ʏUJn2켨J`wŒ"Drzp.-!ޭTCNn}_ xwL!rGN^z-y0K;2Ԇ!eaIڡu<[ʡqh̡1#ln1!5;|+=FSgŤ{:7U#T2n4|qR+MC+#q1q^Q;$(p/5) wpD,1opxji}=wD^cUVpƪpuBqÝqwpHj!1C3<e?;[hNATNMp6iqrH)ywz߯;) rb_YhLӏy8wp;u~ey$>~/w,pǾ+ܡ7D.H;LL;kHֿ3._W9N1[;\79}"1dwς6'ayPOp|e$ w(XF>'1_N~p"q'~e|eAN#'"t2Pg;@D;w8wjg1(rv|g&UN.=/wUqǿ _|Kfe=sؿ )>^a_QZwݡBN]Cqɿ^ϸcǀwiks ^.Q{L@Qo ٽ3;~c&CN>3$Wc9ewNs91O9$$.9#n<>44u {J&aP)qo',:A7UE hw=cXWCA4|tݭNa/ԣ<Ꝇb)[n51 \zG%VQtM 4Q9W=g#T+DȒbM9,O[~UI^˭ݧ{Z?ɝX6moU~wf 8QBL(hAow'|ׯW~ߪwRG!i; pI@J jr葥ʞn;;H!sFȧ5[aa\?1pḢ^I+L]͛LhӋp7BEF*AqRXȧŭԃ;!]{@Z{GE8ɺu?Lcc%.ޡNPª?g&-~FVM!+3Ԧh {bJR0mEcf+(1vzl~~օ;+mJ4c!{3]?m=NW6mECmPgu|G7u|&$̖5/߁B_;0J~wU#S$Y=|]= r+߁=|zqK;bٲ;b ˊoǟ͛؊z^p߱g_;|Ͼ|g︠}wχ5|iѿjxl0VOdz;:=):6_ww;gw\M2flZ#A߰( $Sk`V.-yp!Tև`Q1&`+#~>OzQܱ(EkfwjCJX89TsY8h @o7v^I~PT`w]Zܮ[%:w2v2JQ.<{Y/;m;W|X6|(9o%yN0{+5nA5*t<4;T]MPy3As`dzd[[,7A;|X6|_իwJTs)*{8g3j;:Uyc>_&SԬYWgE|g4}_sM|g^R+~; 8YV0)-YsAYW0w|fwLY<_6?'7w ڗ\ӟ1x;1/Y苧gI{o5e6kaBwϢ}l/;>h_sMF|j7^*,j/_,ܚ[NڬSw\fwJWfcwϢ}l"Z Cvwyu5/߱bVgwU0ӯܿ6gbrV;>h; ˺u컕^mо|gg} ڗ\ӟZ;oΆwx ڜyywB߸|Ww`^w|о|c3T|<)~w&YO'm O^gF ̸v;sPؠMwla6S3U^/3nכ1%S<' zf2v[ؕ? No{EN3/ve펷dzLЎ|g4߱yx^pVCqc;a#잯yN`lY_X ܚ|'w&@wϠGoxMwRY&HNZI9 ٗ5'=0T9BFoIENDB`perfbook_html/img160.png0000644000175000017500000001347711672746054015324 0ustar paulmckpaulmckPNG  IHDR`h?PLTEb``MJK# hffvstmkkXUV856C@@wuv.*+~|tRNS@fIDATx](Ei@ZS *nQc7KBQ+15yVȝחmSH.$Vv^̿}>~۝wCwj\ T| jQmkD6x"|h:a<\ o?zt{SޏAPtQYͪ\BgNR)J\XԒHf/- XS+п"&ɮt뱗x=^Vc_w^;*sIE*| J{RĹןHיy\kz$,Mz_ŸYs9pTKDT|fj&W''eV͔O]ݮĩ)(p%qVPh+)>:>:=3>W'mw;q0F1 +TfkiU=o92yjRRmV۸@]!QK[`ed?'G H EI~/S&L8z/M qf^|ߵ6%4>+ &k%frADpd9 _K^+(3:BMRa'QlpÅ`:8 } N %)!Ӗzல=e QEUHo3Կቇݰ͵ucR> }λ~8[4ͼ 15 mDw|r2ioHSm56KmU!mI$]ޡabH>+˞! >SkP#9Xd5K@賱vJ*__oYɼ kOIP}L$B  GѢUB"y\RI$1 Ϙt\>uGǣfd{D& RTV/;q#w~;dyZBpE:pr%]ӥ$5l󞗨O>x)ds!UjN> <2Dd +O$^ 4/tӗƳ:0E:ꎒ9mfdUe|*Jb 2bV\`e+InW~Q!!<S LuUs!GCl[cV젟+ń="p8ҬRHGBM%SBHm UX4J'%v)r<09$RmSV iJ9#GFi,x&*9):pF #ŪP1.3 J<$;ZQNz;CNu'\f$u8ȹ<>Bq^ q.i"AN#ƲP4G}@E7sO?n™u;ل TRX%[HT?{c~Z?֛*E- 4ҠzVo.;[5mNkU g~62nCY,xZݿtzrQUQ\`'{Z-kgM PID9?k 8?_MHnvP@C$d)94/GL+dNgnH,PCj,dʭ9`)n1;x~]Z' ;֮a+<bz ON^*>&T%jZř>0zIO5ur.n|W\jc>Q,O 5i Cp5/@Z׷VP_ڊZ(?>KJHQ(<&Fش[O??HS\֒ *WE"$H#ѮJn]Y'5̓s#YR2VpkpC$vք`HD"U^x\&BmAf.hɀR')1`ÝqrN^ArHa  23HΔd!coSyrF3$Z sO>(c4+:"/[NW@Sm %GFKmcThO7[?dnAW>6{(%.tqgX8ZbθsuyU3 rc,r[}ib-mv}>l!t5tp]nPos: 1ÔwVE/AnS<:VQ^@;92:&g rӏ RƂ3OI>{g>ߕǬUWaҰVŰԥtp=QSƍuG&?+ܶ*6;e !X&ZXYx1XC<&Zp۳v^υ) Yc3:[|g'1у.NmGa'wi.I=L30 `O짹!{7 nc:[& A7=^Ynk!x 1T6ڟq!{ *Rϒ2Lo Rr=T27s5G8?o(y7;E*d1@( \P5 8Úpg`skϷ5aV|\~NLϾ|oOc5!*V|ښ`Hw5$6քsEGdMX1kL6; o_&6kqa)|Ҹ]9Prsٹ!8ޚ!pg}%KNokry {R =8+*r(9k_cJԷ_B&6i+L XQȓxM KQ3ޠ6%,pkh8 =SV:nHE&mM80cn_^tgvǝ| Doa͡z{^Az0䐷dU^5uj!`O\14!09,aF< \7z8{kOh);!7ϙ1B ]kAX]IU鋓g2yx˜<$P\$#MggF;޸Rrv[ğщb ډMyE/ѱo\ Jf!wޡW."vrlxBvnxT~ΞhVapbS\ND]{ƍsV#]jm6iJf%w=aWmz禙({Q|E1 ^ 1UjU5== ŧbʜáɱt.F*^izEOQI__ 6qb.2ճV0}kf*=f)l,=# >gJʩUWiNlj{[3"EabvaսwWPݸlfkTװ<2kqյ"^=*ƍvד4.Fz7n|/lf[f[]?Eʶns s&:c%\ 3 \GmmӦ#Hݜ!e9E p`g(Mjᙉ]?E (vg8耢b`3Ynmn9:\%Qj!: ϫ(((Td&_FAauŠ\EwszOQ܈ȋr'3Ðm{يZs%\$q3QN_WV6{Og-'NSԍ'wTV~3h+0ԳnO,ƚ$+z˳!DsG*n9jQÊ NU@kSEe@ UTH%uj^Ia&j%KF݌xYAw;^MT=E,B[ӵ)5**6%um+hu+z0)mTDǬIh5 V"(&$Њ)zQ ͨڦ9& x}n`*"&Ӡd;+!"d a腲J7&L 0şdӗK |y 4y(JVUjk RZhEFlzF󈖸,`Oll2)҄vitHv4iQlxr;p*Rl9Q d8գ&|N{DipBho\}o wI|"HyZݤTۊ&ߊ[tk@cَy#w}#;$$'=\c߸`"_}ަ_HSuܸqTl[5(2ArKڰ?cAq5AdZzAhpܘ+k~^E uϫFAh_R w7N,V7๸LH-cdY&lP:aĘ͏" |FI-=9^^vF6@Ll>$_[iғg|~-`یRt3b/- یoo)oJnIENDB`perfbook_html/node333.html0000644000175000017500000000643111672746163015650 0ustar paulmckpaulmck D.1.2.2 Read-Side Primitives


D.1.2.2 Read-Side Primitives

The read-side srcu_read_lock() and srcu_read_unlock() primitives are used as shown:



 1 idx = srcu_read_lock(&ss);
 2 /* read-side critical section. */
 3 srcu_read_unlock(&ss, idx);


The ss variable is the struct srcu_struct whose initialization was described in Section [*], and the idx variable is an integer that in effect tells srcu_read_unlock() the grace period during which the corresponding srcu_read_lock() started.

This carrying of an index is a departure from the RCU API, which, when required, stores the equivalent information in the task structure. However, since a given task could potentially occupy an arbitrarily large number of nested SRCU read-side critical sections, SRCU cannot reasonably store this index in the task structure.



Paul E. McKenney 2011-12-16
perfbook_html/img144.png0000644000175000017500000000520511672746065015316 0ustar paulmckpaulmckPNG  IHDR=BPLTEb``MJKZWWPMM# hffywwmkkXUV856iffC@@wuv.*+tRNS@f IDATh[b "(:w23ٶd qOcdCn^5`1hL,Z$n $4Q˵q]/B'2&i?7PSH1Iu' n@:w'rnhl gxO^wif, ;L)!u KGz b܋*ϩ?7i&6ϛYr-5D L~4A55"'}ÇZpPKd5~\ ]% ~v.-VIc ʻ8GM\RKB51p|p^ik!F۔?6d?9^nޕ5Fkڮ[xyڨ %Rgi -Fu+Řx6'Uֲ}ǒν;C)@r )n.jоHz偊fF ֞k0eGjx7K*Y?Gsk[x#mSI?W5sG-+N{G1f[C].h@ 1C!2ITl-z;6a+>*?j;h IT˛tWGhylsrx0&Qݜٚ(bsH",-$*E[2#~HAbʱX{ruX|_)QGa?WQAȥc%#\sͥlOJWvsINda88_9PLTEb``URSTRRMJK# hffmkkXUV856C@@wuv.*+ܿtRNS@fIDATx]A1Ǿ3b2Īb۶egN+ xJ"l>yDAA7nKFzGŁ=yg>x#|qzU(\ObYtN;殺azr`$t>^]*SebKP]}A/@(10NacMgr]0;@# Jp^L~X0#=es*T+"[{P㣡j6B{L_;}w'/"[zO/b;R2E8G^'Bqoajvf?aw4.0 GXxGFBdMPR?18 |tRB4c90cā qNr.5ɡTGY 4Ʀm'PF\hQQDlRew(#H[r:!wm[42j9-zpnym5YNDm~|EA7S!6NYvR{Qڡ ,*զoMdjq[M}bf_\Sr д;gX5E\ې;@x;L[fH}|._jz-)PlaE-/5ǁk,Sc ଔS/lz#e`rPTo1?udf/WKZ.(TM ]lHPRCi} g9agc$eќd} W $Z i# &[31DwbTE//`nR.ݨ4$˛UDp<<LXX~ݸ3j)Ƅ.ӷ7ulrjhzi>})}ݽdzQLP㟥7ŗ6 .ǹvsYˆŐ!cza8x6[AAQZS $O#r=!+ε^׋#\SEqO')h֫vr"t噏TUiLJwj  Gwv.M[Hf [Vk`Hћ^?/\똱?: 0`@*: B=Gp ш@q4w }zCC鍔SC?[khN8$c҄el x?UO?΄f1}4=Ni8\"LY3P"fb6vʲ% \5, u\(:OC؛#ț,4E'ϻ6ɍ}u0qIbp%i HImCb}!:GM;B񞚎 )ynH)!>)@)dUO]*k8ZYȰi0<1c}ǡ 5ad4ǰ-dfӺO˿;Eϴ(еlz5dʏ:)\y)M]h>+g>O U봤9wd}$Y<2 GGѶ 8&7N"8>ÀW| :P !1GvqY" u=^I{y`49K@ 7tg Y2ƶOz<p1R;:CcM5s^a'<%Ȏ>Ywvx1}_Y* _ ELUh`ڌۨ?-fB|1V#<}Қs;9Dcu k(>(cıIy{z'ƢMYp}8(ڛ6-/:rO6xGm؋*J:-]:,k\eV:/(U٤#Yv&hQK9qO#9._S-SeTw2յ[{l͟/ad茢͜0T|AF, f3y*.5Ĕ#L;7H¿H 9cuOqX} M/A˰T%=Ngu+ZT],P|&G)rX4L-K+tUOmٗGŰ| .eU`Fm7UX7b^^ Hش%"5h{8֣q@og*uuöW4v's/Vw#yh{o/c|~Cr`3몔Sx`_Q^ vi"(+v@>d-CsX2=J+?3o"P6)UQG?t2B˷KQ^4!OXZc٤+zר j{26I+HĎF`D )/y2lX=EYy vn{u<(=sh_a^CAr ȟMdnYXNYr)3 SfZT^x;{|A9QP0y"LރK͉$kpMzػ2!+$g|8FOn9i3cwY=ʕ9RW9ϖ TpGA:<7!o{d϶Vf`i0^M;_]) O"“1PlQH˻к {lg$)a4 r3";:.|_C+u\s %a>HhgA+Xo)~)rco㟳쳏Ю쟳V͢|UWlfJ}]\iqU.BqscyW)aRWddF3 fv1x_EWB9{x60`6 =M@1`ً_c;ռN@Y?+^:aq';3"u Tp闓UzǯMλek?w̥l߷ 4dɬҧ $R pWS9c_ZqKB$Ϟ| Cu$3w]YH6i&2V3=IBN/ 9G28S֪|y&T}aCLWTF4YGTSILd ~V}>Zߢ 8lO:U_ՇP_V_!>)\M([v_Ёt+d$e!h".)=gv{'z]%*V:׿l2>O>5pYڴ';G 9q,dQ^ȀrRgAʒ=GT]@|z=<@\f ?t7&%= '蜯kW_!%)!er 4fE! (wnJ%%3Dz%9-*%Pcvw ߀Mu.BωBB**~ 5A>]w!yw 5A`wsLr q&(/W$z]W ; fcn /F{}}EPjizWFQ6u{&Z?vCw?G;l wȒT0F42D4h][uޕCE!ʀ34y:u G0̚/Q%+T}ǴǩYD8Qw9n($nʘC1y']) 'jTI7Sb28UrfV}P|{ɯ RrL똼iSEl7N[q }T} y&tD}#q3ǐemGRizUN>1g4ѣ~ sp?ċZ %ZA;QAt/SvxvVsX<)G @o >G*qK-]:Qjk^{?֯{?ꗲ : N*0B瀷٧_05rp 4ZJYr|pE f%{Տ/<}0,Bt }7uPd[W̤JEJJS>(eQ-c9y3z=wc_b o8m %48fΕNTڅp٠a}A+1knoYZX^ zFOwVh!l .&R~^1UWdW2T}9h[}9w2̹oDUTrJnu $]}ꫵΡ כ{Al̍`\\칞 6 q4hmBXʋ5\e$Xy!R/&lkAl̍!5̓ qBKn5~W V=;t2oc*h4Ҥg}SĄ+ųou+އj9,J4O8uli[yIGMݸ6q&)HWlubuzIFP|r֓d)ۿ [-qr>LJIKl}Q}|ijt ihu|rY V ~<{He`\ub.|>F>i.FRƷ%Fa#`_?=c5y)AA5)T<8QKs8v8[;__Nü-9yx3b`>.VaIEᯪ$9΁K- elv8S"j( ti0ic9Tmçp N+{"Y@NܘOgmnz[jܽ#;DbBݝOY-f6xa@pn!*,e R7A S}ӄ;>I^}s`[fՔؗp;%3 &קkJuP|z,\_+t2ZISs90SP}Ezfue6/{$K k>HʱWzNWC7^uUm^w7*9_8Y RL}s-A*-^BHʂ)G,`EV}VTl1_Xt`%K6|&+'[t .1Lǻi 5l0 ^JXמw۷Tװs;C93Nڽғ}5o-IENDB`perfbook_html/node247.html0000644000175000017500000000462311672746162015654 0ustar paulmckpaulmck 16. Time Management


16. Time Management

Scheduling ticks

Tickless operation

Timers

Current time, monotonic operation

The many ways in which time can appear to go backwards

Causality, the only real time in SMP (or distributed) systems


Paul E. McKenney 2011-12-16
perfbook_html/node286.html0000644000175000017500000000473011672746162015656 0ustar paulmckpaulmck B.4.1 DEFINE_PER_THREAD()

B.4.1 DEFINE_PER_THREAD()

The DEFINE_PER_THREAD() primitive defines a per-thread variable. Unfortunately, it is not possible to provide an initializer in the way permitted by the Linux kernel's DEFINE_PER_THREAD() primitive, but there is an init_per_thread() primitive that permits easy runtime initialization.



Paul E. McKenney 2011-12-16
perfbook_html/node233.html0000644000175000017500000001356111672746162015650 0ustar paulmckpaulmck 14.2.12.1.2 LOCK-Based Critical Sections:

14.2.12.1.2 LOCK-Based Critical Sections:

Although a LOCK-UNLOCK pair does not act as a full memory barrier, these operations do affect memory ordering.

Consider the following code:



  1 *A = a;
  2 *B = b;
  3 LOCK
  4 *C = c;
  5 *D = d;
  6 UNLOCK
  7 *E = e;
  8 *F = f;


This could legitimately execute in the following order, where pairs of operations on the same line indicate that the CPU executed those operations concurrently:



  3 LOCK
  1 *A = a; *F = f;
  7 *E = e;
  4 *C = c; *D = d;
  2 *B = b;
  6 UNLOCK



Table: Lock-Based Critical Sections
# Ordering: legitimate or not?
1 *A; *B; LOCK; *C; *D; UNLOCK; *E; *F;
2 *A; *B; LOCK; *C; *D; UNLOCK; *E; *F;
3 *F; *A; *B; LOCK; *C; *D; UNLOCK; *E;
4 *A; *B; LOCK; *C; *D; UNLOCK; *E; *F;
5 *B; LOCK; *C; *D; *A; UNLOCK; *E; *F;
6 *A; *B; *C; LOCK; *D; UNLOCK; *E; *F;
7 *A; *B; LOCK; *C; UNLOCK; *D; *E; *F;
8 *B; *A; LOCK; *D; *C; UNLOCK; *F; *E;
9 *B; LOCK; *C; *D; UNLOCK; *F; *A; *E;


Quick Quiz 14.13: Given that operations grouped in curly braces are executed concurrently, which of the rows of Table [*] are legitimate reorderings of the assignments to variables ``A'' through ``F'' and the LOCK/UNLOCK operations? (The order in the code is A, B, LOCK, C, D, UNLOCK, E, F.) Why or why not? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img261.png0000644000175000017500000001244511672746003015312 0ustar paulmckpaulmckPNG  IHDRT+HPLTEb``MJKZWW# hffqooommmkkXUV856iffKHHC@@wuv.*+* tRNS@fIDATx] ,F]tVN]@nnsA@XB@YEչp(GC EeP~:u`Ywp]tأbA9%)ZiN;`kaznEMOZ~uUΟm `(!3-d`x6g_Eח 0ݖftXB&;gw*p%xv.E*iaC Ty)]Z/dH(449`V3=q\ ʞ'@2ݹ\)74ᴎ e i6繟S벿)0?-o gHp`HTUjsH>= Gd`;Ti԰J/w˜~ ^6+TStD9]ZU;HEɛLYY:ΜWƪq`QD V?!WPfɰ^^݁Җ|> m,]^Vw{bG %"džr2s{i|Q0%˥} yywsgjUcK <נH+WOm }HW|@޼=δ~&'u9ݲkUhHK"Ҁe yI~Tb|)Z.W{ y~W2u>dedw˞XіQE*ml9BJBQsfظ\΀3X ZgeqY~RvP3QAU`yǵZ,iTup$[tGGz@yea]@本&n%tBZ]5dyFaOFGK|UFm?иpdN[0, jtL$PKY|2 6N83nd x C8=%]1}|آ~uJLܥrԘBCM."N+ W5pj2YP1y)ϞiL[ΣX󀁢S5gϟͱf@F4j[,{`zmw90"?v0uk#CYېnfU, qFu2ٝgda@vnb7wCLl~o9C M^g9s "/Ij@<'96fW#X!m gdx,X|]$T:fkD4:ۅWiyŕ*ocwd*aЊXp6G번([_9Cdc΄Y\y_-$KpJfz\P\Rv _#^AR m>Jj Zη=T&eܕcwR ZnK-veA:d1+ r’+yFJX{i0ţN"Jڍ#E: WQ^EİY"ں$2 DBczg5gO!g/C9V^7!9R9- 'E=$5r'5ҘtƂWPWVQnfhaBSIe%l>HN`ReZj:1,fIpB_gTgihheB/1:qՍ!8,,!m㜅֞WCFV{D[|, z2#?EsQX7J:ҢYPB+7iZݥ_Mi|R ٍQL,8:2 $L n b#^p!}߆y3R / . q2$; K579g{@f^y`3FFczZfH`8VIBA(qY.N8K8?)b7|?'㴳8+op"ޒR֣XyrǻI1mRv7cpnF{9}?' B `ǬӅWRdw@ lXqOF$@Yt5HQ0>WP~N }Yim:30JT ?8 jW|D yihf0[%B{Oc`h{"-?>8eJrq:S 3蟅!5yIX7AblWlTf2h+dZ;_qzv챩fV`^ҎM8KxkM_eġ2pAj9>S344P'{( *XC "򼨡@BGeiLwd\R9ZP(͙J[U1t7 O cS΂@Uoafuب 诊睯ޟQ`)0=0IZ}ȑ_=[ƧIA*=}$$p7m uDo';ǔm25W:]ˋhԢv9]Gʖw!Ո}R ͷ{rlnr>~*zb2`gT2c5j.3ϾMЧ_e *ʅ[-?đ?enmEK~`߅JjKo\ڶ?M ~zQ[eKmL-ZK[3ڮj*Xߏ4~3Usb{V33_0b'nH rg0RCUbOË xLɡ&pg5`E;{/q= unazW Z$Aも. Td9NKjQ!RqƯl'rnjɀ 3uvx7REmU)'m9ay`JjeXSu(ePw58|܁X^bi$H6R^ #?9t7*ȃMȏ][k?-pCqZX`a ,-BQ+#r֡/we| h{?WRcyETb@߽xɱ.4s#?J)Oukܨ4sr. /ngTfv8od2~ԍBP֍NB-}q '}-{oܸqQ|crWPjeR=&9W»[˘csR,Ib߸xƍ$QŠY}s6jFIU/Vlcy-_ k:~+[<7أ穕f@oTNk%X] L$QW okGލdaKdMw T^:V:R pyٚZ&h9ܟ U 6n%;�7REnys碽(GYt7nܸq=f!91X[YNͶI%#Ԗ夣x&kKbd\Q\Byh3bmɝvV:i:o뛦caʒnr“q񥭚PnkQi:k;jJ8mION&]@\Ų˗6 ΈȺ4ozE͞dJ /'ަ7)9`WZ)oӒ7.}*-2> 'dbŹq:07]h{҈_Zʻ8v})վҒSoDgq#(XDr/;GE rYNRe$xO77x&7\KO^M˓%y1L=4q)0+uKcyh~G 3xIt$sͲoxIplQܸqؠ2?u-tͣKuO\,z4^ui=M졙׌*d|hə7dͣKC9nbkSu]oȊKcq AFxC^/m̏cv2=ܿFVNYHS.b"oSGukàcABXK㓮JhOZKM%mc•O fM;AB΢.c%d6JrK=#dxYh@(.uƍ b.x#zk&q}2?`Vy&VF4#ŝ*祃] HӮrVy&VY<*e8|I^tKr>V:[ɽ \?5Sm٠rBBYJ]x0ҏ?: E.7.2.5 Validating Interrupt Handlers


E.7.2.5 Validating Interrupt Handlers

The first step is to convert dyntick_nohz() to EXECUTE_MAINLINE() form, as follows:

  1 proctype dyntick_nohz()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   bit old_gp_idle;
  6
  7   do
  8   :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;
  9   :: i < MAX_DYNTICK_LOOP_NOHZ ->
 10     EXECUTE_MAINLINE(stmt1,
 11       tmp = dynticks_progress_counter)
 12     EXECUTE_MAINLINE(stmt2,
 13       dynticks_progress_counter = tmp + 1;
 14       old_gp_idle = (grace_period_state == GP_IDLE);
 15       assert((dynticks_progress_counter & 1) == 1))
 16     EXECUTE_MAINLINE(stmt3,
 17       tmp = dynticks_progress_counter;
 18       assert(!old_gp_idle ||
 19              grace_period_state != GP_DONE))
 20     EXECUTE_MAINLINE(stmt4,
 21       dynticks_progress_counter = tmp + 1;
 22       assert((dynticks_progress_counter & 1) == 0))
 23     i++;
 24   od;
 25   dyntick_nohz_done = 1;
 26 }

It is important to note that when a group of statements is passed to EXECUTE_MAINLINE(), as in lines 11-14, all statements in that group execute atomically.

Quick Quiz E.14: But what would you do if you needed the statements in a single EXECUTE_MAINLINE() group to execute non-atomically? End Quick Quiz

Quick Quiz E.15: But what if the dynticks_nohz() process had ``if'' or ``do'' statements with conditions, where the statement bodies of these constructs needed to execute non-atomically? End Quick Quiz

The next step is to write a dyntick_irq() process to model an interrupt handler:

  1 proctype dyntick_irq()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   bit old_gp_idle;
  6
  7   do
  8   :: i >= MAX_DYNTICK_LOOP_IRQ -> break;
  9   :: i < MAX_DYNTICK_LOOP_IRQ ->
 10     in_dyntick_irq = 1;
 11     if
 12     :: rcu_update_flag > 0 ->
 13        tmp = rcu_update_flag;
 14       rcu_update_flag = tmp + 1;
 15     :: else -> skip;
 16     fi;
 17     if
 18     :: !in_interrupt &&
 19       (dynticks_progress_counter & 1) == 0 ->
 20       tmp = dynticks_progress_counter;
 21       dynticks_progress_counter = tmp + 1;
 22       tmp = rcu_update_flag;
 23       rcu_update_flag = tmp + 1;
 24     :: else -> skip;
 25     fi;
 26     tmp = in_interrupt;
 27     in_interrupt = tmp + 1;
 28     old_gp_idle = (grace_period_state == GP_IDLE);
 29     assert(!old_gp_idle || grace_period_state != GP_DONE);
 30     tmp = in_interrupt;
 31     in_interrupt = tmp - 1;
 32     if
 33     :: rcu_update_flag != 0 ->
 34       tmp = rcu_update_flag;
 35       rcu_update_flag = tmp - 1;
 36       if
 37       :: rcu_update_flag == 0 ->
 38         tmp = dynticks_progress_counter;
 39         dynticks_progress_counter = tmp + 1;
 40       :: else -> skip;
 41       fi;
 42     :: else -> skip;
 43     fi;
 44     atomic {
 45       in_dyntick_irq = 0;
 46       i++;
 47     }
 48   od;
 49   dyntick_irq_done = 1;
 50 }

The loop from line 7-48 models up to MAX_DYNTICK_LOOP_IRQ interrupts, with lines 8 and 9 forming the loop condition and line 45 incrementing the control variable. Line 10 tells dyntick_nohz() that an interrupt handler is running, and line 45 tells dyntick_nohz() that this handler has completed. Line 49 is used for liveness verification, much as is the corresponding line of dyntick_nohz().

Quick Quiz E.16: Why are lines 45 and 46 (the in_dyntick_irq = 0; and the i++;) executed atomically? End Quick Quiz

Lines 11-25 model rcu_irq_enter(), and lines 26 and 27 model the relevant snippet of __irq_enter(). Lines 28 and 29 verifies safety in much the same manner as do the corresponding lines of dynticks_nohz(). Lines 30 and 31 model the relevant snippet of __irq_exit(), and finally lines 32-43 model rcu_irq_exit().

Quick Quiz E.17: What property of interrupts is this dynticks_irq() process unable to model? End Quick Quiz

The grace_period process then becomes as follows:

  1 proctype grace_period()
  2 {
  3   byte curr;
  4   byte snap;
  5   bit shouldexit;
  6
  7   grace_period_state = GP_IDLE;
  8   atomic {
  9     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);
 10     printf("MDLI = %d\n", MAX_DYNTICK_LOOP_IRQ);
 11     shouldexit = 0;
 12     snap = dynticks_progress_counter;
 13     grace_period_state = GP_WAITING;
 14   }
 15   do
 16   :: 1 ->
 17     atomic {
 18       assert(!shouldexit);
 19       shouldexit = dyntick_nohz_done && dyntick_irq_done;
 20       curr = dynticks_progress_counter;
 21       if
 22       :: (curr - snap) >= 2 || (curr & 1) == 0 ->
 23         break;
 24       :: else -> skip;
 25       fi;
 26     }
 27   od;
 28   grace_period_state = GP_DONE;
 29   grace_period_state = GP_IDLE;
 30   atomic {
 31     shouldexit = 0;
 32     snap = dynticks_progress_counter;
 33     grace_period_state = GP_WAITING;
 34   }
 35   do
 36   :: 1 ->
 37     atomic {
 38       assert(!shouldexit);
 39       shouldexit = dyntick_nohz_done && dyntick_irq_done;
 40       curr = dynticks_progress_counter;
 41       if
 42       :: (curr != snap) || ((curr & 1) == 0) ->
 43         break;
 44       :: else -> skip;
 45       fi;
 46     }
 47   od;
 48   grace_period_state = GP_DONE;
 49 }

The implementation of grace_period() is very similar to the earlier one. The only changes are the addition of line 10 to add the new interrupt-count parameter, changes to lines 19 and 39 to add the new dyntick_irq_done variable to the liveness checks, and of course the optimizations on lines 22 and 42.

This model (dyntickRCU-irqnn-ssl.spin) results in a correct verification with roughly half a million states, passing without errors. However, this version of the model does not handle nested interrupts. This topic is taken up in the nest section.

Paul E. McKenney 2011-12-16
perfbook_html/img142.png0000644000175000017500000001165211672746141015312 0ustar paulmckpaulmckPNG  IHDR@7KPLTEb``TRRMJK# hffywwvstommmkkXUV856C@@A>>wuv.*+GtRNS@f IDATx]O_7igKsX\倈EJ=@)vR*5jUki ?Gzz#1U_4x}JkՎpm'>є[!]P9Z?^֓ir1|5o (UfquHf- s`S_ j}N&* Vc,nzsGЇg/ޒJ/i5XmC|߼W@_}"[zd#m5s0Z26VPAMU"{kvENGX=ꑂ*TUUDU7jw&`apÕ ts.KE>^]>\7ŝjT#^EFs nKNO#Un!ȘoT;?f:|ͅ^S'$"*N/뙍1-IWs5u&?dC!I;v"(ЖjֽOZE[ʒUG3^G lޫ eK? X@iqfi}}DŽ?UͰf[tn|Ҹb:UUjI7D=$5kmߟ*4#h Z'c$M#UQ/Dj$!3#7 ^DFR*"=k[?o)ns#:Iѽ u @ENNJO.^ЈZ26bAH՜P%|.۴/ K5{ב%ߨ/5!ՒLAWՈEdCV! #V(鲥~,jvGDy͆5lhB*nCßK/`Nщ՞PP%oQQAoҞYBj @eؘW 5T>055fQ"r#;,E-"ThP4X G +Eа.VP&AY+}#6}m.V[ԓB-STZ-߰;%CQn5KZ2վdX]U>p%G]})pc>&;XY}%5ùd~Ňc}h& K}( %p^2e'8/b^g =׏8`@˫{-CK4+P{J3ղ/CZT7ﲰs!vˏ3 3AeT0xV3TmY޲)mRHDi6cH|M*' x-Z;]ZrK? pϡFp-nЀǀpT:ZYba0q J\4yh"  hA G?9jrbK|6mxS320uzb&Rr.<`WhXb&60Zx7wlOr~ӉW΋0tn4?"$mR7JU>~^_MkH@sYyDžwozbMaYC{R狻CAL:^j(S=?:9 *ihۚ^!?U!VPE2O) _:BM)A~ ϲ?,D֝bV)^bnW"$(L$MrS(@e&)OY)ں.DY\o@-@?2b:E׳n %V>ʘĂE*4S*߅j9 zgV).R=YR=n-1?t@YGB /?(G!Y?\y}~ʏ*"W>\ݠ !oO(ܽB1R;~S P~+ckH]8[YZjyt2毾磾[FZ+c]wo|GJd-] LϜ'Z5LE|W%0%Qxye+C=`ȃVL/meU;1p߃Vv K4O+ 9V&\he'V^-WI + uTJFRFS}N&}i,s^UAP;1jڦѝ1ZN+ۏK)3hKkdh~Ckj/3A#YЍ7q<$ᎏ䃛$^ݱ?7glؿ~9Sࣤu;>>DI>IG{y7-֒1oAmǜfSmZ1X|0uC./uq?rmиo$IQ4]AKBbۃg&_vYʤe+GK RΆdhvnپXc0>%t04|2:dd|NM=mX|@?p@ZC v^= IQyo3yע#vShPe(hWzUʱ[t׭^=.CǸ"bDuޚJǦ]Ҡn=իgxUYJ ~WU &;Wp {=dŐlxMg64vu֊3vk2zH;_X \ E:0?ć'4\#Haqyhb ||>E{snE;1/!K8!W r؝ ]|ecWGWA*^2,TU2i>Y٧\W+W; \?=pum|%c*%$2QO~O?չַ|SfQOoάX٫0mQ_.Fxof-Q\t3o˸*^zg 8ݾlk engŹϽԗ-x/te}]^ϥbϽԗ-x/En>ӗ }MD8Ո_hľEhP ʽ6}%:E i>km?|t]h~Jd3i-q^IENDB`perfbook_html/img205.png0000644000175000017500000000021511672746122015302 0ustar paulmckpaulmckPNG  IHDR ͕APLTEMJKmkkC@@wuv≪tRNS@f IDATch`P```(`0``H"&i<fH6IENDB`perfbook_html/node263.html0000644000175000017500000001304111672746162015644 0ustar paulmckpaulmck 17.1.14 Discussion


17.1.14 Discussion

The obstacles to universal TM adoption lead to the following conclusions:

  1. One interesting property of TM is the fact that transactions are subject to rollback and retry. This property underlies TM's difficulties with irreversible operations, including unbuffered I/O, RPCs, memory-mapping operations, time delays, and the exec() system call. This property also has the unfortunate consequence of introducing all the complexities inherent in the possibility of failure into synchronization primitives, often in a developer-visible manner.
  2. Another interesting property of TM, noted by Shpeisman et al. [SATG+09], is that TM intertwines the synchronization with the data it protects. This property underlies TM's issues with I/O, memory-mapping operations, extra-transactional accesses, and debugging breakpoints. In contrast, conventional synchronization primitives, including locking and RCU, maintain a clear separation between the synchronization primitives and the data that they protect.
  3. One of the stated goals of many workers in the TM area is to ease parallelization of large sequential programs. As such, individual transactions are commonly expected to execute serially, which might do much to explain TM's issues with multithreaded transactions.

What should TM researchers and developers do about all of this?

One approach is to focus on TM in the small, focusing on situations where hardware assist potentially provides substantial advantages over other synchronization primitives. This is in fact the approach Sun took with its Rock research CPU [DLMN09]. Some TM researchers seem to agree with this approach, while others have much higher hopes for TM.

Of course, it is quite possible that TM will be able to take on larger problems, and this section lists a few of the issues that must be resolved if TM is to achieve this lofty goal.

Of course, everyone involved should treat this as a learning experience. It would seem that TM researchers have great deal to learn from practitioners who have successfully built large software systems using traditional synchronization primitives.

And vice versa.

Paul E. McKenney 2011-12-16
perfbook_html/node393.html0000644000175000017500000002067111672746163015660 0ustar paulmckpaulmck D.3.7.4 Checking for Dyntick-Idle Mode


D.3.7.4 Checking for Dyntick-Idle Mode

The dyntick_save_progress_counter() and rcu_implicit_dynticks_qs() functions are used to check whether a CPU is in dynticks-idle mode. The dyntick_save_progress_counter() function is invoked first, and returns non-zero if the CPU is currently in dynticks-idle mode. If the CPU was not in dynticks-idle mode, for example, because it is currently handling an interrupt or NMI, then the rcu_implicit_dynticks_qs() function is called some jiffies later. This function looks at the current state in conjunction with state stored away by the earlier call to dyntick_save_progress_counter(), again returning non-zero if the CPU either is in dynticks-idle mode or was in dynticks-idle mode during the intervening time. The rcu_implicit_dynticks_qs() function may be invoked repeatedly, if need be, until is returns true.

Figure: Code for dyntick_save_progress_counter()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 dyntick_save_prog...
...et)
15 rdp->dynticks_fqs++;
16 return ret;
17 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for dyntick_save_progress_counter(), which is passed a given CPU-rcu_state pair's rcu_data structure. Lines 8 and 9 take snapshots of the CPU's rcu_dynticks structure's ->dynticks and ->dynticks_nmi fields, and then line 10 executes a memory barrier to ensure that the snapshot is seen by all CPUs to have happened before any later processing depending on these values. This memory barrier pairs up with those in rcu_enter_nohz(), rcu_exit_nohz(), rcu_nmi_enter(), rcu_nmi_exit(), rcu_irq_enter(), and rcu_irq_exit(). Lines 11 and 12 store these two snapshots away so that they can be accessed by a later call to rcu_implicit_dynticks_qs(). Line 13 checks to see if both snapshots have even-numbered values, indicating that the CPU in question was in neither non-idle process state, an interrupt handler, nor an NMI handler. If so, lines 14 and 15 increment the statistical counter ->dynticks_fqs, which is used only for tracing. Either way, line 16 returns the indication of whether the CPU was in dynticks-idle mode.

Quick Quiz D.52: Why isn't there a memory barrier between lines 8 and 9 of Figure [*]? Couldn't this cause the code to fetch even-numbered values from both the ->dynticks and ->dynticks_nmi fields, even though these two fields never were zero at the same time? End Quick Quiz

Figure: Code for rcu_implicit_dynticks_qs()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_implicit_dynt...
...8 }
19 return rcu_implicit_offline_qs(rdp);
20 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_implicit_dynticks_qs(). Lines 9-12 pick up both new values for the CPU's rcu_dynticks structure's ->dynticks and ->dynticks_nmi fields, as well as the snapshots taken by the last call to dyntick_save_progress_counter(). Line 13 then executes a memory barrier to ensure that the values are seen by other CPUs to be gathered prior to subsequent RCU processing. As with dyntick_save_progress_counter(), this memory barrier pairs with those in rcu_enter_nohz(), rcu_exit_nohz(), rcu_nmi_enter(), rcu_nmi_exit(), rcu_irq_enter(), and rcu_irq_exit(). Lines 14-15 then check to make sure that this CPU is either currently in dynticks-idle mode ((curr & 0x1) == 0 and (curr_nmi & 0x1) == 0) or has passed through dynticks-idle mode since the last call to dyntick_save_progress_counter() (curr != snap and curr_nmi != snap_nmi). If so, line 16 increments the ->dynticks_fqs statistical counter (again, used only for tracing) and line 17 returns non-zero to indicate that the specified CPU has passed through a quiescent state. Otherwise, line 19 invokes rcu_implicit_offline_qs() (described in Section [*]) to check whether the specified CPU is currently offline.

Paul E. McKenney 2011-12-16
perfbook_html/index.html0000644000175000017500000000000011672746161024134 1perfbook_html/perfbook_html.htmlustar paulmckpaulmckperfbook_html/node103.html0000644000175000017500000000624411672746162015644 0ustar paulmckpaulmck 8.1 Staying Alive


8.1 Staying Alive

Given that locking stands accused of deadlock and starvation, one important concern for shared-memory parallel developers is simply staying alive. The following sections therefore cover deadlock, livelock, starvation, unfairness, and inefficiency.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node140.html0000644000175000017500000000567711672746162015656 0ustar paulmckpaulmck 10.3.2.1.6 RCU Grace Periods Extend for Many Milliseconds

10.3.2.1.6 RCU Grace Periods Extend for Many Milliseconds

With the exception of QRCU and several of the ``toy'' RCU implementations described in Section [*], RCU grace periods extend for multiple milliseconds. Although there are a number of techniques to render such long delays harmless, including use of the asynchronous interfaces where available (call_rcu() and call_rcu_bh()), this situation is a major reason for the rule of thumb that RCU be used in read-mostly situations.



Paul E. McKenney 2011-12-16
perfbook_html/node6.html0000644000175000017500000000771311672746161015507 0ustar paulmckpaulmck 3.2 Parallel Programming Goals


3.2 Parallel Programming Goals

The three major goals of parallel programming (over and above those of sequential programming) are as follows:

  1. Performance.
  2. Productivity.
  3. Generality.

Quick Quiz 3.3: Oh, really??? What about correctness, maintainability, robustness, and so on? End Quick Quiz

Quick Quiz 3.4: And if correctness, maintainability, and robustness don't make the list, why do productivity and generality? End Quick Quiz

Quick Quiz 3.5: Given that parallel programs are much harder to prove correct than are sequential programs, again, shouldn't correctness really be on the list? End Quick Quiz

Quick Quiz 3.6: What about just having fun? End Quick Quiz

Each of these goals is elaborated upon in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node22.html0000644000175000017500000001123411672746161015556 0ustar paulmckpaulmck 3.5.1 Quick Quizzes

3.5.1 Quick Quizzes

``Quick quizzes'' appear throughout this book. Some of these quizzes are based on material in which that quick quiz appears, but others require you to think beyond that section, and, in some cases, beyond the entire book. As with most endeavors, what you get out of this book is largely determined by what you are willing to put into it. Therefore, readers who invest some time into these quizzes will find their effort repaid handsomely with increased understanding of parallel programming.

Answers to the quizzes may be found in Appendix [*] starting on page [*].

Quick Quiz 3.14: Where are the answers to the Quick Quizzes found? End Quick Quiz

Quick Quiz 3.15: Some of the Quick Quiz questions seem to be from the viewpoint of the reader rather than the author. Is that really the intent? End Quick Quiz

Quick Quiz 3.16: These Quick Quizzes just are not my cup of tea. What do you recommend? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node431.html0000644000175000017500000002012211672746163015640 0ustar paulmckpaulmck E.5 Promela Example: Locking


E.5 Promela Example: Locking

Figure: Promela Code for Spinlock
\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...

Since locks are generally useful, spin_lock() and spin_unlock() macros are provided in lock.h, which may be included from multiple Promela models, as shown in Figure [*]. The spin_lock() macro contains an infinite do-od loop spanning lines 2-11, courtesy of the single guard expression of ``1'' on line 3. The body of this loop is a single atomic block that contains an if-fi statement. The if-fi construct is similar to the do-od construct, except that it takes a single pass rather than looping. If the lock is not held on line 5, then line 6 acquires it and line 7 breaks out of the enclosing do-od loop (and also exits the atomic block). On the other hand, if the lock is already held on line 8, we do nothing (skip), and fall out of the if-fi and the atomic block so as to take another pass through the outer loop, repeating until the lock is available.

The spin_unlock() macro simply marks the lock as no longer held.

Note that memory barriers are not needed because Promela assumes full ordering. In any given Promela state, all processes agree on both the current state and the order of state changes that caused us to arrive at the current state. This is analogous to the ``sequentially consistent'' memory model used by a few computer systems (such as MIPS and PA-RISC). As noted earlier, and as will be seen in a later example, weak memory ordering must be explicitly coded.

Figure: Promela Code to Test Spinlocks
\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...

These macros are tested by the Promela code shown in Figure [*]. This code is similar to that used to test the increments, with the number of locking processes defined by the N_LOCKERS macro definition on line 3. The mutex itself is defined on line 5, an array to track the lock owner on line 6, and line 7 is used by assertion code to verify that only one process holds the lock.

The locker process is on lines 9-18, and simply loops forever acquiring the lock on line 13, claiming it on line 14, unclaiming it on line 15, and releasing it on line 16.

The init block on lines 20-44 initializes the current locker's havelock array entry on line 26, starts the current locker on line 27, and advances to the next locker on line 28. Once all locker processes are spawned, the do-od loop moves to line 29, which checks the assertion. Lines 30 and 31 initialize the control variables, lines 32-40 atomically sum the havelock array entries, line 41 is the assertion, and line 42 exits the loop.

We can run this model by placing the above two code fragments into files named lock.h and lock.spin, respectively, and then running the following commands:



spin -a lock.spin
cc -DSAFETY -o pan pan.c
./pan


Figure: Output for Spinlock Test
\begin{figure}{ \scriptsize
\begin{verbatim}(Spin Version 4.2.5 -- 2 April 200...
...es)
unreached in proctype :init:
(0 of 22 states)\end{verbatim}
}\end{figure}

The output will look something like that shown in Figure [*]. As expected, this run has no assertion failures (``errors: 0'').

Quick Quiz E.1: Why is there an unreached statement in locker? After all, isn't this a full state-space search? End Quick Quiz

Quick Quiz E.2: What are some Promela code-style issues with this example? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img156.png0000644000175000017500000001741411672746034015322 0ustar paulmckpaulmckPNG  IHDR=z+O?PLTEb``MJKPMM# hffvstmkkXUV856C@@wuv.*+etRNS@f{IDATx](EeX.I@QUR-ٺ""B'!0B<Ht*}p8?F 4C)33ѱA-ߕk>b-JVRQ`@SGm>`/J[Fz};e؃ʕE+_]⿍rEib.+cYX}^J?7bXCCBN)6\e/X?R~h74 gc-B{G4 [ 7 DzѨ)󣋧+0֩jok/hթI`AGƸpBf2|/S} ϓџ>eɲ6׍:Dř>}ZHZE}k|F PM\K\-gĢj3}S;Cx=n7oj!޺@;T*]JLYکGF8UX=O@offR`KZvڂ.T=T) `nw7CٶQå{G{ܹ~(Z׿xXGJުZࣔmDWH{CV9~|,SŬ͔ `IjP(d I}ɢNjTX'-hQ9[^%.H؂U4PU0uY\4v6[VqFe_ͫl@ԭy`_ SOB47@qyo-T~ëi5'QRVlRӔ'CKڧ5RFoN@}XF( xےM& lYLY߃{[UpMՊ)L %k^(r E u%D% ecKk>H"P FD5FR+,dfDL,[|!#y_nrGߐ1~~E,G ʿFzy v ĘwA}E\@` (%l~pΌ;9^*矅8 F;W*h%bd$ \G[?[57e`.p"~eFO?%m?+Ey,yAp:+GщJU3:VэZSd7~;y  e (% W2m}7Cf!$"HKYq1v^ٜf%nȉz&FþAzR}UMBL*߆PÇ_TW9eHPgKU0P+T;r8çj)]"^C 4x }p f҉أbC״$ 7x> Fw !iS!|-I)%] #7=/eG}/XS[᪓w*h*pD0(np*c [AҪ1=ojEmx"!oտb~iո6ԋϨ4`c!TR\%~ paYr,Z~iCtW1e8@ m[=C]&ֿKY>DSgqo,vX!;p B2 cB[mZWJw(A(3h&8Ijzw qj(ےg5Ĝ'W%)?Yf=ݚTK?薓9#N?BD!#v=S*})XjԱ@,TyzKK\()ԨCQ'U4`4`5WB'RWvU9?}_K}fu!9*"ga@G8hFK .Y`햇cKtr{Gr/l-IL|OP' a?44~0dV*2 Idɞgk>6j3sB{ȏ BriY#{oz@'|dp|  )$TWW0 c{1r\Ftc*W%#;s+xiՐd@ .M:(*Xo$oʁq!)iI / U6%¸HgeW[99W8[V)zU3jtݭ+aNfQ]mN ?렧Ȧ? TX[a 7p8t.Ⱥ}Oi04# ji:oʲdo=%ıJ&v qPFNlF"{1OgG@WQr_S)5(ju@vS"^/W=>9ۅN҆DFe;5*?1z! a =,Ӟ$ E5GhDkmiҙC4FUÙQf_gTuTKSx6 3(3ikP6ijox K *_RzRUSVwK>yw UgD^Ϝu"gUGy]";ʙ@t$GN . N3/-DKP`C+|Wܔ oOW^itl&CU/GY[;4MtF[9Y<8ڬ, 5Yd[^ȼ€%TY gft;FMFkqsKʾ獷lWCǾ `}pkoNC] :lf"ֈָUۈ!3, k@ne˜,gߋ}Rzߥ!ODYD=ϨJS%ǰxe%H-ٓ;gu$Oy*,^$JmDK30~x< 7yjћ7>?h"5-x?RӽMde {3*ezW9(m!/̊WB?fc{ݫjz'j/&tgU:a?? rzE]u!dˀWfC'wM^mX:ܵ]ۂDsv' ̶4 ̂NT6(Q/Yl#v}hA+fTFltPK/d8[v,^.(ygg pr퀻)KB ]a$eN3 e0V fj';+EV<uY6mHr}zmΘ|F%+hvG,yJ&`Q~EX9B^\0*: cU څloCEm\ӹE#S_)z1q#$˄xq;ݽ|0UQ/q8ǝD:hAK,|[ݏziaQhȜ7P܏APֵPsB9 ^e7sWڨ})6TX0 M1FF߲٫Zw ZKF) 7[E[Z3D>*% /Pzq˶ nC7ee:32%45,L:Aݍ2W% L'}KՉ\j~+5O\e0knyσn,l8eȑ:L5(o/Ad҃qmLzŷ}9A"b⾵YOQHL}zR洫90;^wɸm|un5OM>lp'ebQF-OY.ⱁx4!C/B,GİjC۫MeU{,GVye0(S\U7|rKw0pݹו<&fwX6K7{zɩ 搏ۃM[g}ÍrM٫OR.+kZUI}ёh4뚎{4\μOEܬ*{iWڞvMۣn2X)Kb ->ty;ʮikA 6Ui~)ԣBk"Dy3s322vC+v֧$|N=|1J(cI=nKfyHYEmM6T{h+^ek*µ50a K7-3`fT2(ǙkŭJC/5=d) >ef@ڵtLEl1Ϳ;՞k ll{DHJ1WLUfS %cFf71MiFqt;8%~Atj}u?Aے(,'Ou$#+HD`֌X( kY'`Dy\OgXEg,fod镀C*c3֭avQ ^Nb雚*kb0g:et&ՙѼ/.J^s-_pgRYed| 8QgW7^{粅&###㋡ ;ϼo򟗣+>Ҝ}??a<3_yA Ϗ<,**ET>#cΑ!2;zêԯ,wa濗u ed|8 Y[!B:P{ q6Bˈ$3KկI}~yrql1ׇ.R\= qvHO -~Q lSF`dXy@iC jo?JTo)ʧfݑLz`3[J6>~/3Ni*C ڲ|q$Qꖫtvgͺ''6&? K2JF:AzVrHJ"\Ts:[fE⇐}毀\M3m}dJovח͛%뺇4SkېÅK?^߈J[.h ]+r,-J9oUTZsg^XѾY{ZY_s[,=ҲpTNsίȟ\֚}\^ ms K j/ nݩ{([3ѱ6RQ:!VL'3"_1o{9`MVvvM}8^y 9mFl86?g+~;.-ǁ\guUÎc# dHϢy+ Q ;ی ljf8(FsM{)䶂..ݲp]g\LBw?ʬ^Usvٲ?0fd$壟|wRS~/Cqk!Tc`'\o>èQj9(lԁ)%%TLFk($Xd'~=4яer+MG~M۶2qEi"|KNLP0G_7 L4ؽAW.ǶaWV֏n^pu"nmkYb1%%GϪ/]@ذ}&hl?Hl{ Iowכt<&YAavB3Z:v:+&̶9q1E'tL9YAXY۠HzKtj3tL‰ms73Ű 1W1sTpqx8K@@4$)+4.ΒDo6a(u%9:`Qܛ~̋?0=˭G`6s32yK/G@Ͻ`,3ᇑg|3"zGӘ+ΰt)!-tFf)~0Z]yִ|ȼmϠ[*Wl,3h6o}[ׁlA̼<ĥh6d|LinsԺe64p~sGfN(s1 IENDB`perfbook_html/img72.png0000644000175000017500000001602711672746047015242 0ustar paulmckpaulmckPNG  IHDR<WtRNSىHIDATx]+LrI$B Ѡ  ТQ"YhdrFhCld?Q.bXhQz1wsXRK~TWW&ǹ:(KJ/q‚5e#"߯g̒0-S=|ㆱ9 ;&ml$J'jYcuP JrlU13ձ᚞3.PzI$#th ė/R3C& /T(fE=BolŔ(LncYLFe a|ÒX>i7fր7|bۍFS۫|F?p,* >Ҁ%H˓tWZbaUذ%!C֛ -J6_#鱇>Thq`0RyROx=kԈsߩ4Qå`N |V#|;\ TlSp^\ _G-W0ocm LؿPE6 jPN\D_o^5m7qi;nx[,X:ޜ)RjMr./G=Qچ0I^k:v>|#0G +nFhuxD{we@xLDeY܌)F@vx Zɵ VT^qڴW 朖J&[jCBXAqF8mJŃ$Qݞx7ތPZ@9L$djp"M>Ühnr4+0 &{i. V.-2kKIQV'+s9A b׷W$rhK^Q] K rξj)e wߦV*s&%jp#}aoOT^Z5A_Y^ϻ+PG%$/ZvJp'S >>^}{/_ Dw1pm8tڭhqb`o !ḌC})߈y0{KR3DٛKRȇlLP а<q" (~,:xP٤b)d% UkDAUc|2gtilW>TY"wSE(KCZqh+2#  [>r\v 1OP1U>A%N^ê;(էkHV |h?Ԏ]E*{Â8kXXTmGA<}5ɺ#a(pӰ@Dpab,x\DY`iaP*rT  bۄ7iʄ}ּ! *-]%-HxήU\թ%%QN-o@aS/9\5aak7C FGX\5@LqanA Tl8Fg=PUsw{;θI*#3߷-muCMˁU.-3;|x1i0Gq 2Z{t#@QnƷz}FiqK{d]ăPRF79.i~l4^ ,K%v c g\63.8~$V'3,cYvk;3 Zңӭf9I. [ކspMslr"zJ_ś'r{D#GK钬Tr0ڵIDÇtߞ*8'6B?𣵨Kw(@S۠Aud-%I(TZ0 *aX8n9/=kvloPqyy{Tm0&yL B|aLI'\Sze? Lf Ά^hPf  [KbL]t PM|Ẋ$z4!HIʼn=oIqGɱw 8K/!I%! ވt`ͼ(*ʟp\|E*f$V L7R<*5*BTZEGEݠAqmElP-N}*^/'0a]VOJC\y8Wmu%@D8 4}:ǃB( cj,\H.~_ (46Gɤ,B=Πb ۻ@b瀞A؈kRmڡ~"mԧ$LU~=Iub@g-ŠŤ˩8x۝3vСrp-'`Q _a D5<2.7_n_x%1Dx~y *qozFUl#I=W~elwI~KIF3@G H 5Fȶ o3 (!3؄'?$EvlڑE|1)3oJ\m3o{ky^%>ΐ w X`TM@8d[gNNؿdO9&W:WZSKx7%?oz*MJXtߦw}_fVt.K[^r7iV؛yW~2AdSk(©;(%A$7,v!FyCxD8Nzb&@e@2om6LV/ol{5Q{VyCx>o[>VFU콿9~#?s&p|m0]m2W]q@[gS#.yv]fZd^ܤ-7zw?'œύq,FK^|g^|g^|g^|g^|g^|g^Ȍ0b_T|J}Pӱ}.d,D|zG=c>(iMh?qīkTbd oM:SfV\" hs𵳑D"RSSqL[;;ѻcusmK2w|J}PӧV"O5);<@ } n] V%[?׮\V,wa/!>&:N1_ KUe}^?O jDCp5x*cym2} P@yi}W+k,]pA& :@M@"N װ뒒:@.o%o¢߯璒Ϻ8N@⿦KJ]Ϻ-*`A$.2 ![ѻvv֥¯uI0{h>򼎁=5]UPХQX3&:F$]˃P!Q9WDM֌qU=3~ T"|(j0d8hPi ?˧U\nT#@\9FqϚ!.* TG{*;j#iM=K ES&* h@NgqI*TKj2k9R~!M/ZXJW:p>aK2Cv #'%E«S(gϨ|Cy}L0<3>ڗB߬`+^_ OsT-ԏ *NDc=ϖ0sN< \GxP@;8@zI%jgH;vrEo9YdmK(h*!=%cR.p.5`9e\W7I^aASvI峎Al 6ޜ=3M~v73x;條P"\R7bgw`sӯO9pBpIz$#:x`8 y+73O;YvƉ\R zvZK{> o fGDǜl 'ksN~++ۗSv1tOk^3܂,U(CB_}dF"IVˀxmS?o{~rdbdCr׈Wsdx}\&'wz<"6e8.A d끲?w 3X6ViCq@p®&hjPݚCj,@fp9:^>h.+j́WT.)jeJQw;=U>"QWθ,Yè%EVʫJ4^RPڮlxPP5}g#Zd1H) Yr܌ CEpHUxU\tޛ;ze[g)5Ҥp~M p@Y=1<g`ȳpHPt\_z[}U o煇(6rOb1xh v׽cJp@Wc$=_}rĽ}r E=/VEE}9/JOX/;]p-[i+U1|a)X TEpg * 6GfaQ%$xh #UY?uMfÕG(p@AD-X%aU5# h Mq<jRI@["%V*[?ej7?g'2$ //7ׂv͕&kI?/y\UܧGKϼhs~;ii~"85X?Ɖ Aٳ;#mf@T wħz"UGaj{ڽ\lm捃끗ͼr0a_JlMwXs^[\^!@+!86@|V K FߠaDL 774_+g^%hq9˜Q[`NiIENDB`perfbook_html/node29.html0000644000175000017500000000766511672746161015602 0ustar paulmckpaulmck 4.1.4 Memory Barriers


4.1.4 Memory Barriers

Memory barriers will be considered in more detail in Section [*] and Appendix [*]. In the meantime, consider the following simple lock-based critical section:



  1 spin_lock(&mylock);
  2 a = a + 1;
  3 spin_unlock(&mylock);


Figure: CPU Meets a Memory Barrier
\resizebox{3in}{!}{\includegraphics{cartoons/barrier}}

If the CPU were not constrained to execute these statements in the order shown, the effect would be that the variable ``a'' would be incremented without the protection of ``mylock'', which would certainly defeat the purpose of acquiring it. To prevent such destructive reordering, locking primitives contain either explicit or implicit memory barriers. Because the whole purpose of these memory barriers is to prevent reorderings that the CPU would otherwise undertake in order to increase performance, memory barriers almost always reduce performance, as depicted in Figure [*].



Paul E. McKenney 2011-12-16
perfbook_html/node113.html0000644000175000017500000000515611672746162015646 0ustar paulmckpaulmck 9. Data Ownership

9. Data Ownership

Per-CPU and per-task/process/thread data.

Function shipping vs. data shipping.

Big question: how much local vs. global processing? How frequent, how expensive, ... Better to divide or to centralize?

Relationship to map/reduce? Message passing!

@@@ populate with problems showing benefits of coupling data ownership with other approaches. For example, work-stealing schedulers. Perhaps also move memory allocation here, though its current location is quite good.


Paul E. McKenney 2011-12-16
perfbook_html/node313.html0000644000175000017500000002022311672746163015641 0ustar paulmckpaulmck C.6.4 Example 3


C.6.4 Example 3

Table [*] shows three code fragments, executed concurrently by CPUs 0, 1, and 2. All variables are initially zero.


Table: Memory Barrier Example 3
CPU 0 CPU 1 CPU 2
1 a = 1;
2 smb_wmb();
3 b = 1; while (b == 0); while (b == 0);
4 smp_mb(); smp_mb();
5 c = 1; d = 1;
6 while (c == 0);
7 while (d == 0);
8 smp_mb();
9 e = 1; assert(e == 0 || a == 1);


Note that neither CPU 1 nor CPU 2 can proceed to line 5 until they see CPU 0's assignment to ``b'' on line 3. Once CPU 1 and 2 have executed their memory barriers on line 4, they are both guaranteed to see all assignments by CPU 0 preceding its memory barrier on line 2. Similarly, CPU 0's memory barrier on line 8 pairs with those of CPUs 1 and 2 on line 4, so that CPU 0 will not execute the assignment to ``e'' on line 9 until after its assignment to ``a'' is visible to both of the other CPUs. Therefore, CPU 2's assertion on line 9 is guaranteed not to fire.

Quick Quiz C.11: Suppose that lines 3-5 for CPUs 1 and 2 in Table [*] are in an interrupt handler, and that the CPU 2's line 9 is run at process level. What changes, if any, are required to enable the code to work correctly, in other words, to prevent the assertion from firing? End Quick Quiz

Quick Quiz C.12: If CPU 2 executed an assert(e==0||c==1) in the example in Table [*], would this assert ever trigger? End Quick Quiz

The Linux kernel's synchronize_rcu() primitive uses an algorithm similar to that shown in this example.

Paul E. McKenney 2011-12-16
perfbook_html/img303.png0000644000175000017500000001655411672746110015313 0ustar paulmckpaulmckPNG  IHDR x̤6PLTEb``MJK# hffmkkXUVROP856C@@wuv.*+%>_tRNS@fIDATx]E}TD̩۞ٝ3"PT}(HSY?ʝ܌^9XHu)WNZ nlkr "0`RAHrXTrNwRQZճ[#eElB{9SMøa $_(V4ӛI6w-J gy*d-o=x;Ե~;U\@'r8\XorIpXy7V^ھ0)~D'M#O  T=2 Z %(~Üy/]qMUy] ^R?m߲te=J76wx˾3URb/T/A`>iYj"yE 0Zj7Kr2NE,u>MY44"?%δKe]@gG (rݎƙ9Y3Ci R* xP;hޛaXyʾ]1.Rc8*GOؓ {-AEޡVYYs}A8>֏F&ܮf Ş\u1{~R ٳ`,//&-'+?_T( ¸2e/zxF{ 'JJRkAڶB!jDGT愿e4:)D[f\QTHMQKs5&@^AZf2 n2O3*+@Σvg3r ʍLPUiZ-=kԌ#\9.jOΊS)`iԌZ퐢NݹL}1{-4ZŌA/&]{웠+QcėxlBDa', ?GNN oAXb!=-SJ"a`G'3[omh-4qa)+0kku Y^;!Sr8J|3Yzİ,sRt ڎYI Bhg{ӈ7ocj8r7/^r 13J#DS0r^nkEa}jUmdPõAĒuZ{o̶w!Q>I̵pKД^-ۅ/p`a=IЎo K{Ӱ)f#uph7)=xe 0pҒƦ!\ kkKkTzҵkvɁR?b)C,w;9;& s ]ڑR~A{pVU(+;IQgA0UN>u:*ɒ݂_V-3C11(~#K}Oƴ@M/%gYGʃBKGt(s2@=J'!vœn ͠F+a x0ַ$KԚXD>|>[l9DCm88B[ð~%MmvzKD/2,@So$E`#+étW,Y[ûwM^Mt#+#{ ujk(I4fpOqq=\qq^ͯc3rK@42~89FKgqGt@ 8:2b9p>yrYOFFaP{^E{t}^#j|4es4:qQo:ZXL#~dir@]eapRgkj#u0vz,_r[e{xmDMx[rXo,ZCbi|Թ4n8 t~|~R=ܦ}Z[ӽ`UaDKw&f% E)~)eG 6Ɯ 'T &U+VDńiy&{P;F^.6{" $f~EړměE@yZGtQ`wK׵D_ϢV/AUCZђBă}(\ t2<(ZBL4t"39GΝ!fx:d\@ǜг o8tʷLD3Th(l )#:D1`d6\cQQ~Y(|x&s8j-%B8 ފ]v8`q_ٕs4GZ.(y!NI+2nt.8}`F ќMNQ /fPT)[|ʉa较ql]N 4cHLkeBRb$QV`턽B' vvNFD[|LLx2QI#I˯- _@}p!mfz`A#e)%=4#w:19pL؅A,ƒLU)/RՓowb@^dd Iylmތ$1ɔȶ҈g%7xJk,B]of5[Wv}L'j@PgW"Dqzٿ3I MN5| Ú7 P"#㕐/sHE$t[F؍~Oh$hK&(nt.#Z5YN5%,F,zLK{ܩ@OoS&N=-kcPtWsj$_䗷0zS pi Ww)tL+>0MK,h*wbtNraN)ѵJx8_s}5wXhI=? 8} y\Dܰ+LǤ R0fL1}-o}{F@F!x_;X2 pY# Y;B36;>֥C'ot994.# FX}|x.lu7r0M&QĹ=9=#9й%kٓ#y<֙]JNޡNࣥjTUӞcltE` X$ux&0zs&l}FqfTzNm[wعSie.{\G7Y[EG)tbwK _[ qww~%x; jT[ȵWZwQ-a6| ߜg.l*ew U,;s vB1^8KwL'8)zMϔ v`ت{H[eV6%f'8$ܬu+.BPP<,_k~4 ;>ufqi#f5PM(9ob >ҕ?'0+!um);;~`pgy/y!!Cr ~B'bJ=7ދ9]ztYɎumu#Llѳf 蓳͝4s[̍V U\MP- VKe<彝eL6F}bD] Q`tۣbtp 0WH.0:tbƌ΄es6x=N9?kIh ` d`wWh tՒۢ?Z:N`n3k'M 'Nr5`(Kσ5p<+v'EĶ u7x {6%hE,۞hylɷC>:_EM=W7dcJHޑ^6ƈ m- å1kU[YVL[DģjtvM&nM %.Zġжo05n^ƙ5ecž,< 4Ά+8bYytobfFEA]ӌޛrOζjĝi_V;3 B+Y ;++4V_{8/k}.}<,0&qm//b<{D|[^ >n鞋ʍDW<|c7$ 0E6sKVr &BlmYt?]dd8Ŕ^]{9SAj:p)6u<m8k5ő1+J8q3]~1ߑ TNyu(/ ΛVc^D(2vI(-?H@ m nKMv,#|9Fa Ϡ>!}>~-JTx~FxrD[*EO,ғJR ߋ<%dycsRAj37!% Yw#R^&2j1|o[w*V4|-7G`^VQޢQz18Du;|Z,?RXVwnVvi;w%fIls{YAW3]l5sa{zSBWMV)&|* {gWn"a{0;&dddddjWUet.ƊR$sdғwd_75u`IRj\_a] *oTV@lVh9"@1&8JT`8TeRE$+mPq&K==2>0e%6O4HPY7 Mj+ծVd 5>+m`? wE}5m3_oq:e|#!Tk/ VuaR'P>BպZN\zÃp66MSHP8%x Wq_gra؛KI#ږץo3'nު)Gm+i%TJ3wLHOt#M_diX8g6)߂S%@<]j UzLOInMF ˸bt0*:<|GHqu\1%aLmdta=U48p_x }ҧq O:.ǔuΫ1;Ac3XBHDJ/ePJ?'Ր)Y kQiaf/4g5 g܋ g ]耛i>#$8J u\BF%j+~lqّPdVLq9BYx? *]nbdfyv\u޹Ŗ|0R_Y-2mRl9ZN-bCeG _B9.Pkf%%kW/Fh-FhbˋBIVubxkBYWHڤ"%BPk ÚZk-0UT\k9sR5e{#`ef5_K؂3rE7;1:nxoQbXf5ct;NL]Z-3#%tɖ\fϹ-m2nenYv-X۾!F/n$ K 䗆BhJ4~XZ foTڌAhU+8Gkw*z#خy,;yUƵdվ]i+-jv|Sl./mTR[-== hj}6zMb3qTa@ 熝8h_aNIRSؾ;_bywpbx{?1 b^pmF%r>H)inF$[n1.ww? ^^`%x36|xfQ.f\ܙyNW; F0c,/;}&3˪D%kыh2Màa`tOiו5*tزxGעX Psh 7,tp2Kb[-eK_|#.i;zR鼺nX4ݏh5wGp]Fj -_jBD4;Hz4.2z]1܃yqp[ӲA ŵ>$i 7G:ZFKh47edývDp1ٚ= J:IPsU*cs7<'`F1{j`vsH5c߈3b@@Ov%W2 UO*|Oۀ;,Lc4ICt7^"_t>q ]%exVSU8A,K#Y4YO8JF}kA2Z,CUadUwy 3icգNT <"K>)=\Rb|xPl YSYH}uW:Y\\`NCt ˡ[ҸQ4٭H9I-*;Sr6aVh\ yVFH6񼑋>r Q_YgS[%Mꂢ1v"7:ҩ #Gt7`Ik#Vh ,41c1+Nm*RݻdNׁt,Ŀӿ4XՠIRQB A .p}2L^dY_ NThɥ" '+qxb4O=Y;K;![Z;TKYy>q"+}AL3T_“8mC;h8`x6|vvзyꡝT9}+'= O?S @J\!;Pj8ѩFrmd}C5u 9k2:״9[A߯{2OeysA wVATzvF f}*ooW,x|υA 2uv5F%(D 9 OcCoWщ ⧷it\"wtB#~%vLr kV e:ЫZ15/i%(W7W*+sqb鋾T/\~CF3\=%BIkxfNuuEp{*:|\dz`s\%\\uU ^NrM uF @Ww̔+g{deflk)o4@h8j1~QBUҰ&Nis~BUҰ& k~Π 4L27I0:yo'#/7A.yd_W k Ӄ?!_w; .3jǕ5f ZH+a46U>6R{닏QZlptFu SD,c:Ы4WyKPTzR e7cu>n*};t}uqvCķ.nf9q]?.a>~>4'׈-Ktx.yqF>Eɉ?9˯HqY΂_g%:ʔa2#@T$nj< WC(5:  H< 8+FI}Cyz8@ύځbUg:ԊX&|6>>^LttxPG~=Ѓ:ζ8:RqB'U3!CK[~ӿs~=xz'mɮc 1~E ^x/;5ٜ_I#_A!!~.yqӀ;Tį ˯/΀?2;elˈ׻FuW3&jD^l r\704ɯ%ޣJynoX`< ,#ASzg U_8#ޡ QHޙBUCM>]og9T\>! rM띉+tί0Eslgq+9~v<MG/4ɯ&> t _~M (kBf@~Fm$ޯjVe=Yӯ!LO_`&H@5QhXck_PְP&hݫRC-R$.oG<^;rWXOTQtjoUWqHېx* lVJv/\א-zR{_;6үOdyўbTS7ElzjC-R$.Ӷ#ݕE*___L Gdbu=v].~]*kd8x lki$/uvۺFmm+څr{45ɪY&GPr{4`RO+Z8;!~EP3PQv-U~{sdL&G;ul$w+VOqqB Cٲf,|P.sD۠﬘{ 4f.>*jz̹APE_Cñ A2+2E/h8߻6yA.w+XB2T  k;2_y L4#z3M>w2(/Y!ضw)`WwP/b."j;,o~EPH^而Xm[V@5{;Xbʯ'b."j;,o==x;N=z~UЄtU#`I[ ^p=ۯ'b."p~VY6]$blЫc>B#w b1cz̭*گri; u o38y#ѿYëͣo!OR_Jr{4Cn&]}!34ͯw%>[z> ގM>S<>N#Az=j:v6)@׉}'r8ޙB@_?d}t{xD#˜Ee&"Xw9E zNR0Kwb茍68zI~}$^*/:T_~}_o8i^:^Mɯ]Q-Pv#Nι-9/HkM%q(Ѳ:bj\}/Hkn3cҔ8ү*Q-vaYE{!^fہa^6T6hLfcC{;!7_ #w~x&qm/kMaLlT"' MH.^"9Q[U-ٯSć-x_\;&f/<34گNBu5!^h_7%sI+9mm.iJiO,WJ"IENDB`perfbook_html/node174.html0000644000175000017500000000427011672746162015651 0ustar paulmckpaulmck 12.2 Assertions


12.2 Assertions



Paul E. McKenney 2011-12-16
perfbook_html/node242.html0000644000175000017500000000457711672746162015657 0ustar paulmckpaulmck 14.3.3 Atomic Data Structures


14.3.3 Atomic Data Structures

Queues and stacks -- avoiding full-race non-blocking properties often yields great simplifications.



Paul E. McKenney 2011-12-16
perfbook_html/node40.html0000644000175000017500000001327711672746161015567 0ustar paulmckpaulmck 4.4 Software Design Implications


4.4 Software Design Implications

The values of the ratios in Table [*] are critically important, as they limit the efficiency of a given parallel application. To see this, suppose that the parallel application uses CAS operations to communicate among threads. These CAS operations will typically involve a cache miss, that is, assuming that the threads are communicating primarily with each other rather than with themselves. Suppose further that the unit of work corresponding to each CAS communication operation takes 300ns, which is sufficient time to compute several floating-point transcendental functions. Then about half of the execution time will be consumed by the CAS communication operations! This in turn means that a two-CPU system running such a parallel program would run no faster than one a sequential implementation running on a single CPU.

The situation is even worse in the distributed-system case, where the latency of a single communications operation might take as long as thousands or even millions of floating-point operations. This illustrates how important it is for communications operations to be extremely infrequent and to enable very large quantities of processing.

Quick Quiz 4.7: Given that distributed-systems communication is so horribly expensive, why does anyone bother with them? End Quick Quiz

The lesson should be quite clear: parallel algorithms must be explicitly designed to run nearly independent threads. The less frequently the threads communicate, whether by atomic operations, locks, or explicit messages, the better the application's performance and scalability will be. In short, achieving excellent parallel performance and scalability means striving for embarrassingly parallel algorithms and implementations, whether by careful choice of data structures and algorithms, use of existing parallel applications and environments, or transforming the problem into one for which an embarrassingly parallel solution exists.

Chapter [*] will discuss design disciplines that promote performance and scalability.

Paul E. McKenney 2011-12-16
perfbook_html/node351.html0000644000175000017500000000652711672746163015656 0ustar paulmckpaulmck D.2.7.2 Pass Through a Quiescent State


D.2.7.2 Pass Through a Quiescent State

The rcu and rcu_bh flavors of RCU have different sets of quiescent states. Quiescent states for rcu are context switch, idle (either dynticks or the idle loop), and user-mode execution, while quiescent states for rcu_bh are any code outside of softirq with interrupts enabled. Note that an quiescent state for rcu is also a quiescent state for rcu_bh. Quiescent states for rcu are recorded by invoking rcu_qsctr_inc(), while quiescent states for rcu_bh are recorded by invoking rcu_bh_qsctr_inc(). These two functions record their state in the current CPU's rcu_data structure.

These functions are invoked from the scheduler, from __do_softirq(), and from rcu_check_callbacks(). This latter function is invoked from the scheduling-clock interrupt, and analyzes state to determine whether this interrupt occurred within a quiescent state, invoking rcu_qsctr_inc() and/or rcu_bh_qsctr_inc(), as appropriate. It also raises RCU_SOFTIRQ, which results in rcu_process_callbacks() being invoked on the current CPU at some later time from softirq context.



Paul E. McKenney 2011-12-16
perfbook_html/node416.html0000644000175000017500000002342711672746163015656 0ustar paulmckpaulmck D.4.2.4.1 rcu_read_lock()


D.4.2.4.1 rcu_read_lock()

Figure: __rcu_read_lock() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_lock(void)
2 {...
...) = idx;
18 local_irq_restore(flags);
19 }
20 }\end{verbatim}
}\end{figure}

The implementation of rcu_read_lock() is as shown in Figure [*]. Line 7 fetches this task's RCU read-side critical-section nesting counter. If line 8 finds that this counter is non-zero, then we are already protected by an outer rcu_read_lock(), in which case line 9 simply increments this counter.

However, if this is the outermost rcu_read_lock(), then more work is required. Lines 13 and 18 suppress and restore irqs to ensure that the intervening code is neither preempted nor interrupted by a scheduling-clock interrupt (which runs the grace period state machine). Line 14 fetches the grace-period counter, line 15 increments the current counter for this CPU, line 16 increments the nesting counter, and line 17 records the old/new counter index so that rcu_read_unlock() can decrement the corresponding counter (but on whatever CPU it ends up running on).

The ACCESS_ONCE() macros force the compiler to emit the accesses in order. Although this does not prevent the CPU from reordering the accesses from the viewpoint of other CPUs, it does ensure that NMI and SMI handlers running on this CPU will see these accesses in order. This is critically important:

  1. In absence of the ACCESS_ONCE() in the assignment to idx, the compiler would be within its rights to: (a) eliminate the local variable idx and (b) compile the increment on line 16 as a fetch-increment-store sequence, doing separate accesses to rcu_ctrlblk.completed for the fetch and the store. If the value of rcu_ctrlblk.completed had changed in the meantime, this would corrupt the rcu_flipctr values.
  2. If the assignment to rcu_read_lock_nesting (line 17) were to be reordered to precede the increment of rcu_flipctr (line 16), and if an NMI occurred between these two events, then an rcu_read_lock() in that NMI's handler would incorrectly conclude that it was already under the protection of rcu_read_lock().
  3. If the assignment to rcu_read_lock_nesting (line 17) were to be reordered to follow the assignment to rcu_flipctr_idx (line 18), and if an NMI occurred between these two events, then an rcu_read_lock() in that NMI's handler would clobber rcu_flipctr_idx, possibly causing the matching rcu_read_unlock() to decrement the wrong counter. This in turn could result in premature ending of a grace period, indefinite extension of a grace period, or even both.

It is not clear that the ACCESS_ONCE on the assignment to nesting (line 7) is required. It is also unclear whether the smp_read_barrier_depends() (line 15) is needed: it was added to ensure that changes to index and value remain ordered.

The reasons that irqs must be disabled from line 13 through line 19 are as follows:

  1. Suppose one CPU loaded rcu_ctrlblk.completed (line 14), then a second CPU incremented this counter, and then the first CPU took a scheduling-clock interrupt. The first CPU would then see that it needed to acknowledge the counter flip, which it would do. This acknowledgment is a promise to avoid incrementing the newly old counter, and this CPU would break this promise. Worse yet, this CPU might be preempted immediately upon return from the scheduling-clock interrupt, and thus end up incrementing the counter at some random point in the future. Either situation could disrupt grace-period detection.
  2. Disabling irqs has the side effect of disabling preemption. If this code were to be preempted between fetching rcu_ctrlblk.completed (line 14) and incrementing rcu_flipctr (line 16), it might well be migrated to some other CPU. This would result in it non-atomically incrementing the counter from that other CPU. If this CPU happened to be executing in rcu_read_lock() or rcu_read_unlock() just at that time, one of the increments or decrements might be lost, again disrupting grace-period detection. The same result could happen on RISC machines if the preemption occurred in the middle of the increment (after the fetch of the old counter but before the store of the newly incremented counter).
  3. Permitting preemption in the midst of line 16, between selecting the current CPU's copy of the rcu_flipctr array and the increment of the element indicated by rcu_flipctr_idx, can result in a similar failure. Execution might well resume on some other CPU. If this resumption happened concurrently with an rcu_read_lock() or rcu_read_unlock() running on the original CPU, an increment or decrement might be lost, resulting in either premature termination of a grace period, indefinite extension of a grace period, or even both.
  4. Failing to disable preemption can also defeat RCU priority boosting, which relies on rcu_read_lock_nesting to determine when a given task is in an RCU read-side critical section. So, for example, if a given task is indefinitely preempted just after incrementing rcu_flipctr, but before updating rcu_read_lock_nesting, then it will stall RCU grace periods for as long as it is preempted. However, because rcu_read_lock_nesting has not yet been incremented, the RCU priority booster has no way to tell that boosting is needed. Therefore, in the presence of CPU-bound realtime threads, the preempted task might stall grace periods indefinitely, eventually causing an OOM event.

The last three reasons could of course be addressed by disabling preemption rather than disabling of irqs, but given that the first reason requires disabling irqs in any case, there is little reason to separately disable preemption. It is entirely possible that the first reason might be tolerated by requiring an additional grace-period stage, however, it is not clear that disabling preemption is much faster than disabling interrupts on modern CPUs.

Paul E. McKenney 2011-12-16
perfbook_html/img120.png0000644000175000017500000000337611672746022015310 0ustar paulmckpaulmckPNG  IHDRWZL`PLTE$8D6Sfl*3-EUQ}wcU3"HoZ~ ?awfu݇D"~LZtRNS@fLIDATx\v0l$ "Mr  hRmrq:ye|}\Qݣ|hjnҼyݖ?.C˅ -mtV ļ,ÂXZn#@Q4G.Kt^nu.tgbC E]}x?/[2*2b=0p5COYi8lN*Jnn+Y6 ڗrd4"/; t+Ũ,daNU61cP_Ѡ9JJldB: ds$ʎ 8/*΁RB$ێ<4DaQ*"i0߫y2T fM=l\R 6`fM WcZ W3ؾWY%eEcDzG}qNzОzɎ8'-M~ℋ\yaYw#O-Bz}eV$܂> {kH=fAu{U~`K{=l\8qګ9ʿBEː\!n-rs]e~(zu-֭uƉ{~սP\e+qTLN[K^55 q z׫ G¯_n)cq1!I(ټL_@5\(;H-.$4%Sė(YPΕ"uוx ϸ{ lf`s5J:SVT\\eGREYVEEM-#0`|o7yJi33|S(.Շ }hO.>;N )гlgh/'s,tm<:} v]kWm|11Y*Aʷ\OY~ĸӏƤb4SDSj7i:kuϦ#׮v[PM[^u]eɜHS7ƎyӊjO7^45WBw]^3z7LBWX^uKQ-גZa]v5w֭(fEL^4u=C擄.Eu?!:+*媼P<+\(NLAՌՌ r%<)MbMG(A+;f44*FCgí⛹` :k\}TK̕̕,ݠלVn9೻6(\(zضoj6W3 lf0BFR/IENDB`perfbook_html/node296.html0000644000175000017500000001312311672746163015654 0ustar paulmckpaulmck C.2.1 MESI States


C.2.1 MESI States

MESI stands for ``modified'', ``exclusive'', ``shared'', and ``invalid'', the four states a given cache line can take on using this protocol. Caches using this protocol therefore maintain a two-bit state ``tag'' on each cache line in addition to that line's physical address and data.

A line in the ``modified'' state has been subject to a recent memory store from the corresponding CPU, and the corresponding memory is guaranteed not to appear in any other CPU's cache. Cache lines in the ``modified'' state can thus be said to be ``owned'' by the CPU. Because this cache holds the only up-to-date copy of the data, this cache is ultimately responsible for either writing it back to memory or handing it off to some other cache, and must do so before reusing this line to hold other data.

The ``exclusive'' state is very similar to the ``modified'' state, the single exception being that the cache line has not yet been modified by the corresponding CPU, which in turn means that the copy of the cache line's data that resides in memory is up-to-date. However, since the CPU can store to this line at any time, without consulting other CPUs, a line in the ``exclusive'' state can still be said to be owned by the corresponding CPU. That said, because the corresponding value in memory is up to date, this cache can discard this data without writing it back to memory or handing it off to some other CPU.

A line in the ``shared'' state might be replicated in at least one other CPU's cache, so that this CPU is not permitted to store to the line without first consulting with other CPUs. As with the ``exclusive'' state, because the corresponding value in memory is up to date, this cache can discard this data without writing it back to memory or handing it off to some other CPU.

A line in the ``invalid'' state is empty, in other words, it holds no data. When new data enters the cache, it is placed into a cache line that was in the ``invalid'' state if possible. This approach is preferred because replacing a line in any other state could result in an expensive cache miss should the replaced line be referenced in the future.

Since all CPUs must maintain a coherent view of the data carried in the cache lines, the cache-coherence protocol provides messages that coordinate the movement of cache lines through the system.

Paul E. McKenney 2011-12-16
perfbook_html/img71.png0000644000175000017500000001570111672746042015232 0ustar paulmckpaulmckPNG  IHDR=+ҍtRNSىHzIDATxAXLc'L[M upPB3(`|96u|("K {,Hm]L [{bS0A-!mئ}^B M ;]!mzڃ$[%Yv82{OO}tG1(@Tx $>>#Ni;s}#i$>z2A̜l-{j-7*гҨMkoBԪkM^(i9EJtϳUř33ʎn^ ƂwBdR^oGy~qy eQjŠQ8uls$pG-C&&ɣ;*ޅ~/'˒(IH.l/,8ox (jjȺ;[Tڟ_lk ,Z<{B'h ޼›u` dF> Ukpq KLb@浲V"Ȏ*)F*D]OsL)^ѬV=Uj%Af&x#((A/=n(|A)ٷE>=q譔Rw6UY \b08#\a'oJ, N @t YPWmtV3jq/'I:AVՊ̞MSnnTF*&d,-8g.TFtn> $9m,3U]iF.|PqOh==FfОr;o\_~2FR+tZ4.!r~ޑZHTㇿsT>-y}%J;SA!ħEYC6Ym#CAZ p"2#n:8xHxb\S+EP8PX,xoF+z:% ь2@zNpnUb9GQM(-j L*m}FZ%\ `4M 0MZZxZ@ư A̰f#œ]q/Cx󑇮1 Pkv㜇elaw.˲ŕhۤ~d̹]I7ZƮ])qP Yz^^QnKc]mnoݡYP1D0[: ͱYy7cб!B:_}Fكe+ TeD۪>/nUI2?3n)EY=!,Ҵ~J.P]MIeYmm0gsV\W<&⠷=f:QCo@]5暑Gbb zJ687@$yԆw.WhFGt y{<4 h# ~VjmP|gox+zqyO&w^8 g_Ў@h>wG?ڌ.BNxocnܡ)P4}eRLnN_??;an!o X>s?'ٌ%#'ֻzQFh`5>ɌUw{aY|_>eIxl-Dm.9-,ݹ XXOR]ftsv/L`xkuE\eڡ%^UFT(K 拤ņtm.s]7e|٨D[@u$nH1B T+L&OVc|> 1JJEX5Dj,$sx*ˠ4;*ч`]! [ 9f @K& QsWRsUhdt̄C"pf zs VM$h›қ-D:7~SJ =?HyD͛-?~="@^WıA L#G+ Ezr,=4"ڠ&y&DN**g05{ /+ܾ[|f'L'J*)ևhWE*Vg.RR*7'9cd  ):t0Zb ,fO5@*^s9Oj[ٱ /ylCF!z"O=W']<ʮ #g~{PQ1p8vI(8zC:Ƭ[_z }ДRJ|g:(ѼLqjv3?7lc/6ݖ!G*FG>e2jctlbuX ΂*gTQkmu$O<&yO>k]k6 ›9`4A.< ZZzK:߁#J2YRTbb5$[ q$%*dEĽޖ| ӥAz,i3zٓwYxhT]( pѣj[`$N?.BckMge!G쫇3\O_x#Kyt8"g4e4+oeB?( P8={IPk?>oxwo>wD<&m}_ O #?>Gick'yX7^l&F pa67M>շhcS;{oqо8o?Ni=KOgO|N}z}'%ZScxc)?|&p&\]p{~N _5M tVpͱ_m!C):&RWAzS1g_lǶ6ބO_kw_W7?>NVcʿ<'pv>?;pzg?g?mGqyxjIo}XOXbsi{|ɯᩭVv3y ;?w?=`\ಣU[ЀDj9?&{6?ِ\a?O 3<v2R*ggl{삋 ~dyސ˶]be֬&_crͺUB/Kj=I1wlPrVb̂c䇬b0VJA=4`fڣxdc ڭٙ9s: *4`mNIkTooLZr L׆G82])ഏAJCloL"Ȟ8EՓ䍭``{N@{ s0PDvV?蕢2cنB&Rj)K;LKb݋QpFe?H/cU +3E3챁EdhމB1ꑸIhMkL dk{@^-]fEYn_*v{9=t/4C)EyPDo1,KIzlt:qEy>Ttei\bWk6Aue=qto4C6pB,']Mo:r:h#fafݽ*n%݄y8> >~09#kőMk6{5`=:G Rq14T1ч#S2 [ p2;%nY|dWZd%bCwb${yE2i2ֶۛ4֕vvµʭtXRQ ߒq*0~iV.<&Ze v9Uy'6x n=˸^^-i7e3W@89" 1\\}x-@ZsFwfk+Pݪ ba7'WsVq6F\Zo<[P9TbT=Eu1(j1aj$ݞ 66iKߍq~1dW5 b[}~9P{ j ^sLb#׈?*(N`եs`u ԰}j_vǭ1ͤY5e2%-SSobC]ŰɅG骖rڞW;\Z\e"Rt f.9|oM%Wkp9=kR GyIENDB`perfbook_html/node25.html0000644000175000017500000001074611672746161015570 0ustar paulmckpaulmck 4.1 Overview


4.1 Overview

Careless reading of computer-system specification sheets might lead one to believe that CPU performance is a footrace on a clear track, as illustrated in Figure [*], where the race always goes to the swiftest.

Figure: CPU Performance at its Best
\resizebox{3in}{!}{\includegraphics{cartoons/trackmeet}}

Although there are a few CPU-bound benchmarks that approach the ideal shown in Figure [*], the typical program more closely resembles an obstacle course than a race track. This is because the internal architecture of CPUs has changed dramatically over the past few decades, courtesy of Moore's Law. These changes are described in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node44.html0000644000175000017500000002227211672746161015566 0ustar paulmckpaulmck 5.2.1 POSIX Process Creation and Destruction


5.2.1 POSIX Process Creation and Destruction

Processes are created using the fork() primitive, they may be destroyed using the kill() primitive, they may destroy themselves using the exit() primitive. A process executing a fork() primitive is said to be the ``parent'' of the newly created process. A parent may wait on its children using the wait() primitive.

Please note that the examples in this section are quite simple. Real-world applications using these primitives might need to manipulate signals, file descriptors, shared memory segments, and any number of other resources. In addition, some applications need to take specific actions if a given child terminates, and might also need to be concerned with the reason that the child terminated. These concerns can of course add substantial complexity to the code. For more information, see any of a number of textbooks on the subject [Ste92].

Figure: Using the fork() Primitive
\begin{figure}{ \scriptsize
\begin{verbatim}1 pid = fork();
2 if (pid == 0) ...
... 8 } else {
9 /* parent, pid == child ID */
10 }\end{verbatim}
}\end{figure}

If fork() succeeds, it returns twice, once for the parent and again for the child. The value returned from fork() allows the caller to tell the difference, as shown in Figure [*] (forkjoin.c). Line 1 executes the fork() primitive, and saves its return value in local variable pid. Line 2 checks to see if pid is zero, in which case, this is the child, which continues on to execute line 3. As noted earlier, the child may terminate via the exit() primitive. Otherwise, this is the parent, which checks for an error return from the fork() primitive on line 4, and prints an error and exits on lines 5-7 if so. Otherwise, the fork() has executed successfully, and the parent therefore executes line 9 with the variable pid containing the process ID of the child.

Figure: Using the wait() Primitive
\begin{figure}{ \scriptsize
\begin{verbatim}1 void waitall(void)
2 {
3 int ...
... perror(''wait'');
12 exit(-1);
13 }
14 }
15 }\end{verbatim}
}\end{figure}

The parent process may use the wait() primitive to wait for its children to complete. However, use of this primitive is a bit more complicated than its shell-script counterpart, as each invocation of wait() waits for but one child process. It is therefore customary to wrap wait() into a function similar to the waitall() function shown in Figure [*] (api-pthread.h), this waitall() function having semantics similar to the shell-script wait command. Each pass through the loop spanning lines 6-15 waits on one child process. Line 7 invokes the wait() primitive, which blocks until a child process exits, and returns that child's process ID. If the process ID is instead -1, this indicates that the wait() primitive was unable to wait on a child. If so, line 9 checks for the ECHILD errno, which indicates that there are no more child processes, so that line 10 exits the loop. Otherwise, lines 11 and 12 print an error and exit.

Quick Quiz 5.4: Why does this wait() primitive need to be so complicated? Why not just make it work like the shell-script wait does? End Quick Quiz

Figure: Processes Created Via fork() Do Not Share Memory
\begin{figure}{ \scriptsize
\begin{verbatim}1 int x = 0;
2 int pid;
3
4 p...
...);
15 printf(''Parent process sees x=%d\n'', x);
\end{verbatim}
}\end{figure}

It is critically important to note that the parent and child do not share memory. This is illustrated by the program shown in Figure [*] (forkjoinvar.c), in which the child sets a global variable x to 1 on line 6, prints a message on line 7, and exits on line 8. The parent continues at line 14, where it waits on the child, and on line 15 finds that its copy of the variable x is still zero. The output is thus as follows:



Child process set x=1
Parent process sees x=0


Quick Quiz 5.5: Isn't there a lot more to fork() and wait() than discussed here? End Quick Quiz

The finest-grained parallelism requires shared memory, and this is covered in Section [*]. That said, shared-memory parallelism can be significantly more complex than fork-join parallelism.

Paul E. McKenney 2011-12-16
perfbook_html/node80.html0000644000175000017500000002004011672746162015556 0ustar paulmckpaulmck 7.1.2.4 Compound Double-Ended Queue Revisited


7.1.2.4 Compound Double-Ended Queue Revisited

This section revisits the compound double-ended queue, using a trivial rebalancing scheme that moves all the elements from the non-empty queue to the now-empty queue.

Quick Quiz 7.5: Move all the elements to the queue that became empty? In what possible universe is this braindead solution in any way optimal??? End Quick Quiz

In contrast to the hashed implementation presented in the previous section, the compound implementation will build on a sequential implementation of a double-ended queue that uses neither locks nor atomic operations.

Figure: Compound Parallel Double-Ended Queue Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct list_head *pdeq_dequeue_...
..._r(e, &d->rdeq);
55 spin_unlock(&d->rlock);
56 }\end{verbatim}
}\end{figure}

Figure [*] shows the implementation. Unlike the hashed implementation, this compound implementation is asymmetric, so that we must consider the pdeq_dequeue_l() and pdeq_dequeue_r() implementations separately.

Quick Quiz 7.6: Why can't the compound parallel double-ended queue implementation be symmetric? End Quick Quiz

The pdeq_dequeue_l() implementation is shown on lines 1-16 of the figure. Line 6 acquires the left-hand lock, which line 14 releases. Line 7 attempts to left-dequeue an element from the left-hand underlying double-ended queue, and, if successful, skips lines 8-13 to simply return this element. Otherwise, line 9 acquires the right-hand lock, line 10 left-dequeues an element from the right-hand queue, and line 11 moves any remaining elements on the right-hand queue to the left-hand queue, and line 12 releases the right-hand lock. The element, if any, that was dequeued on line 10 will be returned.

The pdeq_dequeue_r() implementation is shown on lines 18-38 of the figure. As before, line 23 acquires the right-hand lock (and line 36 releases it), and line 24 attempts to right-dequeue an element from the right-hand queue, and, if successful, skips lines 24-35 to simply return this element. However, if line 25 determines that there was no element to dequeue, line 26 releases the right-hand lock and lines 27-28 acquire both locks in the proper order. Line 29 then attempts to right-dequeue an element from the right-hand list again, and if line 30 determines that this second attempt has failed, line 31 right-dequeues an element from the left-hand queue (if there is one available) and line 32 moves any remaining elements from the left-hand queue to the right-hand queue. Either way, line 34 releases the left-hand lock.

Quick Quiz 7.7: Why is it necessary to retry the right-dequeue operation on line 29 of Figure [*]? End Quick Quiz

Quick Quiz 7.8: Surely the left-hand lock must sometimes be available!!! So why is it necessary that line 26 of Figure [*] unconditionally release the right-hand lock? End Quick Quiz

The pdeq_enqueue_l() implementation is shown on lines 40-47 of Figure [*]. Line 44 acquires the left-hand spinlock, line 45 left-enqueues the element onto the left-hand queue, and finally line 46 releases the lock. The pdeq_enqueue_r() implementation (shown on lines 49-56) is quite similar.

Paul E. McKenney 2011-12-16
perfbook_html/img57.png0000644000175000017500000004532111672746064015243 0ustar paulmckpaulmckPNG  IHDR.'lPLTEb``^\\\ZZTRRMJKFCC956ljk# hffmkka__XUVNKLJGH856iffKHHC@@A>>@<=wuv.*+|zzmjktDhtRNS@f IDATx}<AQBX`&QUIPl_NbZO y߭”BR.P8RdxWewV)E>Q7O7KR? ?НuZDQ|yEb_KseOLEpyIg @fzicw%^ e/(aq hQ>'^2U;#?:zJ}=ӨzJȝR\ ǭ[5L ;a g$瞺IhxVUxRt PSՀ7JT[`cR)! .Y_uI30$wnfL@K(0N&mkdǕǁ앐2n& HI!f#Ega_tq-};7p=\KsA;P/?;u)*T+zY'uL.#b{AO/ץxq"s'}#TjZPU΋E5 nG6=+e잔Y}PVuu\vqSWp#%@;-QWa;weuy g3seucۦ4/r`ؽf[o_'u p# .eA{=145ݢگIVQ:w|33Xt,K4{bHOo5s7f'#]^$חLsd4Bk|l5jP薲V^Jpt\ҧyAw g_n䎹@FGƢ HƻSfuFKjeecoj zȟG%F瞪w&'>p[r&@AᇒI?As*5\?]R<KѫTMAyg(j%b `!ۑIOY.s4G({CV56p+ƹZq\{Ye| Ҥ85Gr{@1~Ҕxײ9@Q p_ʊ;/!~wTTIi D%Xh>a}d뭩@$fX^Wv}&EEF'][f_99 sCZxrYN׮sGTz^PwfO7u#J}A='YJǺk5b[IOgkϷ"dz+L"_Q{/;1 PO&T.Gz90d+ty#0T+}ȡ+Lco|Ejo]̜Cz}J΋Qk6ݺ*;PIѱKC6Xe5|EOZ*`@ـܪ4czTSKB/1 mїS1X:Wݓ tsnVu_xt\!c_ YPV}!XcZY#՝Qocd\V 989^; iU]HH'˞@jitYW+1}h2\z?PAo'yPhkP t0A xggSnK9}Lօm df{\i7NZa~GdE6o)k0̃ZtTNL&X垳se ރ -4{pk_Ԡ {U5Hk|iKz+?F.:n+SQ[5@Qk`󲫶 0_L"NtNf5OAO/Vtu+~ 1…[FfL ) nHrkYvT*@xm C/ʶ]RxYqut uA^pgQ#Į_ qgg;ʷP?5h&WB j<TeFMFG=7Jͣq֏[d˳=oj\-GM(Z7JG0<`GD5nl}.H9'$E;(tDv噫P_*;e"*?D1ZW_!S1rz B(+2^F{J0°H]hJ5|rm(3M}6[5n.3ա6 g^TAYٵH] FIr^x󀃤1y$E^J:SҮ>=*{)=0,O>hd0dн\ |i?f\'I?o{: n_J@d[U͉2!` Zsmǜ~%nRJE⹭;xE[͡hȅsގNjkCZd3pA[mrn[ .˻4^xW[ ,Nׄhk֘¬1ٲ{)>=9C\[u}IAW~.|ji;݇ 4u5O dUĨBVŦ51?a5 [n3s]HX O͆BJe?b)|jx~WƧ|]C\vj Fgoɡ4RUޞ2/(gc9ݮ%✤Ջ^t'H\ȢBTK.N^ g?9`7@V#[_D$ z1P5sqrŪ7]^*; d0uA16:{PD7:N:jڹoO7?;e.St"!j Tgpi]˴]mW>8해r>N}hV PSU1 /_jDIj2e5<I4&#M` 8Y]+WÇ.K(bAA(X /:dzηzA)xMBd#[9GW:ksl!a)nxs4`(tG{r4z!?ꡩ;@@-%'G=pEȎ98 JA+Ui!mMeV\YJ lueD>Q+?@FKI:J:{kFRtj]g+$[QXCN s+*4Tp2l\ ]1d¶],3U)u \}}B=8|(6b(cԅ xkx?*i dSN!WJC}/j`~3-@yJ*Ol `1 J+4l pH} 5.x7x\!V+yAjZokV IpmC}=pat3J<^EI\Nm?HNJcv(YN1Ug^]n竫Gaj7T )hBl; =dڻl*ʹ:/Utن ^A1ltxfi}lNav(C5<+4SU gvtQ])Kޖ}da[kmL$C;4E-)$A/Eܰ+*Nggr@y5{ѠSQu*^$HE)\LJp Ԫ,ŠZݐ&$ʀ$5\SiM xO"*NL: ƚ'F{Ӕδ1ڛPhfr20k?ee jUKrSȬ)P?䵷I0)(Ծ(I5a81JwRB2}os6/e,eibt;n@W0@i?qT)0 I|odvY#]lfbF5++6"d^aP=U,U݅ K.֭o75wPsu*X:dbEN}[& ̪E/ I;g~̪6v$3oL)(/5qlYs"Y9'?36zWDඅ)$9m|uRb-V{~dRg= p~̢:7rA/;Ma5bh}_az:^Hx8)yf {e'P}$ =vA]Y2ѡ/eL5z_cSL@!]#kh >޸EgV~\YTU5pWf2䮱FΨGQ٫(S"pW$t< dc^oCɰ[[V8js#+>h晢@׳?5T]z$T6CGS+c}tٛȬM:JidWn2抠yW)x 7H$#|0fH{ۖUa&9>䜄Ϝ('4XŴ:ti } S* ƶ]Ac;+CwH8SbA5O7 u`0ȋ׺HPai+;Tjm< }jw>^2BMZvIgdSQ•a9s&S7;?ja莚2*'BLţ.) "kL:"yJy'F\|i7kECC\4 k=X^.hFࢡ!k>s>VeJo|Aɳo?E|`-P+α JVӖpW~)j|"}pjz}9?^X&6k囲oc/SպG$]YWY}Nj 3d 8UYQOdZXfZ4ͨ)nZ+L`!i8F|kqS\G$sF\ђ>P?|2%*"v(|UG#A^1XN7ѧ&]dIg \@.Lkw<_{{'T:*9'ϱtftKWC Zb[-h#r45+(hbݒa T $ψ -3cgPx&;vv"JǀJ]47dk:4'`'cIî@8F&ͬ$nG1ugUk_0'H\-ӌNEGML [{Цd?t$԰QRvcEC,G͋hE@Ā&<=U T2ߢ ۵D ,Ls._BBYYD&ܪ/"Ҥa<}lBTo LQ&{FJQzmd!"λ;. TBFݕ]% ]gk@1vH6=4 >MX%q)R͌7xY!Ky3\Brqt弎\r4/Yv8ù_UOx S(F G%<kC=%s@M~m/RW, OL*.q0ov eM+B8kU9 BO' ULgVA+\ ҇ppG;ԼK TyOIV?j|'}R9QQ/]-ݿy*2R=ߍ[Sc<hM WIReZy1B&֔p-R`оS7!"0*7u28.+ q ˷*U\"pP5TJğJ_p8btg_}&}`yKo>Zt릮gւ?yCP>O4ˋ\"Ӭ}< d>{(הDe1ܛ8Kީ q '"TOT/? /|Ì/5BW֟/]mC#١s@Iv@4 B  :.+LHބAQ(8n;?t'?苪gBJDC$6_k$*LSr/ }(8z̲[ )?IG?hkO 1\}dC6Q(Lo)}K . Z_} 5ecO[uɹ%?5Ѩer)my!1JvֶͻQ*mZߗ",#;rJ ;" = $"[<:Lya`V1Rv-G3FvTO|ÎmW*{|uukriȳ۔qTXP1(\ldˡX0>տ f_mx_Hֿx{7 (הsT4OL4۟ E3tJt1GN{4Ͳ-fjha_Y+ŒE-V՚&H\(v(!Rrɒ&;E-lyu?f_NWkEZ ׵0ο%Qf7h&  M5XįYQFc:b:$`izLNTFkw{"F~N6ef OcQ ۫WTC i82D+1rGqRO`|}%f yE; y02O߉!"4gj4%[Z_/鶛 yv( v|WDz b. dz^|Wy'/~G :P*LxfA/ ,%XƼ1šO07f vRWkr.cgaBK:,L_G=_: sh+ s/7܎L_ޞFNff"֓}R?:RC ? ?g޿ ]U%}u<pKS|4_fvb7f:kgtf7 vqyow{Lc|d=ǿ:I‰c$]+k,, 7(H #:uVU/]j&dh $} UܘXQ4HRI3sas ]ʎQFsZ:Wᙿ߸#y Ʌ#*wYɅ(JC.~#VـK%E)n7˜Y`ax 'Dȿz Fӯ?o '=` SԗzY m¨*{~^ܲ JiV cy\=oM Vx={ڋ] (nB%}s)>F[`>G {KG'`3#2߇_E?Ϳߣ\ߏ'peՙ#DhW xL_$eUOVElُ?de?<=*8<7~q 2楤e}ZE2G}ZFX7uNgbͿq28 Ogοz=p*Vhbs.Gh-HE!!l/A$˃_D H~яխx=Y.ވaa&)\"Sڥ.|,.|lC N/mW]kvACōx$EOMa51r~߷iǕ"/uB&/As?80\<ucigr*L"/ε}HsG @BcilӅ /_}_g,0oV1}G;ޅ"_U{/C,RqaS'/t{%#}!#z:&l[($jR->k{2Ƕ_9eM_l4|m;FpS _#}S=k*_ߟDv E"lAv 6saS?jVw>rΓ <2|4y;0x8i1k' mgiqE 'ݑxcCS*控h :x9 XOkrR3sr$DkQ-6t剬E~Or44 d'U?)RՊY.:~"f^? p#;?~~y{Ts7{PçC{Ǹ>7*'UxJE Xf ) v?{; H]WPɰu_A3/:Vj ")ae gsnE\OG`i{(;,ke(濤|^< &zz@~ߏ_>/yvAKų`R>Y0/,`/34cWyc3u_G4.ZM߿H 5;ޒ/.pÃU$~%}jQs?/37jJm57.}; JMn%}E<_O1j>Sθ? n`ܯ ?:>p ' bԔB(X+yO]kdZ:tZ|`}W lz+/oYeKk4e*GIS 3E *3zZ3_hs{'0p.kdq`)n^ G~iCFkЪXx_z(ǘ'2'ڨ_p,lDneQY72J:`"?9MxT>*AAG[)i3f;χO*^#hqU_?D'nP\,w_>ħ@e` Ǐ%]~`\\=۠3꿹:q)ܲƍ hmΔRKP7֚iUƝ`*9R}@㕊h4`H8q)4GLkP?fLQ?@ZrBDŽyʠJ oshYz+Dp4_|j;rh £k!]Gk>7*TTq8y4;JL;I LIDr-2I>D4Ӯd-3s0)KV2 fe=52"y`P]~0 0k `4er\RWgee1 y`me6H L:E4aE/Lj $eˌZkdƺͮPW V\0ڇvkLo8c*gH? -Z+ȫE) lOR[9-(0I@Tu tnDiAߺiN1[:e(_'Hp+?u=d>9М1 N?΅5/W$275nHʕQ3ԃqC-zŴ1[do3YXԍf9?# \k"x?v3SYA˘9֮F<_YbDa+sDu?/q/,eщqkY_n|#*'_4pkX3_; } %vD!oIÀpOd^: R. Scp YC'?%r$_`s^Ы](A:pq!Sr?=OvUI$\F;J!;$Y\5 P}9_eR-l0|ZX;Ȥ bώRE2kxK[v]ْ^U .2eOjJ{#gW<߲,cnOd^͓wu]`_K~YT6mߊI_hN3ѥj*"} o?Q@DTЉf}LpGLt\5 @W<[\hɚ1UȪPwdS:irPzcPyLU;Y#p>z~5(9=kT#`Y#*L?(MXy\+wW/%? "iކw/{QQNWqc)>#OS`^P僵/ ?ϨZk`KWh<& /+vfT~*>P4ON*_BJCSʗUiʌOjʗ)\B4}dv9Wӌ0q SWjV*qDB/} ?W(#LB.(i{2(-)R'M~;<T8"zqRΟ=.伨FxaWiKvP.>o*t߉ɷD/ PF=E2r ,tw%ӒPi򥅕)^zܲ^R~))kz+&w+qpmb+o(G <\@!'1F$Zgb&=dTuKrpY+ܓR|e}nR[(Y'< m~d$gp{Dmv~=K?QÈbj¤¬Iu:x旸:Z' avNK&fNRXjp;'օ0wj6l\߇T]O h*274H5q k$HEE @|4K~y hr G!ED9_@u%: S^vEfp[U~eJ?q$cz[ <_V]tj/V+aKV_>/ִ"+XSX-~ D协*-6B>Udn18ENm3X5e_؊K;Yω ש/ /ִHXo{n_؍-]0z_^WFW/l sq ®7_Eo_>(>b#SVFD*eb:|f̆`|ށg{M=b2eʕ[@`xaxAwB~ȭN3y8&i iȻ:~)v2}y &H]sLF(:09 9nwo38_8EH| T.|Oyd)OR=Pɲ囊[V`3˧=7(眦0:fy?&0*9Kn&6.KgsaN[y sb.Ʌ_:3ɭ0eb.} 7捏|hY O"f=I•5kelm|=~3+'M.tohzv/y@9[;T2wW,WO>$~Ə:5Xc@OX >TW q*m2W"y YA?;J=]kbs7 ~M1؈텟@)ST3^9,ê{KlWnj,]t3 ?~`fq0†co-7*7[y<"8ߺS\Du̯$M Xݘ.yt)=cxa0ӴLrX#AvØ"X`Rby9p%-e~iZB[(XRxOJƏ{hy/Y5xyUX8ɀ[3]pG*W3_}|}$"oz9LAIqۀVtv k`n !_;c`5Giͨ]%KG m,L, ȘjA2:]8bn( m8!ڗKUr-#^+ߒ QcxĂ> 8Hjv#JQ4"=_'8 CMoDYΧjR}9_eR-48 sh/O?L̼] atg(OrG_#v5Q${I5~KEp_ M#ϯ; XK9_E??o8e Rݔ#{,YA{UcvY 8ad~Jܽ]n|!P`YΈ=I[>|(c?+1W&~__~~E8p_̯*Et/>+M/.˕)Np׿i8eq78ӂ!6Y35QRRWm WCt!j%[a=DҨsr_aDc(d!i򝿪zu#|@) }e`ǣ^I&?|%U!C:O!fÍ3EaDcj5Z{RU_ -8pJ,gASrѐ{u/ȋ'1N;DjxC _MosfžYA}b]RobƆ94+O "'Y@Dԛe\>V: 8f-m=Z:5ڱA#D'M1mF߳a(z/#O=ڽ8Ի<9@gK0M_>#6@ceqh̚/7n\ \'n:$峢 ](Ne;տO[>+(Nr [|~>F S$I9" 8ELlXG"a"[|{jw?dk9X(#di7ԁ]]ϟda4T!(ieݘ7Vo=g0*Q7Zڴ%|A5K +UsV_ pia+/w]̇_*Ѩ 7)L1,e5k녂Q{bc C1a}e]c\|#zyJOpE,Du؇ː*&W.k*}g>F֞h(L /:h/ pEHA@tl5p&O7f6UHn8-\9|׿jfpfz xyf\r8U0;'#ơr1%Gّ(\9^a+\?܇ɗ qY"g\η#Dc(i"|U@)/)_nyK 05(g?=hPY5PB'cSfEඋN%jD&`wv\dK?c;|H _+_Msj:Ԩ, 0<#~[ LS/pPzP)'넋Lqɿ `/wN6B~H@_FK :"_9xn IJOjuh75vMS9ς6G`c@]QK ]mk9G`ubM ޮ6E`)G 9P~pkik>=E/3J8ך?_@\ZS?q^|!(2%\@Ϫ%gZ.ʗ7΢h?0h#fqoWGp#f Y3c pgOCY`ƍ4 k(9\M/~qq2tMPx!KՇ#_+_V %wP%_ݮ%g"{]S.?CǸˮ HF'YeA܏pO?Rւ)4O.dP=z6T<|υ푼2H{p./W)Mz f}ס<'zmJrl:rq/{t1Dmy^I.y^'z^.;w<_kҴ=Tk >(T D.4.2.2.5 rcu_try_flip_flag


D.4.2.2.5 rcu_try_flip_flag

The rcu_try_flip_flag per-CPU variable alerts the corresponding CPU that the grace-period counter has recently been incremented, and also records that CPU's acknowledgment. Once a given CPU has acknowledged the counter flip, all subsequent actions taken by rcu_read_lock() on that CPU must account for the new value of the grace-period counter, in particular, when incrementing rcu_flipctr in rcu_read_lock().



Paul E. McKenney 2011-12-16
perfbook_html/img317.png0000644000175000017500000000066211672746126015320 0ustar paulmckpaulmckPNG  IHDR."R0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@f0IDAT(Q=K1}ݻnͩ`A5`*m+8PP?a;+[{Ԗւ3ɲb>7%>8֢(:LB.FuPpp@/af[2v550H'h'{6 ~4tH\A}AANB O6d> p-q^[s6!t;r|';+>Dq蕋|A /GV G(nϊ%̧V9 .>T<#/On΁U rWܴS՝ɜ~ٴiBIENDB`perfbook_html/img16.png0000644000175000017500000021244111672745753015241 0ustar paulmckpaulmckPNG  IHDRYPLTE{|М7)%⽳ݍ̳ވt鯥ՠ业𤗙օ"!ԗ˿̨ۆ笢Өv{܁zfkظ O>=()qxԆoW\ѠùٖƵۭlq¹蜎ͧ?3/ ;-+؀ݣޘ·ȼ^JMVDEx_cʵE87eQSك/$!ȷtRNS@f IDATx콏W[Wv(%%JDŸ é<-}XL4IT|pˋyv$#KOD~Ld[+qG)aKA s1${zm}gMGxn 3t#h만u3 |Ə2s)Su`gw{S֕ZQ 2d\|jr0\CϮyumpfw\%[o{0rU1:U0jyѷ?KoZ;>ztt$A HXQQ!48]!t$k'lp|NT*M>sIzhrҊ@Q%YUEe^;u @џS}šY)jP+zx,2{y/#p]ّ&\Co5t/HKuAMS^Ysa~eMs0TaX(NбP'0,uu/#ٗt!L,3(E jjjކR4 SbZS:7]]GTxhQ5M)v=#ξjKvxNi`0̪ N!h0˲– gHgV%ԵH8Yz񌨂Y (ɟQD7־׬uKHhdϒ$ K_QChugq9od2DZQ XZ޿7JUzF!I@SRB'pMz꾀Kz!U@x̼QB^Ϯ"g$)E`@\cר_j: S$m3w0ʨ*s Nc/ MD,QD=E/TnL1 ?G]t4~.#Rc@3)kn3338YW8PWb4b$3ܔ9qe A}i#_%?޼ 3羐y?ߣh;k[4:UQ,Jmý/c|Ƌo8@X=o=pO ǫ#>o9TGfK|#O_!_jo]g3+E 8o^GM얧=%\A_޿ uaM6/)E [Q^5q*Qe "02!TNO_;}Z"qԿk.HSEte!:|ۅP7f@F-OKiJ&z<IP_??;`$eZ)׮Fit1#YI+(mUM%v횜u)]vוVWue'Αђk%%%'2xkL 71Etfˡ\ Y9=2i~,5-#Oq=:t\|#4ANq/S} ̵TPPnI11E d<*j@@n!̤,w(jbƟhrsf tު $N2(/M~{NJ&6i̫3ԽZPHmT h O.STꕒpx8bZf ˞,H@~NybV,) >_œogDgCѹ竣$C(aFfhyR%e\5_̺Q=%U'3jcgrASꎀ" v+>DM^?:֝|N wd3qB쒙 ILQ*VE3ch0zj~F(+#7sW%NI!ZՅY y#9PwE+jc߳{t/څ0):V+'s3X` ɔ2C?w\]ZUC>ˢYT~l Fo0#É;Cu)b[tbwcqA7ɍ> e$D2ٺh]ѱd!KT wAOx8N?xd3򤽈,"klTee.W5(d`\QziG߰o\U{-Yʥ*niU]G5+gow>VweTŊ@GE=@ZmҬvc~D:=<6m{7_,6/X]dtYUBlZ.-qGfneTSa)GXBZag=1=[0+Q lFY|ٙ4#MGV+tzf\X^v(} 'pzTp@a m׿|k}aҀΦ* _U tB6n7j$L}LdDaV(ՌCYmRFAHf)/B:Qk &+1v0#FxL+jjٍ͞~rQES`g;M^jč0cƁ2_Og Z}`XYRb"/[y[ǁ8},1nu$Cex\%>0#L'`|ۊ FzѠq]<_RR /#[OX%X2HTa2 Sl^.:$`zNci並ɞRJg`9YJ ,KrŴᣩulIe{A9" e l1~sv n2%_&9+J*rrlf]]]h[p(߃@ |A/"\ O (bN`ѹLRDU/_*<6.]`d]u ЯAG?/+.`gARʢ-h!0q).ƑY̤K\8sSwS$TuE3S\d> 6g HBSWerSÖ,5LO7࿩[׍!%:z'_2mg^4?g~_pO;KnmqLz~ch'~XSvچƙ}WTdc+G3I{f뢩nʮTkx;Ŏ. Yѹ5а4LmMmz"=lPۏ=fO o;Í ߡwm >0`MxṴ޶PΠIy&|s>O̍Gǃhd7.9Z^jd03QQT|K6-y,wcMNq2ܵQ^O-1 V>91:A#"<V{mHn.99bVW۸Kn袩&lg8p%9󜃛7Y'" '@C]zشergܪ8޻w?M}^_g֭iI{z>0[ 郊7QfYY8C"}k%qSu$ b3RO in4(Lggpآ#t1w!{% YLCO%'0F'ؖSji19kNRz)}|dKC#lZ"QqѺ 4;t.\R w7iV+)m$\8g͝'tWb5q~a}|:5Gwhb"N.8m$J3xqpg|0̡m!Vܚ4c]O&DC_)JOS]s9-lҘ n:8[H v^($hC%cXYy:ͿӺ :v݊ vp nۄX״Ͻ%sMgH8 t e qU,-1fpfo4uwqCM#`<ږyHK/FZH7223ZIF~Ȩ )u$H.T ]§Hu[%G熰, W8T,I1BUh0)ߥ=dsRN]%4B0ΝC$*$4&n<8H)L p^C Sa̟R_q(3Iqۥi(JByc5RE]-},cCI P `22DBt,B37զf>Jvݙt^E S'2`(2 lGp&#J{.Ø%vB5 }}.CKkX3M`*i`ɺ5Ztwv9|-Ų2nw=ӡa=D O̧9`@HFPI&rfi/]J#uiJtb) p{TknкHD`-a ~$,qb;re37Eh<4FrN l 5Þ͒ .uX,jǢIr=iuuD]qGNd׻9UQEÑ}1 ˾P΍14`|Ӥ@:Å̦TWLV軲MN,wCNݡL]$Ct=f"ݒA;B aZLBu > |= \~( w(ߘ"J#6P]Ŏ? NxHQP'k)D$?%u&Lo+j5M7ʹX AH>:X4)ͦl 5܅02љK;X.c(J7Xz'Cy@"˘0 Ot`l+h75⃁l㭾H|;|3> : 2ٝ e2`YV'PYKŢ7>lUȶa޷$SF_Y ΄nR f}Lp/?jX@y[goh)-t<]ZѬ;?:?L+։hu"T)ءEp{+).vֶ/=gP+L/׮tڭ?ti|vs5>ֱ1x[kd7]8]OTNlaYcVrޣRJq)^i$[[ܼi2d Tf`OQʦ#M8 =ˁBfņ(uZDa**_eZ2Q0!uL*&p;t,./w۶m8tJr#~/Јѯ h*J\q{F':F۶@LlN†-*X.0ڡifbP`IcL2n{0:\Lg \LBmf{_! UStBҒ* a21PAv{+tz1,[p3R`]!U@x pT8AIkSJU $?WfY7*@ϪЂеlZ-nh%ﱭ IDAT4CxcNwj@ ߙoeZ %?`J*zI/ 5FX3-C?w*dޱ¢^g3ilJPM`_9U|D'1l>O8蘧9A_/{>xj0jЁmԹZ%`\*L դJijq(:,wz}6`՟==tIњP馜zRgqamGmᴗN@[lA4hdfĕnz g_&y%i}8@<(g6\mkǑ˧HgFGLKgňɘ%- emFIl޵ǎ+թFZyUWxGhB6+8Had|_UŬ~U5No30{yr!j!] ):'@@HOl%mD_6gqT čE.gpq-)]K x4Z{;G| dztOTF^JZ $ˆ[XR~c 5Sbu#y3{fN0g%Pgm*z WY6/ I,# \?p7;ϪUǍufyg5xrVD><१hd'bq lYĔMߋHb/!)(]Fz9U1Wы3Ib\{!4 %EOqr!:M?ʢ,+nV,Ȯ6C5Fa)cgB97m#Øbe$BZOKU\./YL0x*f!RPQDz%5Юe;|ݷR!!&g%J6k I]^|Z:/߱TDpYԨS0Q x6 HL+2nŪӿuid !~<.Ch 1PR5yq1xٌ7!g?'IpM>>-s"Y3J~qEP6|VK(bd3^rk#Bu^yf=$[ė"' Bb/7mCto^es4lżk O$|ԧ44kv%{|QX_Ev}%{|6=о/(q|چOδ(ŲGk=4\z_Z{X}zx}Αco?o ,,-Uw۝V}UU-ڇqߠXΥ={u<;n<׼8vǎ](O;֖A=tA "v[Sf5c-bw@76[my^{:%n76_f,jmZs:rg3߸OJ&XYyMk)aZH#ݳfw|ڤ}֝dYʳ-/wr4=R W͗&Uрtۄ}=,W{ÐmO[ټ/lgEw˵m( ԇ']q2[3304x?F%N!Oa!YUӚow#kCKaW/9Yr k~lwZ^-)|晏6գ˛>8]%;,Rxۋ.I 2z|(*0RtXR gY܈H|| 2Bߧ#evǏ* x.++;}%>x{$;9z`N¬.N8eE8eZB.;3RA%s2:ٛ8ϞL$hg'OB$qOFա-'v'e5)#>tM;/\͟{i8,;b[a% 'Պ>t/N%nMLºpF:7phfhO{Jy.1aEho {mOSֈgR^<]v53a*Oј"Qi&K\:Uncz֠eˋG k|%8)e\{߁w?Y֮ShrcN5kk0M{7rr:t;3qhH^O ?tpUoUI-B:)NwSken8mis-/_p/aoqeGYEH&HtXS%q)sUg~?^=zO MiVK,tZOB&K3yE`%UE? b"Ō H ZZj4ҚY@IM.k1?^xlIAї%kHeټCh20B_f?JE1SU|nBD" u0h-3c>2 Dr,BP7+&b:xVdJYy~8nW_gbI5{8 0L]!cㄘR2y>R1],8]`,_ꚅ'O'T9X<ʺ2z33U]o[浘ҹ,E=]kkF&%3(BE*QD"yTSh4ɸ l|b9LV @ıhlwz6WqQ÷cl 7X& 7J9_(` B2˨#+]? 3n591VcR`o\ՆZin V[šB:e(Sc<)4̈́ϨlJ3EH]veVZhq{ucs%-O5$r15L-[7ۍw:UQG5`)<[[ɥ0q JGhp4,I \.,yfZQZlZC"4/j)N~8~)HaR`:7wʚ^0@:ݬO/fF#Y-~v<%P,DhM1uvyJCure(j=_ \9Aua9w!b.)N5͇ Ae336?h,7!N,%0):70UԳYJHb$X0 ;c'jHBMӆ1}+S}\ϼZ,M;  U0|]OSi{h5ٟqw DoI 0f8tԌ6jx*.? _y,^c5lg|ؘg|WkWdrQ AXF$]?oK6R3I+nmҸPP|ueX vfd0,A>dZ+'ٲ,W׌asxS&{϶օwcw3v L ^1*H\tn2Z[cdxp gxDt4p(N0s" Bԝ- @oPOn|y^N2:TnC `-ٰ&}h` q͊)~5)b (y*(*c!@X<(AVMQO# ,eӦ[GNND<U0Z]K\^,6~" ˚Ƃ7E=Lv3ݖ}Ei^mvlMGD].87.*a._&}m䓇g[щt:vAyuS'i`#0*ʚJa9ֲ1@K!aV3%J<}gq1yƇ_${qǻ+'Ê X4YY' D{ 2n\j/KZD/j̙f}E %E3/?Y?;8طȆd`,#[ZZ^=m wC}Kr>`ԵV=dkk0ή9z ]]Hc18ݢµ}@hV^(>sg"W*q:]8h-זھaMFùkȑBt,ZFd&v`1 (nʚV*`0D2*c뜱qUbz ?~dg飏vG_OE@`bK`7j3AV`W?\a.̺㢂$L֝ 4wtnսay)K] P\јP=t _n>쵿3iޏ<-#ز1LO_w:lɗn2;ZcQ^ˆwPn3n66:6 sHլSr\LeԄ8CܢWԩc~CDonb}_,$Fmj~] t\Io\%x({Y4sGy}`=x^Z>f%G3iB3cmq݂P gxG#PlFӜ7V9i18u+uˀhf=L\}rm蕹J5;Ze]L-| h4N WSgO_"z@{ `͎fa؍b|Kmu||C׳(Q+S6WY)e|y nha8ʦЪaRe{ *ͩT6\Qa{aN5 tqQJ_f*߰!B59rReZY iT(uBKMˣ䉔XZӇ~Sm"{4-,x&B I셵-vw,|}qkܶU5k06h'`* Q'̴UfC(sH[ފ/3;.\kK ۶ u~N3_.,/m4\FVh3܎c&G ؛&~ڬFղzBYs|q(%SID]Lb:JO w"rLպ.3g.~pqg'-=x(5 rX |LDQG㘺˘vZ]cRP k \q ƀQa*kK- Q3jWn tq0;z 3 hu=e7lg}%Njmd*) kllݲ.6Erꓖ2բ\`MNYP U7}‹0ؚOio{і쌟!>rhUQڈt;v  T[\?(9BhYKgu~`nx+/z;/?Nv/̿,iȔ&ټwl?M|֬S>Z]ھ Ipc } nyy}}? b*OĬdʖ5O&kvst۰c,rtz?mOx8Uiwy!rM&AύZ:xc}LNcQPq,u9J?ܲٿ;gWbWIV7S?À:D`x4dsGI%`*`RD!…^9h<[=ٵFCc,E^ bTR'y?-߼ t5>#Yς29h{ kHP[$z%;GLPl깔&  9S\" T*ZcZ3x׵.er.J}kS8vFB7mKI" +#T5WrVuJ=,]k*\:q+j5󉋘>7EO Qhzc_ׇXlol g?ʝmX^x|_nOuHХn ve)d?P2Euě q"xɡp,Œ(IM4s)؊u{ //ꞏ_ra\JXwNBWC(BM$t3t .ɔuf֒Axwcu\E/TLqDT,x&oVLڮVFhHVfT'r5ɄE[Lt5}w,k ~G$YfYESSf &ID&= >7vfypCےg|;\QȨ%)vSzE50=fEʿ1쬤I*Z1+'K*sGFW,?&fZ=(1U-qJx&DKTP4)x_xnH"OXMv\b<ĉW$2 gbp\KBSyW%$h"q)gmdvRy'$vtH"&ynV2Kϛv xkl8տfSԦtч&&6:uUz@OVDfK"D T<(}sz!\y#p[+W5Efe5U vKL&H1,*?NumxJtm]$TZKTP4Zסq0Mn=6Qq&E6a| 5F!%L//؏.^O]& oT43P̶K#?%vTwZ{[;B'R26؝2D{~D;# &dݞTUl*fW<$f95s p"՜HN|=U\FTșO4Kf,*$j.+%>N/ v5't^dVqr^ zpUq"U;$֛W0o,&⒖a'om\#{7n)32yeynyWro6}xc}^%ͭS [NO4}vb >(̗)f>f/3^&<̌4ueRymo{JpUs0?UU;_o؆Ђ%:װu݇p|ִ i/|IS3 JpH]qgo5LWu/e`gJ~%8¥o7</w`3u.gB:|,Xy/es8>g`7ߴZT\i]'̶/WuG(GHjtN.JgTOkA:7t^]Ćvk5OL%jU?o =I:`7Ӗ3f, (53[:;Y)Ii=~sSt>vZzLM{ؕj@ J6|joŎ"uH-YZ-]ilDyݏc`5PbcXҞ=KKo=ztс_,= jbQb0Yglɿؾ=hJ>XR?`;*.x 6^; ǰuU@lnmf~ ;Cɥ'o 394j},[c^S{7_3pbJù>R'wB$`m&֑|;s;ZWμ>~Pх|.F(r5mh)KWin7 #]V_ns(!X# d6 ފ:UK}Q[y;6꛿`5vg&M۽y"G'v|z9묳zca䘒gU"E\(mUŮQrTQw '118B IJ*,)MJ64qlhvZom m:tE^^6xt#ܜopa+K CEi )23/OUfux yc)%Ə7}i;Gy5=lz<벘g:`kE[憐6Y۰C"o 'Fᘼr佩ࣽ=Xl<&r; Ɍx!g!o>lbI6^s65S޳'zBTd%Kaxɣ' қkҡPBO+'c3?$`H!m,敶>]y 뉃O`[' {?ĦQade\cz6-K'P.(ij n<ӬrHE:< }T0,,VH;a_,iî>mp OhZ yx_%8ocM<Ŗ-Vgӱ ~9ˆ6IICe?}A%ᛴ&YپXj5IbƘ\8cXLB]Lq]U7k%M9/պt-a݄7$kb>$Z mjE6v{=zt.Pkk9<0͡/n{7?x̻x<4 /8[3EsZ62V_rw}"Q=ZFJ iwcFV.dǙVa격{۴IbG8*vZI9Mi a焤LNbyұ/UV^xo=P)QZǂjPc!ty\rD@mqk%Jm+ zqNz<(!%Aw1Gm5 IiBӎ-?]'wx^p RKiJ*C aUg[٩ 4*:t7n:l]1e8ͣ-l_nEwƗl9:jz[ im0A@` *kZ ĦJņֳV2" +tÁe,4}e <#D4 憦FYT)Z80VUc-N `3P-bmzBG[ਤlu>\x9[@]H"S:z?*&#8[TL2q~$_F顦{ k ~R7vı" w Og a<^ -F hoAHR-l]W=:H{$:~un{ TLAQ!O7PlaV¨eyzMCY.s .+@B!r-JQbr$$6'^G)tee^ab=C -dۍ6bxQ[V]s.n%`\P WYRL48N+RTA#+8v07TVV#!pLPXx]Yڲjos.] Vm vD@~5䦀d10% 4W&Z]y쯮<)K Z8cL.pՁ 0gk D@m[B8lV GۘWPu˫]$V&`wᗂ(Q+ a99tټQ(}pO^A@FgUaG1 D /˪f j}ZtZmЧJԊUPO׆6R0:!Uxٔ0ٰ'?ioP7Ʒ< B=b4CA0-ḠHA`gt]e^r*8bju8|2 XdK[`OeáYzW9!ލ~$I2gʊ s $j*rE%4}@PՒBL gU|-7*"H^\ln. jn>V3?K8%;`ÇhKo‚x&E?wtBY{. v>SѲ!"ś"DCQCNӥm!Pշd0.UbJ9B QU˪p{G¼.Yw!#ꔍxh<{+#]gSZ'.צme o7ѹa-r|%݁뜭qP&הDK5dj^K,»б`b0Д j_ -bG=]G[ey!3͆ ?:$@PB.(y\vkOayWKaY㈽S 4f*C'`, SVQ'<|̙șg_yws Ǣ*S,3O@D5 T+)pEZ@`e Xm3܊o`€:*c Kېǹ $*DQ=g>(kG o4weΕV=t<=Y^Qq]X{3[Uhg|B-K 6nf`a+0.\L靧RBDkw}Eu3^3gAsSܞ-8Q7bSekSj^dt,.OU).:v0X[L!ek.^ԧ`!O_.yK{d;D(ޱϕvpžz̴)QIgӹyY,+wsۦ"Q8]Ds 9!ׁ44Hܔ պjI2H&e@ivk%E!(E v##1F5cET)IC*`₄|߿uۢLM$Ʒ !;p:(Bԭ)W2Z[MEIWýrn)D:$嶉Epm: RZ^޼n4,k9رjUWQ3r3smY?I^&:Sd2%'wزX*.lo=+\-EgEJ.5mǎ q 4,;G嫧W32ӓfxdֶ ue"v R#v&"RVR;£VY&|5 *C`{xd!рډ,(l?q`h͵ܢ8TyaL[*"/Mp[*筏XHcx)>a0i-IC3^iqZH8ܕG6yq[v[DSmljHxSJ.й)JWٴ"I5[Gwk,yx8S%gGMMWs1O!|Yt6tTPT6^LX(ۂ}@bY(-AlA"'$<\N)o_+e0Z~ eä=r,:#ia )nE3mqnmmA'FQ\=J"ӼC&7*ܒNe6(iFKM˧ Lxti= \MTB&)7\T4k]+M'in{ D08#I \4#OtJi ʳ~TY%3"e`f6]O4{W ܂ڂMGvl4/M}5 'RA4`yD *NԔ۔5hm;T/7;Ox0!kHl8/S)in" 4p L*6#0D{)(Z@G%& l>ox!I ]ˊf5[9Ir{~AnnAA|S\sX \|g!@+z/Lf^G^ݤdZ$Z%ҙF 4=x4]N/ ?Q^ˀ*m{ /4ʫߏ6(_rkBY'Q&+t /nb"NB+Mr%X* 0iL:fJnq88u$S2 ЉN~J|Na{ n;I\CNnOqo/3cpejcoog N#ϝzsFFvhSaT)U V0fnަ@L Ph xwNxA 0٦o|Ы@l.bݣ Ȉ^bWz͘ѓ\Dk[KR : "a患7ܜa]@GM ' SerO^k푝33S/3 n@A&lN*Jsd~wXH~:NPXFYpP:88sAmkȫ8?ڄ,{>zhah<""y%EL# _y3lmNV15_͟q{IGHUR!iE`-k:@? W-a5$/I\|bUZ.*+ y_}pdٮZD82GA62ϛ"ڂ9a0$rgG+j<grg䷾ޟ\assH-*` m~#/++U].Ru,\c[nLPݶkUYܫ ù]rЃ#RT5MATO~ڞ94׻Z5oaN'Ie˻$j]gb5; =ԑS&ʌ78C xא?>1OC#" F.:2νot+qʼ=SIKR.-'7/OM=?7$iolQb[ #9&SYch_(@|ꂂ<4@%_0G486:%ԧK4NU'?̢mW{v]1^dlbqeKlnõNb`䐅&Kl3QijMsP{/?j39v)2 ,C׿zCT}iPHƭ"FԨLG,fwyvU׿HV jØ>Qu/# W+Խ&)at5ĚQjMt:~?(13ZDMTUnRJ.7Vϭ oo2ff$~~QHvݓHmHHN>. @P {k8 ̉sUs&DW+gr#kV#S<0T E{4Khދ P(Ҵ^]ztW7_|1|;bDAprr  oO1DC>i*j#`pa[J"|u~-ZQgгV4WP@Uk{ngGFW^\r0Q #Tl>+@/cg y"`m&)U/F_ |GpE.qShzABK7t]ysȜqzs&`)bDFC0C#ڙLi[cY$ nizpCSWz衏dea{`=w.2B/ ȩ!+ȺoГgebYSAbB% fCԙ3Or!\`@q/S؎\TXck%ʤ( [% ~C,"& S1Iv|z'-fYԿMh@y腦ql(09A]q6TbǬxykyfd%-נ}K{ZxSC0RrvvZE,gHҫdɳ wYcKR&ZA:P S0f c'ЗJv/|PErL~8288oLͦс ZMVS2D]e Ƴ,a,K"7hqDCÏ|ㆦM b@ Te s$ 6*}.kvȢV-)cc)2^(,ݮL_W'UeIq|QM_FyGy+plU9r~g!*vĉIV v5jq[$oh/ZN8'+Z!9Oj@2WQCQ70,!5]4"]<n?qZ,,<\$ߩ 즂qmu°#q.AOtMEii:'P )Юl#1]E eѲ`GY|fsѷrwfDk, S)_G\F`5b4E΅ڏ^%VQM[(iv 8_xJfSR YR7I6k5Q٥vLz+ًҤ$i8~tutϜcI1<ȷQ mψPū?fkl¨QY%^) h0Ԗ8fffy=R}p9|`: DWL dkbmǎ mYPDi LҖfs,6dSj.hkVSÐ5(P?>7$fx!8n5ж4֟>)oqLҴV3@3™6hn]fs0Js;~\?:^kׇ3*mtVsՉ 8 ;.R(;EFBd d:K" M Zը6qu)LO cjЏΚ?_ybAnr 1 G'~˥v,$"np: t8*¢a(Lq^%9:czy_{"MSt[4\hL ^h3osDR>& F~ Γ61aΞD'4׽\NK6?V01PtIf:, W,RP^տsxQvm?!Ж0G0#fp-,,S}C|:l4x^oΌ.f&;kab6i\K x7Mšq`۠LSpn|rTvYջS) "/BZhMJ\HP' | BPdgP ،m6m Mc'xoTgR?H\K7qQfYr EGK9S6Y0Rmb2*xn;5e8eTZx J?= ηݺQ  -*Z'JBXÎJ-"&c(Y.} BZc!8+K]NVsk+۔ye.P~}uYD/f!i0kDL` ݕC GO3_b}&XϨ l_Ho.[e4k0 G7q<"R jQwZE #c?H\n4GGjQU LW$sb $&Yypҹy*dx[\Q֛y*5ͧD:@U![˔<9P"g*c`gY o]p=RMU}i2-Y:5CrOgm׊$WKLԃ(_#XZ:RsaƗ# Kyc-K7ut0ՐX&p*W$5j"L/zUsxe~TvnƫnO9Kil$ MLU*Y1O7 .S^ךCۨ.'!-~P !`Ofn{9bbNΨסOSTQ!z 4k+MG,YKM2,h@51CR4W9Y6OFk #JzP@V6W 3{ϝҋ]Q.Cv8oÿrT,&r)!)|aHq+bѮi 1]\#@w1e&(nJz8nGW^]%bE/TTg@J]an'L%GpJlbWkg8B.3PIa2]ݙukEK0 1qd1VV oO|Q;ă!N֯c`Uk$_.䬆t9j |>Vg-ٌž,`* ԭi~g<35xέL  4UR?ovj(wU4-%* SB]礯S$ A6gOѨFXUq0"DSCDRĒ"KjJMMv &Gi+csMdMsiX"4I,_x|,ҏ |?hؑX8WN ozv=AJL W4-#K8eь@ H<a w}jba%| ? |j Q|aT9Ypi ^ YjBXMZBh.:,)T SER{z:?*.;̨ݚ'K(42t z%t2']{2M lc:3o&#. kb+Ji5pD㸰 L~OuiOE[ۑ4eQ!ehڻvo|]@*-X7K`ʋ Va2>P$\4 JϚ}RZc֢di +XYM1wj0\~:͞(b ^mi)OBH*HhZa+`OB5SN\Ϭ9+A偋PqZ@ Z0#t"3>)f[u^z\rk/W[XWPSqاIa39kUZ^V+&xN_VgPñl`S?"* :j餪hZb<~=U9ʹ6ȒGxv K׃.^غwcCr`d \k 8m 7$AP}U`a _r$h6DMjhUӂNģ[Uc*c^AC1c-ZZr- 6%*?iSS,%di6aCgvan+p|@T9>oqye5~i&@9ٝe^ 7qђuqxh9k`0pxFVve X,iqᴤh Rz͸\ARv{جyjݟŁ@BK':!^8.ƚX>Pfӗ`iEmU.D<\6r]'!ʂNuH,~1"zLΩ3eTsؐӚcq3{܍8,˽q5|w CwMr@榦SSv# Dn>[͆uv{8k rD`9tGIiJDX։ik@/W_)`@|qf BF13C0b]r/2r? BRurb?$QzhdOMw_Į (CO.[4@@GcGEE^%_bwDG= x[RI`.t'˱[I5Ob+7[A)(0MU2f$QI/5>;.6|U,YEy4y`pUbD/l0ʨy@^⃮z |r dl`J z=>:>άӏ1ЋT^촬r~^3,"2%Rid;wd cde l;fBya$Y:;>}<څK#_p5e1$*/L%b/r_h:/[ucQc]D c&+Y ˷K{+Z-ŷ^Nt&({e]#*Ab(^Om݉X\b<},SEЊ5W['^`]BkBiivlwghj,B`݋Om-`dcI~5eNaFv2\aݑiDtphtxEbiB+ؗYXtPOsɒE5=mFDԻlgd͝a/H@' %kfgsg{L_|n-i~>:yER>./wmm&gv_A:)svo;fkbNX/k7 S]ߵx]&OOO;~#W,? 2ale"+u6_ݶ_("?NP n g_go~;qNuώrguwwۯN uA_'s͑#?>W7vٺKK#.\Yٻ+Ƅ/8m_gl]呕{iM&a[|ɀNW~/,&pJFxi=$" U56Zs_a`n-8o_EtFuXP+|yz"-)RÒ:qx}E7 єtQ%/uX噕sp{aDkl_\?;װivx2 BR^1YPX _o6nw۫nw:#/{[9>*ʚN稨.d"o;0(y[w@2:VX'' ?ގGFVw. >|~ ½vDlT]}}m=p{wMͅO^t:2SQQl ;"}t#TI{}eK#?]Y;aaoYW趮>ͫ^~اKKa!GB922r>"bbMe"qeDåw`'F.gOVWxbG ٰnW}wFÎ!Ͱb'I]Ev#ƭzF ?,~'_bl++7o.݄?qf8{tX7=>ʋ3}-z>}s)-_*swz/|B꩛c]j#tWstݢ/SG:3Cd=#Nuuij657o3l䀽A6L="v8wuWg<O=ׯO^yv~~;-~|#+]xueRU{}Q|{liI>̂]t|"|-_<&>y ]\US.-__&[>[ ͎/.,e9y!f,+2952Hh7}A~Lk*̑eZ5a_ zĉk-5UѪ28`[9CI@<2`kqe\뭎9W'2.$[ZzZ"U¹)y-[+iyl-'_ۺ-gk˹FDqӿ9..I ?woA@smՆͲsׅʿY_ !1:W|{|}--.\qe^G<޸sK+b\^D\-kƵgxī Sʹʟ~8@u٦l FMŦqC[}*q4ޚl[[겲[Qje͹;6][rgǎ!Gk vF+w/**Ѐ {[jqe-9:_NhdmE5Y#&P-qvi%< VJHԸwg9do;(1=F;]H\ܝ?nw mʃCwڭ p,zÏ!ճsov$AM?s)|nX$خpԍcmg;A|J,h䮗y;7_mvNx'ym[c;YƱHζ_^GVO!D2^z\5헶o?FutBl˽Ys?#_Zǎ8W]j4>SP`2i6?xl9>~o%I^>?c?w+`C!B=.X~>ĺ(R:m=uP 9=c.z`.Bwxh/&WVM^c{{Ɣ+FuÞ[jܒ%oga^;ȟ0oo=F)tܧ냶mmٹM4ʶg~{N[RkrקO4 /ƨ  ! *t:#vgMq@\y:(t8ZMW6ؿe=G|U1auS٣_ݦ_}CxG?=]^RGX09899a@ΖwVz2N*bqSmDyX:UxeEW\DFUU4Y~zB=`MS%Pn+-)YDCx7ǁr~=}k\\2{H́DWW#I+2daf][C<o`\$j-˶J$綸?:k<ql&H&,#nn^t3@xX[3qQ3i;sq;VǡYnz=}[iErœ)3@}$֣qRX~m .˲T۬7`osσmnξoC\$&x~ɿz018x>q}xJ w&/d 7lvs|a2sg?>0|;˹ Geeeud=<;hqy<#c]IPT$ԛ7 ~H:!!B؈v0Bd'kC0A7DM IDAT ')}u ?̑IRf+ig+gmsktzG|%<ox&'4uXMپcD um#EԔAs22l5A o|5#$%]fCdvv`2SZR2GלB37^Xˠg>Tb5xBYpDW 5[e2 tJJ\֚W3[-=%=LƘŽ}sC=tg iywe2c*m:J F.<k:n55IzƵ.Ai__u 9VhuחC бOx+G~+Jz(#b5T=/(q%޳0pNʳYMKj6Pxɹ-@ LLZAf{& hJL|%i)YLϞ~moF )ʬgAx0fgb'|}0fg}sC^+\2n1F525l:G9; ca'߿A|^9,~MhܡʷĨےCʕz>vpSA |znLt?U6l|Is65u0_? O]܂uQ]^]R@ٌ1Oa6:8[8jb>NO pqFfPኁ'Az[؁bI6z4Ey;kA‹G?̹q5W8+썖8[IwyVܙ5Ԋd`klo.lMyHMOc+3a0u*|Y6-% v\QBV@ph}|NL̦|mFE|^o H\>/<SsrDeJh6K%p66,}!#hDu*)飂jԘ»WjV_f0 Ol $DƁ!ĺ0{ℵY-W0 pu hKʙk0 v>HP˄wzŸ, 2o1GYf]ZhJwyVrxFMI\ qz fŽ{ycle?W 7Ϋ<>Lvbx'ܑO`4qia#FN߀See---|;z4y ɬ c/@IKh4${.ɖj03bҘzlO^Ƅ8U{4h;'}x瀷~ _a0◠{,<`UBt =Mx?> ~N#1r@Sg8ڶ-1#"M 49vwr?\N𣒒yM ?1 1pI%:FOۻAU;qt[5hcE#\ j[1&0"ZxSÊ;1pU~'5xRuW6~>hCk w|ry XQtO_ܼ{}FdqiiDāc; ưKs_7_?N>VTR"Xk WՆF"05)%QU JWYIT }$=${gQʀ!ƺo7&3?26cf5?.<ME!{obi㒎#+['^*T  ˆԱ$Gw LBv{QRo"0.}fS*l4v(šyR5ʛ JHyWVu`DlS!a͔Itrr8OO]6Rj p^knJY^;MomJ2; XC,C qtn,T< FJ&>x3~ꉲZC#Q5/_L'(xIh$vnssԴ +lsEgRGeFY xkI@0eOuCZDzB֑OR ' E?.1EI@di^t6 WC&nfCt02ч5_;_`kytp.mnﷶL] 5Z:$\"X 7*@!Ƀ;. V<'GF%6ɾ븑QpjۙO)#cIVPZ0HgUdi>*&E?V5ƭ՝R 0t,.lXD0-A2FP!EeZt>vW7u~W_맷l &[˷$~A| Ds!A8U[b2eQ0t¸q\gg̕QJD pIevyx׹dGZtXx$.]J\ϡD%N^RBB$D{3TuNG:RsTYݞ/^K|1g2j<]Ez>4›n$n8gPY+=D֍ \=wT)v4%ɮgH@XgG:ղMOyĀoYHٟ @PHzV z̓ V+4K%gxm ̪FK54@q3霯ysdl]vWf2LΪzC#1;[sYV'|@Q6U{>nœNQDECՊ6%e&#&) E;=/9$˞0juQ#M<4 &DeszlXa=(/fPʹ,s0!u?צglɾmV_2+`)4;b>Je`tl8JHxr8V#eM{Q1rdwccDʼݿL:O XА`aX+ZDGFSt!mqwv^SgzH A8FgT͊Hf%G 'O{Zeeeο-)q6]ŏc:2T@ ( sc1#̘ rMj\M<=Ods(H16u.!L1Chv_Cɸ@q(˄ (TsS q@,GD.'X̨08@%5pтEeU@##CbhNUF"Ȩى`A;ݵe}%d Xc@׍`XhTIVۚa^nj.ʲ5I(-d7Kֺ c)CW6jS@@o!2f-p8UfSaEjfԑ

 حH- X)9k% T +zQ~IyF]4FM|lV 1T8fCWkk4K ~Uu*ԀQ&y&뇇Nw-F/D O$6q]bڎЦPSX(qa]V,t{^.$VE H52ybX^* zKHϺÓeh tlR|dρ=pYS-YBI eKЎY k2Dm;"[Dz uG8Gl`*dR<|  5tBEG-ds7*qQwn۶wߙż?bdW\*'Ojᴯ}FOZN/y ~&Tm{ӈĤ#ЕmN|yBwX= qkz2c =xBMa fk:?{^b㧂, `ܚZ%-<Tqm{d:.;9;sE2@l|Ӝ>Vm9V2+#(Sy!­fE~T-D#U+<~?*ɌT)jw$:nd0O8q13ʍ|T8a;F5&E<=D S\R"rBMlXw{|55C+8pSSՌ׌|bT޵jLm&R49cGî㟭ZVTQA'-dNGص$mñꍓSq[ @@2ܬYyFi~+Ѓǝ>ҠpKjrtg I+:Fh }Gձ w5jtuD=]TH6y^Vuܬ-a 8 Cj{ork)ؑrֲ NGۮٷI"7/~߶ƺC۬þ#姫?S~8)tw](9×]mJٮ$V&lBVFk~6rRk2^1OyX22r:3Ji|ҀL9=EPF_|@ >Pҭ`ƽV`Eg^M\HVMVk) \PbxƸQ IDAT8иI%E*4=_@0Vèit˕Q8pbbF(~4QkY>2n6YVX^g~o'PXl57_mFf֦M`莟]FđB(k`z.Y!Fs?Z52,͑D&?=\d˩kY"[uGq}$9i6&K qd"Y0QsjRuFȨ\RƛWPw9}½/ YG}?+)]mzm6ՓQ\ A\ʒ')ݽ O&HE@T?,҈׃AƵ4z'`FPs&? x{P0ab>{7\nbZܔ.RRvi$haU13 uG ZvXw)~lvÍ'OD/- z\Ij!10ymkզ՟XȌ j1[&"ϚqvK3VF%6>t I1O(ܸ]/؎peaȆ" ʃSF.62xϜ+kT~o[M1>K@FxPUa\ptsW CजfVܖK$F8-LCe䃲ݍEڲP( Z*$v)Y0E^{gxA}߈/ɯZGYv4n߽ cF}$}}(|*_uC] F21$SJs4ڜ"6ǘdS~7^`,n{(V4cZ$jކ q4KS)Hn\f@ l V)1 ±z;1bC{<)av~="=8!qi iQ^pˡ 6\hf涾ݛoûDž$井H 'HF*:,AvSfY=xGXg\ZFA;[Ӹ# JgHO b.1iK ҉y3?HREſ|>j>orTp4ҀrwuyyxXTCU_x Ե'_ݸqBҥjӏoE.]ѿK.#--:pڈ|*&Wk_k8GMYîeq>/V kުь1$^G~~f&]~Ele6ە%G/ڡXtäׇѠg80c= d O4Gu ^jax,Onp _)#:I{Lx(/PGR3T@T9~Kg~}̡g ;hOg*Tn;Ӱ(p ZMUOgjǞq:>+BѱWNZ2vdsrZo7ϝQ)"u *ƭm{6HL ;@Wc:C7l :/jnŴFֲ2UF⒥]¡lo!c rS_A-=5_]9֙_]_zwbk_4tpdp=6^węe']UUUe}}t͟wL>S#+ үf6/h =y<:n'ᅩ\TжyOX2K*OQqiA1)S`(7|HYK1XLӷ2.PG0w<\g//5gM8lpUp}b~>=?7UFt5{>QgzcL$ШxPKTͩ]ͩs!O t-3k >wn hMHcd|xwF_ $ +Ø4Ս}WTN`D3{n %[2`Dh@R?Lf])yQO?88ڗ_}'N<__Ttn2m//`T?fjYǾ{\.PaUtirn2k_a1\ Sjx" r6KEOn*r~_T_UUe2E2X}l] X>>(O ?WVO2v6ضʱcǂq[Wz¼?c4~ؔIZME7*,Z.Sk2眡*1V?;o8vͩKً'y)A& q#p4*OӸV VPjUQI1lfHt#%%4(xPX$}qe%LK3n'*gf@>C"\yeW3+z /Oԗt MDYJcib_J6X{06[fAm͊*iMG^'DmyT7 KW$+lp`e cTlil~"TbE7+g&$i EZ-տzRD_ ll}i9]2hinS.te/͛׎FLVr~dl2 ]D*6],T9UD; '@&z- r~}2{ր'*lCCF+efٮjL'ZXّ$ q31#ƺD< 0(5<NDZ`G9=v{+_mB0|0ߖ#La 'X8*,Sd27;ͣ+BIA8{=@Gզ3\ w'q.9-U q~&"94,Ze2ʊ$-8 ! aI_a.oYdN[ +JXi%|x8K"gǾ6on3sK׺0k@th:ix8{% ;_^qhȳvԏEm͋!5#ǤIxnߎ?"Gf_Lw'*+kWԫf>ZN@WѠV(Z]\TfRA]턷HPIW;8R$6j|ϞYcu2$U͝0|7l2`f!xC* 5|42SYՊP.nP(#A.?# ;CT YxەjIc%Y—ѲP|8r2fOUӃp$V]UI{StbP"lk^jA7pM'P1t~$c9;βŋ'GīI0;0aßlRhE񚲕YXU!:) .:-T&Qj?U2MZqxOeW*L=8ғ(7͙:W⬏(RkT8_z|tG=`pᡲHyՋj~Uf4q " 3^-fɅKpy$΃ω5<[5bTMf$jˢ)pTY~G8$˼B?q& B60]p8Bö sȘAw-!LҋLTrɘ &jI}IaԶbr-4򗕿9/),KDQ:eJα3KEE%#f-Blt& 2+n)IƆdBX[-zU2z,u kMYZJ"x1J2(P -##Iu-gWQ?ppP@"FcY1FgEΘfccl6~; KKSpgvD[Aa9SR(T5Yb͂-kdnd~2,uT4 gjĤU1C8&XO.T,)yC;Nj7Y6$ѲxeS I$P 7C&hW8jv4" bTťESұxp}|ĺJk6xM%m!5Z[|ѳD2P$V˒0^y;VB i a,Zqqf~%2y=c-wPwIU}tե/)p]f kQ ۿ{ 9p?|ðd"z DQ4;KN|a[ٖlWyA{SaCNzC:fi{$g}8i`H:B_8]2E%4Z$a}qNJl6%hPF^,tgkW)1i`8#ɴǟAe g=pڂ;w{r|s8YPےzʲd=@e^guh; <˓•%`& Î/&D6$HN )ڠ 0œ1E` }(lC@!Lb9\Qf ?FpQ¾eee\REjm`p}_1^C{,."vtZp` 7ίwI˟rM 'IQ ^S&F%z7,>*R ,fHX'¯$4Y0AXXtB}>P-M:𥬚,.R:Ĝ=~#2󶐫*nNg3AN/6?1g\ PZ>Z"j/ C=0V1\l=pH$'yVd,-L.֌G%g(X:[CAIQ\}I|z ft-O>/jxE*$'Hh4QX|=)xIOmQ\^VR]e(2n'>Wܴtblzw %F U@>a aSJgwp 0~:60YDATF"WuI0`i nRO_A*w#-&[h"_0 T_b3,ZZ:hXtT@'ovo.Z)!\[̊:93l J@G(l6IzJd柮Ŋ9YֶvSނo6e򠨦]Z@A& ͍6r]gZN`hҡx`iiP 0?0a@# UOM9L6"o%Q) k>x U݋f\e*xx&W_F$bkjݨdB&RU^kܒL6S.v9*[6qlLK2!K|4iζvֈK75^jUo(%R)T(p{aU*Em j0ia uG~p㖷$6LP&ɮUiQ[P+ھ7)2Z^& -E1t5B i tIQ*Q6gn.fӣ̋p.$ l<@sXeN1 s6X ^ݛ7]ټ/GaמW*':%L-Ye68K~Wpqpip Tc;hh6$JVU5̚A4f6TVV|eCnZ ='v>83"3Z㏲InmadU' ІSTmSSX 1XK.!FHyk|rj{B"S.+oG}W'iX2Ϻ$kkw.ŦMƊe,FE)v=:;N׻zuE\gptVEX>%Sb*^ :R.Qs >ώ4(sEqvP dWQ [h l44JՀ.٪\ ME'|9'&]:~zNc@(<ÐB(9 zeUe] N"6+vrE}2[)d.|V;~iT> M r zI>|8|NZཝXMPkNui%,j%InX3K†'aC15ԕL¥ݟ?h0˜se{:E(ZzC'nqq0hp`  t-/!Xk@GbԺWQv@;Ik2UF#*Ψ}39% ް w(5 ZFյT3)3~h5Q=3f%8o~7qZ@ D:`.5fZ]Z͛46M=-vWJۙШOpgU>wxϟyo5nXf*A.w̡kaK|M??Gt*e iR"AaodiWXPk0t?CW1x4'v@=hicmDcO;4!3 a݉ &&&Kދ~"`ʀS{.w%=߉&=rԒ -Ys]e^ݴM:t.[C~21Qt@r^ڳ<*ILPxC+Acd S$Q2f}$@_G<? i4N;:orܚQQ#%.h}&߿4A5N`IGn&3aFPOF`6Lě~&R@œv2$ƴ׋8-S,o4)kSןMv>ÇΜ|0>tXvٗX{mia]uvRf:SEΣ;GM bxƗΧyINw \/-x//-}gL-֗0EyZqu`B=ʕL?vo6 JɉK+C쀩SAAA*vU޺/MUdTU,i!6:NT}͒kObn\m;w6n?b>"uL``Ne `F} |9ET`hפCkAg/#Z*֔N0Z#ml9$*i9C-.)*7ٵc570H 1a:c6FH#+>ðhEibB[;YYYb1TZF.w9v\޶;5ưZpuS_918~rO>! 6No8[q=掵Pr#SVOYQX4p.5o%._͝m;|t/ Kz[Cyק O㲱T{q&jŦl~Fctt6`(18j5zlv[q}λ[½}x ^s-߀2헎UIjUнݓ_)Pճ2 IoI_ Efūeo&'S?&dNDSAO_qlg_cy{dipVtࡈCCX.LN Gѻ- `@%$5tKK$H-aI8Bh[ϧJ:[ɷYT9-Ilr`%lRLwxBOFd-e-0 MfO8RMnzX]<-wwH+ie7"z=aK2[|쩸xq۽Vac)rLN u%>>]9/ u큵V -i4#0 Q_ [VbRs@ѩu.dK>g"yh ] 1ï `&)eJ 8ˡڝ[x{f!}tsfi ;9_M:~T({ މ %]_u]@.`#nU\faə˷ T g2gw(/'I, s{3ߪVڶG],قpy v|O.,m4 xjFS\)YldIUy.GvRL j2!mĐRQUWkB2B *#Vɷnl綖~eO P!ĤXW8?ҠWyVX,ā@DȲ55!Ah8pTMҹ\V⊴֕ƆHɸ?}߅^*lDK3|I~u,Ol0, 51fak I̗B4NTa'dKv Qf5\eK$*#,)w6a Y[' z$^4w=ֆ4nSn2sٽZ'v?>#@ܥ**.ƒiOg5.`wpβF42ҙrYe=ʆ]t+pK.]|NR CYH2IPWҒ^???{I`"vg@Z~qT˃- 䱙 6^`JOOӕg5^`l3ZYOGF6|Ņ!p}l5T(T+8NrW/rh&klAc yڛ|.Ocƈy0Ch,m ]Ѭ( йd<+3`1&ӶִjƇUltJ!PZ4'XQXfj|i;.'DivjE*Hum+QA)]ħڷ Lv.n"q.))Of ]ڋ!/tﯶm?xxd,BWYYY$}Jlt${- Ds;f-hYl8,zk,M2WN2[c Se{\Gu6M7oS g?7'dsϸAcZ gyT_pi^~FLz 7EJK/#!\>ձ@R1 /O"n9h6 f)p@ 2x*fwJUVOsdd\nĂbL٫$WJ3U\3Paw4,!O-l`$a#-0Z΁SŐ f4^:~K*nY3rH|־f[^szџkiR>% %j fQt:eL-;;ѨY-xk>*fם7wduƴM ͇ҺhC6=վuwSjcVԣsn sqfV8[;ZRl .jb*5R]|i"E`}K/&7<:~e/yP*yb36U,!ЧoM nSdYqBAo.>rd棐]]8ڙޤ*7'^%x(T?Qch@9h \7x0GO|>r<1e\-j r<yx+X61,_Z_w9?yR6jAؐ4qDhv׏|ˍ\zѣ )vM. ym!>ávM@Wm̝e4"QBHK Jޮ:TG%x5m8OI1 Fn?UZ*;}c7KORBzfXX۵l;> ?>g໰9ʹ+OmB[P[nڴC i@jiԈWagȚG6INy[dGvaq'(򡄛M8SCr4f>n`ϖ%4x!`۝oDi h!?x@Ӣ-,/,,%y3;3=T?~?cn0,ZNMkm9~Fkkm顅뜎{ 0Fk .v\JRV%H RrS`A/1j6,laŐp lkǻXԥ8\w1E0;H^h5z3Šv| ^V;_}?ssd!BۘjVv]DHFyw.Q?gq-!oR PWD)f[j2F$"0O3/H1;0Ft}]G~ͷŐ0_>={x{w}#ۏ܆mǓ Bp(Z cpoZğ+l;HSt=7bD@+K8QTc}ix"pVNհ^1$vyv& oB;B.#ˢRK>V[ys`qW;Ɓox/_wwXj'!_q/urQ0ZMnyeG ⦙ZG-ighms{^4!0,߱RP ّUXX-DxT %5܅K=REWYᩚ&cn%BQjʾe;]B!+?WhR2A|+Q`؁_othi[^7ӊl -Ao^\Ej,65qf}[W/'p"Rv\\CZCZCOÚUSd7b RJL5V>OBᤷNNIf}QE4h,H2J˧Y?? mѹ|9ar*/Nc(\Ō#t,on6(cqeM9)DZ2>Vi'_|űqiLd8SFۇ:fo 5"z0+1[LTnB^lln S7reOkHs%Ӧ˛"AV}EJ*K*C*5I$ϑ^`O2c+ J mB< <Ʋ>\@3Hw `bxPpxb&>܊3SWE ljoApq%P7wD#Œflqjل!Mq]VJDbB3QD`e$Gꬬ{c ))6棭*>KY;^]cY<qWؽ0A{v\dTCZb"3-f\gËA<ϊ"PoDJCC$Qk,S$q6@&TEhg_ArG.>tc 32і`]L eZq-̚fVeRZl 90r Xdy!^CMKU!h|xUɲؓ/ =,ǹxWP R)~9*{l-@F$XY1-H7g+R|EqÙ"PPE&wCZ":WC,>bP ͒Ɵ!NFEP~V z&imEhZ8 ^k|Mlk,I!%e'oht$cuOu*i eb:3[pi̞ j5V d!Lt@6ILe I*%2$:<XJp4x <N<ʲK {:柱` SqPLw}Sq?!먁;D|u*'cKc `m:~) F +a\Z``"k Y#TL\(4 X%7Jڧ!$S7 I[uKfd`D$)DA;:֕Z+NO8̃ϲ+StBDoŴ 1קx`f Li%;MT-;/ b@K:u5,W 9WrARo 2^bk3YaAi[V0hC_@7zXR#h/ȅ>2ep}4-02=;u4׀*A tɫ0gCI@,\^T304|$Q2%,DsqmQFn sOxpʪ,$8ȽmE0dDJV$I Z$ʲ!I/Ic,[ Nd1<ṗqdEQrr -T@1j'<h=)eLN$Ka'H>Ɠ.A4-^WJM-&{.:f A K@}ʼ㠴Wp 5D1 sZ#{oo-^9V8:C,)2 Cy(BEJuRHc)!ͱ d ';~aƻO\`F _=AVFR`%ڙ!I$՗h1RO3šܭ܎˄Biu\G #Q`l`lG` 99:~ 4!;x [Uxѹ'ZV&t`1ǘWh%zRvaeB `o' QKAZ|mKŀ&et8eŝ<,nZ^|a| \1e"*yqbFgbzgSv14bV50)4e^g./62eDq/e0/Y~OLC"nXѺAEynUyzꣁh v|ߢO S7K/hD0V*,QzvW}LNk\O`(;$4E)7^"#!/TZxbіm4*@c뺅r+ 7fR?KR4n7Hh ]~ TthN!;A.:+oy+;fSKpgq4+v]zt?pI$oծ ό쏸>taX`­ij ph4;fx,4fwF%+- +y@R @lh`,Z]%oz١N"r"XEߐTfaB6lVNҨFF镁 wNNjv1eyd>]^$ٶg[1jKye`U=g;W:D4Xr뉭.87~,?OM$h`([H#"x! щH֛%z8%"0iMb1^67pX\Ji ᬟ3|܍-;\.'*h|«к@t* Ddų'&8@ApH)g R Kv+ɊPad^dU5ʜ׈%N%SXUs^GF&ߗFf  Zg<(ԗ AG} grI rsIJ4q%^YaC4=I4"%L\_fq9J.B|NxxEFn@:" U{&0R˖KFBe pP@c$DCKZRqFdJZnHQ4;s14M8` p< _%J;ťy7s=&&vjIENDB`perfbook_html/img39.png0000644000175000017500000002024311672746041015232 0ustar paulmckpaulmckPNG  IHDRW cPLTE^GgggMMM;$''' /vtttZZZVVV @@@j444SUtRNS@fIDATx]*.&$pO3$yں_qN[  lhpE6Eo50H[~]B2?2q02"L]kgܪRvG wn5 )&p :P*}b#fFkEJU "vY.13gk{SĴ;Uz&j#,9w:YBxaB́m %E)Y5UI?:1h>w |92*`ݿhMBa^ k(nrgWO}Ȧp5 K@+Ȯ6JG?ڢp Q~iJqia\AP512~aB4;jygjlԬAUrjR awumRh=`֥_QON*[VڀV4FTTX"\#~֓`× v`V=zNaFU`q0IȺ(P+է5LM- NiaɹwR딙7 [lW'_IrCl3* [1ixL^Dn);Y'N0Ԛ0F? X5aaKQZ꯵;eF7a▱g{2ME]*O?-KoI%0؃ڣRFJLDݰvUhΒ>z-RCI t@n%Լs29zl@խ'{wtyQGG}v7Fεs8gm>;g/e4{P?VG<W;& CuUT5Q"ꄛ9,֣F0 ;uhD&)|mx0|x6% b+~|u)0Ԃ,EYE'^u% ϝ|!vP9AleO=sו8$?Yc&7aL&ٌ;3lD{]M@}z$~%:a37X#h9`~ ݒ!*3 &RJf VMP`yS]jl3Ti&eJexlp|z:$R]fp S JE*\C|FVo6=,s::[}gb{k1O -i5STo@V ! ,񩢫;!5pNxzYxF*`dI6}+'P`L[!Q[VE7 B*K6GqSAўOҡ` srKh&Y, d(cQɞhwj:EE̙ ݷFF49RDw# de+#d,cvO֗!0DKЁ{'f! ,*&0Y_[t4 &ZAbk-0T5#S4PtǶ +SMr[QM=`_g~[A,mؚkcU>8n hBKVK5+UZ[s-{ v]*;:i ;{h>;9dH'`(ౡXDMO YVQ_txN'(E3+! i bRa؂oMLٙAIvdcl:]G1M0gq xF9׋kF_B oǀLZ h$8_;ƸHlf#eѭw,J]3V%!%-)6*G yhYul9/].uNN[53+PͿݩ}!HMؖICo3,mA03`ZrgP &Bu\fE5lF4YMAXЫ5W5͂7|Vo{Qb0 k6r2\h:7Mk+&bQw=ѝmd}YWgc2|_gu0'G>sY˰f)Ax4EQ71X(PήOr$nI3,3KM:|4'$&9_$%'9 +z4;5o!6@$:k11Dl9A$TTI'}\'N.A?[ JJ!➟O-J֑7?{he:s Ԃpl0E7H_E>6a変xQ6YAx(ejww|M߹/Cj$ &z[#A/u!%k.hEH:[M2GE=C5U]=墽*LbM֟#OȼmZSH&i/-r BzHwrUrd\ 6Xv0&'x-Q ]]s]ިl?,zvJFc,vy|4t+yB):y ^BWceýW{p8_'R#>t^\G$q3J׿Kz.bVͱ+|&2Ί4]}opB f+*c=u@ ~1ôX3\(ȏVÀzk"Z+W{?8mn:srH&TML!s~q=,sh;J! h וQ[j3eʄk&LtSm$l[zr4h Kk:S\'6HEHF_+j$8<\U?a]9ՓlT=΍k5iVY%2{~Qq0ƨ߬ :s225n8;ZWBi7 ^أ@Yfne@pˀ7ف=b?ucK>roW@˝AtG:Jϕƣ;A6P~m¥y`ҜUqcM8MԴD6ŕp]BOse0: {ZdpaBV}l̶)w*6D({ʞ5r@[EP\EV:nB5?Fm43qe+%8\#۸%v?ЭD}I2U4Hn^TaOHc[iې\u0ic }KGA\ 3,>p+󒸃n24_g}?zZ/A>!2me:qU27e/rNY\ :1`+qUq1Ir4`_Bd.gK}#>{pJI1=uhwLSkIռ<5\-?M:i_,?>b?(YHykΕ9K1\7wqy+c.٧[lol UD[\Rg*!h>m}TiUa_n|\]p?kBL!snݳ^3)JN;N;+mFn('`{27W):x>k8d#mw,:Nxb>eƷW|\ UUrƧWDzS3jZk|\iV06>[\1;Rv8r~b99Ol'ymSwscpQV_uآӉ@` 5>n췌 1mɻn`3#E5 s5szUQC4n]:!Z(r}Mx-׷7'֥,c|g?w%p`̜Jޓ)z} x7ʦ; ȗM=23DJBNs|q80W*+.ltz7Tbdq>,s;5'U+Wt4qgԻgzCiL&3ZbϡB5*WU)SƉ+=G\Ge\:B!s.&z. ?wplHp'j&xş"ӫRZBi`}~;) wxhv43 MtSCw۝(xZK20:.G UԐNC*tl#NzOɓc!k}T5ze$ ^hoځ>EquAfzuE2=N=MH]d$ uB.I] 1}\40 PZҵ;s%:ҫ)`gL1z Ӡ^dazx#đSAqjEb^VI#ʕ@~oJIk%Q 2FE*?o^'5_V_]Lh)+/ 2/ǛY ,=H֫3)VS^)=Wѓrf6!"8cՀ#HGBQqϢ@+2%\E M\n[*]^)v[N?^āU 5xx6gѹ:1QGq۬:{!53,ز! _Vdf͢ч?̆ťGL ۬rn_jt{ϷzI|d*g6,.NbmVzU-"3d8=PE֗hG ,uaKħ$LfAc7 ^W ZN}qgkMwp?xK✩]fQV 6#%ƿFZ]'6ZA4 m`2 gb6FN =ʃyZSmr*\/]xk&9y^ 6zՎ 9Jw̄XROS>Վ3`]RRJ ; I OӉR7S+ z3w^VIT?Eߋ^D9M6 p\~^sNyoL!܄u-z GD!Juu.G(P4^wG[qԡa}bA 'l{qwXNq zMWІW`^S( S$||u)f)y?%WsX[rRF "*|*fІWp$ˤ:/@Gl+ v=h_!m7Lg^5CuASE \uڰ B\0_gac (f vg&wWyRئüAc0y* TdCz;I$+ze3s8 ;q5β.WքƷۯE@Q#WX}9yowqWץc>=O(K QЫ"XE Փ;'W#`]bU[5ȕ)fES~Slb0z(ϋcTV:m MӦ"m'f# 7ʏX a~Ś~ŚjUu^/> j7ЫIgu[5H QG^Wܔt{N80Qk._ڱY,2B)1gkX2 y>y <$2w}@_X l24+U WyyJ nrr^/]ˀ ˲eYu9D9/'a:H琼yiK4"^yƱ_rLJyE@";/L&.xyeP_WY9 >ыI9[G~>gbe^IJ>g 3:{~ \.k^)9uٿ!=WgFߚ~z \zY^EW/ n5MWLr ]W࢞W\z6zyFˈ[FtK2p٩)lҫ Wڵ+igG&nW3PcU]QuPLP vx GyWU}?Q5fꪪOZWh; ܖcW@N+B9|*E2,|{t\4TNX,yP2Ed4\ (Ejشo"eP[/xWRWd% zNT5 SYJ5zM N WGVd<;1 5YNt5k-ԕz}'<<7%!A~LS)͞ȨBIENDB`perfbook_html/node453.html0000644000175000017500000001436011672746163015653 0ustar paulmckpaulmck E.8.1 State Variables for Simplified Dynticks Interface


E.8.1 State Variables for Simplified Dynticks Interface

Figure: Variables for Simple Dynticks Interface
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct rcu_dynticks {
2 int dy...
...ks_snap;
10 int dynticks_nmi_snap;
11 ...
12 };\end{verbatim}
}\end{figure}

Figure [*] shows the new per-CPU state variables. These variables are grouped into structs to allow multiple independent RCU implementations (e.g., rcu and rcu_bh) to conveniently and efficiently share dynticks state. In what follows, they can be thought of as independent per-CPU variables.

The dynticks_nesting, dynticks, and dynticks_snap variables are for the irq code paths, and the dynticks_nmi and dynticks_nmi_snap variables are for the NMI code paths, although the NMI code path will also reference (but not modify) the dynticks_nesting variable. These variables are used as follows:

  • dynticks_nesting: This counts the number of reasons that the corresponding CPU should be monitored for RCU read-side critical sections. If the CPU is in dynticks-idle mode, then this counts the irq nesting level, otherwise it is one greater than the irq nesting level.
  • dynticks: This counter's value is even if the corresponding CPU is in dynticks-idle mode and there are no irq handlers currently running on that CPU, otherwise the counter's value is odd. In other words, if this counter's value is odd, then the corresponding CPU might be in an RCU read-side critical section.
  • dynticks_nmi: This counter's value is odd if the corresponding CPU is in an NMI handler, but only if the NMI arrived while this CPU was in dyntick-idle mode with no irq handlers running. Otherwise, the counter's value will be even.
  • dynticks_snap: This will be a snapshot of the dynticks counter, but only if the current RCU grace period has extended for too long a duration.
  • dynticks_nmi_snap: This will be a snapshot of the dynticks_nmi counter, but again only if the current RCU grace period has extended for too long a duration.

If both dynticks and dynticks_nmi have taken on an even value during a given time interval, then the corresponding CPU has passed through a quiescent state during that interval.

Quick Quiz E.19: But what happens if an NMI handler starts running before an irq handler completes, and if that NMI handler continues running until a second irq handler starts? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node257.html0000644000175000017500000001455311672746162015660 0ustar paulmckpaulmck 17.1.8 Reader-Writer Locking


17.1.8 Reader-Writer Locking

It is commonplace to read-acquire reader-writer locks while holding other locks, which just works, at least as long as the usual well-known software-engineering techniques are employed to avoid deadlock. Read-acquiring reader-writer locks from within RCU read-side critical sections also works, and doing so eases deadlock concerns because RCU read-side primitives cannot participated in lock-based deadlock cycles. But what happens when you attempt to read-acquire a reader-writer lock from within a transaction?

Unfortunately, the straightforward approach to read-acquiring the traditional counter-based reader-writer lock within a transaction defeats the purpose of the reader-writer lock. To see this, consider a pair of transactions concurrently attempting to read-acquire the same reader-writer lock. Because read-acquisition involves modifying the reader-writer lock's data structures, a conflict will result, which will roll back one of the two transactions. This behavior is completely inconsistent with the reader-writer lock's goal of allowing concurrent readers.

Here are some options available to TM:

  1. Use per-CPU or per-thread reader-writer locking [HW92], which allows a given CPU (or thread, respectively) to manipulate only local data when read-acquiring the lock. This would avoid the conflict between the two transactions concurrently read-acquiring the lock, permitting both to proceed, as intended. Unfortunately, (1) the write-acquisition overhead of per-CPU/thread locking can be extremely high, (2) the memory overhead of per-CPU/thread locking can be prohibitive, and (3) this transformation is available only when you have access to the source code in question. Other more-recent scalable reader-writer locks [LLO09] might avoid some or all of these problems.
  2. Use TM only ``in the small'' when introducing TM to lock-based programs, thereby avoiding read-acquiring reader-writer locks from within transactions.
  3. Set aside locking-based legacy systems entirely, re-implementing everything in terms of transactions. This approach has no shortage of advocates, but this requires that all the issues described in this series be resolved. During the time it takes to resolve these issues, competing synchronization mechanisms will of course also have the opportunity to improve.
  4. Use TM strictly as an optimization in lock-based systems, as was done by the TxLinux [RHP+07] group. This approach seems sound, but leaves the locking design constraints (such as the need to avoid deadlock) firmly in place. Furthermore, this approach can result in unnecessary transaction rollbacks when multiple transactions attempt to read-acquire the same lock.

Of course, there might well be other non-obvious issues surrounding combining TM with reader-writer locking, as there in fact were with exclusive locking.

Paul E. McKenney 2011-12-16
perfbook_html/node479.html0000644000175000017500000000551111672746164015662 0ustar paulmckpaulmck H. Credits


H. Credits



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node408.html0000644000175000017500000000535311672746163015655 0ustar paulmckpaulmck D.4.2.2.3 rcu_flipctr


D.4.2.2.3 rcu_flipctr

As noted earlier, the rcu_flipctr per-CPU array of counters contains the counter pairs that track outstanding RCU read-side critical sections. Any given counter in this array can go negative, for example, when a task is migrated to a different CPU in the middle of an RCU read-side critical section. However, the sum of the counters will still remain positive throughout the corresponding grace period, and will furthermore go to zero at the end of that grace period.



Paul E. McKenney 2011-12-16
perfbook_html/node68.html0000644000175000017500000001401411672746162015570 0ustar paulmckpaulmck 6.4.3 Signal-Theft Limit Counter Design

6.4.3 Signal-Theft Limit Counter Design

Figure: Signal-Theft State Machine
\resizebox{2in}{!}{\includegraphics{count/sig-theft}}

Figure [*] shows the state diagram. The state machine starts out in the IDLE state, and when add_count() or sub_count() find that the combination of the local thread's count and the global count cannot accommodate the request, the corresponding slowpath sets each thread's theft state to REQ (unless that thread has no count, in which case it transitions directly to READY). Only the slowpath, which holds the gblcnt_mutex lock, is permitted to transition from the IDLE state, as indicated by the green color. The slowpath then sends a signal to each thread, and the corresponding signal handler checks the corresponding thread's theft and counting variables. If the theft state is not REQ, then the signal handler is not permitted to change the state, and therefore simply returns. Otherwise, if the counting variable is set, indicating that the current thread's fastpath is in progress, the signal handler sets the theft state to ACK, otherwise to READY.

If the theft state is ACK, only the fastpath is permitted to change the theft state, as indicated by the blue color. When the fastpath completes, it sets the theft state to READY.

Once the slowpath sees a thread's theft state is READY, the slowpath is permitted to steal that thread's count. The slowpath then sets that thread's theft state to IDLE.

Quick Quiz 6.38: In Figure [*], why is the REQ theft state colored blue? End Quick Quiz

Quick Quiz 6.39: In Figure [*], what is the point of having separate REQ and ACK theft states? Why not simplify the state machine by collapsing them into a single state? Then whichever of the signal handler or the fastpath gets there first could set the state to READY. End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node325.html0000644000175000017500000001461711672746163015656 0ustar paulmckpaulmck C.9 Advice to Hardware Designers


C.9 Advice to Hardware Designers

There are any number of things that hardware designers can do to make the lives of software people difficult. Here is a list of a few such things that we have encountered in the past, presented here in the hope that it might help prevent future such problems:

  1. I/O devices that ignore cache coherence.

    This charming misfeature can result in DMAs from memory missing recent changes to the output buffer, or, just as bad, cause input buffers to be overwritten by the contents of CPU caches just after the DMA completes. To make your system work in face of such misbehavior, you must carefully flush the CPU caches of any location in any DMA buffer before presenting that buffer to the I/O device. And even then, you need to be very careful to avoid pointer bugs, as even a misplaced read to an input buffer can result in corrupting the data input!

  2. External busses that fail to transmit cache-coherence data.

    This is an even more painful variant of the above problem, but causes groups of devices--and even memory itself--to fail to respect cache coherence. It is my painful duty to inform you that as embedded systems move to multicore architectures, we will no doubt see a fair number of such problems arise. Hopefully these problems will clear up by the year 2015.

  3. Device interrupts that ignore cache coherence.

    This might sound innocent enough -- after all, interrupts aren't memory references, are they? But imagine a CPU with a split cache, one bank of which is extremely busy, therefore holding onto the last cacheline of the input buffer. If the corresponding I/O-complete interrupt reaches this CPU, then that CPU's memory reference to the last cache line of the buffer could return old data, again resulting in data corruption, but in a form that will be invisible in a later crash dump. By the time the system gets around to dumping the offending input buffer, the DMA will most likely have completed.

  4. Inter-processor interrupts (IPIs) that ignore cache coherence.

    This can be problematic if the IPI reaches its destination before all of the cache lines in the corresponding message buffer have been committed to memory.

  5. Context switches that get ahead of cache coherence.

    If memory accesses can complete too wildly out of order, then context switches can be quite harrowing. If the task flits from one CPU to another before all the memory accesses visible to the source CPU make it to the destination CPU, then the task could easily see the corresponding variables revert to prior values, which can fatally confuse most algorithms.

  6. Overly kind simulators and emulators.

    It is difficult to write simulators or emulators that force memory re-ordering, so software that runs just fine in these these environments can get a nasty surprise when it first runs on the real hardware. Unfortunately, it is still the rule that the hardware is more devious than are the simulators and emulators, but we hope that this situation changes.

Again, we encourage hardware designers to avoid these practices!

Paul E. McKenney 2011-12-16
perfbook_html/node232.html0000644000175000017500000000700211672746162015640 0ustar paulmckpaulmck 14.2.12.1.1 LOCK Followed by UNLOCK:

14.2.12.1.1 LOCK Followed by UNLOCK:

A LOCK followed by an UNLOCK may not be assumed to be full memory barrier because it is possible for an access preceding the LOCK to happen after the LOCK, and an access following the UNLOCK to happen before the UNLOCK, and the two accesses can themselves then cross. For example, the following:



  1 *A = a;
  2 LOCK
  3 UNLOCK
  4 *B = b;


might well execute in the following order:



  2 LOCK
  4 *B = b;
  1 *A = a;
  3 UNLOCK


Again, always remember that both LOCK and UNLOCK are permitted to let preceding operations ``bleed in'' to the critical section.

Quick Quiz 14.11: What sequence of LOCK-UNLOCK operations would act as a full memory barrier? End Quick Quiz

Quick Quiz 14.12: What (if any) CPUs have memory-barrier instructions from which these semi-permeable locking primitives might be constructed? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img61.png0000644000175000017500000001437611672746152015242 0ustar paulmckpaulmckPNG  IHDR>6tRNSىHIDATx]=lIvj" H1UkHʼ 眰er pt d`'K*Z'@T^^I șׯ+&` w.m8l%АW 0UR8B#HMmTz&?Ak̅"YJ=3n;'E8wUHp`~ܶ>>3q l86F/ |ks0=*gvOۈ T{3y*1sux2$=v_Gugj &3OdH.9AtlJR bPJU~eR0!Mcݪly%s;fR tST;!FaHq21)qt5bPU!kX )pTTڏ'TN:ɾ SJ]Zhx [^u +1ǖ+_6  ) -͌'2hZ]3^_p</H&gQR$%/ !}Vv$LFdXE.RuXLA6ݮLvcL=SJQvUlZZܨ)UB8xHtRq"U9<աD o4QX-n=ih(mZg,C\/P*K,ߚ^JA9<մ=sl8k&V6č6ڄ` ƏR4#nGFgjqX85^|-Lp L ٵLk-lx96P8—xjv$fHSP/\_vu_(@TLIj Gi h(4C30-єa0K?$S';zіe0IJ*P%w6d?ǎ!e5eW1~/pyca*KNaݡ63,9eE ; ;8;j'b`Ԙb0^ӆ\8tc`@s2*W]\?2Ȍj<1&T"ƔoV.:5hi9cLv(>|7 sS {".>:~3X} yixs}q^'W ?sh..I<~՚I8*k+]EPR1bdZ' R R\TF/J /o?YsJ'ƣm pfw,1%&b|1chGNXt/nV9%]̝;9>4lKm|-"ru|>^A,I0ŌNK YZN~< .˸Nyc68+@Px 9$x$ (Θ=&I&kOA \_~gΚoEδ,!p jB^j)*md7LD8 I& 쉃'oϷoD٢4 y&Zr8L/pLH,`\J#4sJamۛ.<OމB"]2ƙElG9+/.AB7Z op@J5Lp1*G\j)*LmM[wuӺM0nR T){k JpϵJSg0dt;|5vj";\r8onQ{ޣԺTgF ect>o(}hΐZeRD 3f`c&IEFDIqid,(O$IBo&sȖ)Mm>"Xc=h'C9J" _[_=iqG7N4L2PV0x vj1 O'T8Ns q"55cڔxrU/ Y[CZ}A L+^@ 4= _Ϟ؇1;w8xzZ@N~L8KRT:n Bp?#adJ~ 7pk b1{P4MVB8hѠ+_"w8//^&~98c{G9?~FZ0 C~6(ym l``!wx&xfg`.g/ΰKVyY|&׼vWff|cU>8@̔݌RJ ٧c'7n{ WF<[Xi)9o9 2?ϝk2S) K):S׺ S

$l!`|!/$_bfw6ApïSV&#Mvu ry׭sųAtRddk/o:![Wxx:%べ7B4I_cB-wBJWoo}C<"(Y|7H`-ߕDj,^{b{R7s&$asq87"2ܯI{;ׯ?>.O_ )S 's0 ,݌Xtj!{kC05AClŇO^-ぅ}lGX qd5mJf0ۀXXaB0`rv6/3,OO;=w}GCyNќCz ;J>ܲ!iPVgzNZ;6]} z4=wl>v3ٽ]*\3wH:;3{{wKGV{dIq>LIaf,W\zDQs1G;v>9G|+Mn7W33_]H3.(CN7S~זhSC1}WNs)*_%|c^گ3Y|x&+1Iؓz˖'Mi  $=C 2nylm7#wu{7c;r\wpb6n@{NL09H4>UYLџ(Z\J@9<]M: Nxc WOa_?=_?AvKf'\na'<؉u 2dV(;^@qv {K`')8o3@jt8vHPK{WA'8!LrTҪ=B,>^~܉tYG$&Mc-EfN"+f<w ǿ=w5OU@?)_/skE.Z970  ON=ږ&2z%NԻL i4¡?" YSvwRLٷ GY!BxƯܭ*-$OA]D3SN&7&,*um9RK Aj?j{'^L]N`cSK_JfDTۓKwZ wy[{rv>o;sBYέT!䧔P{yRrš4RȐ JZν!|/\c!-^;.x=̃-PyR<nIJg2vBT[T;E>|moœL&<6q>_*}D*p08'f?W_) 6.2.5 Discussion

6.2.5 Discussion

These two implementations show that it is possible to obtain uniprocessor performance for statistical counters, despite running on a parallel machine.

Quick Quiz 6.23: What fundamental difference is there between counting packets and counting the total number of bytes in the packets, given that the packets vary in size? End Quick Quiz

Quick Quiz 6.24: Given that the reader must sum all the threads' counters, this could take a long time given large numbers of threads. Is there any way that the increment operation can remain fast and scalable while allowing readers to also enjoy reasonable performance and scalability? End Quick Quiz

Given what has been presented in this section, you should now be able to answer the Quick Quiz about statistical counters for networking near the beginning of this chapter.



Paul E. McKenney 2011-12-16
perfbook_html/img222.png0000644000175000017500000000761011672746047015315 0ustar paulmckpaulmckPNG  IHDRBPLTEb``URSMJK# hffmkkXUV856iffKHHC@@wuv.*+,tRNS@fIDATx]ڦyծ6P3G0^̞֡VeGlW3}* H*UwW+Fe❾Tœ|+z Vo]~=;=}lQ18,{[s7Pze *"9'y<%Ԫ P5y4(镕anQ^+_ccQH)nLjl)gSM>.:"񳋕 <_E#*WӍ>1ϞRѬafw4j澶 cx`^Z7f75Wi9+-;;7G3~a{JܸHZ8,.{b! ǡ ɚo6nޟY4Z3Ҡ{TFLjcF+ZP "4ixRؠta?}p:*TCvSe낪 S!xMf4EmnuVUQ>r@H Yp^-r*< $ޒIb_i3KX~o6% $/MMM6r^S*J,/g?$f(w:N憁k k- :kv&Gn<,){e4woeF^u$SY F^MfTՇdh* KE"$j:*a'՝K)9蓰*P$ y݊@? (ih_1!;MW)cž~IXԚKS|*hvDyMyٜU%rMD#!Y^h殮ԥz^Kmӥ<;OjO$2@sxזn5#m%$JkTI\;5]L-Ikw[=ܽтFx=v%5΂4\CE'RӒ 'l-qU^C?^egUMǾ6 7DVH1P|Mb3KCe%۩ZrX+?BŻ@3\'Uq>:0rC ojYrE高75LX'A>QIa8ƶ2HӤY'`TF 2}|H w0> keQѠ/K)!=wۘ/]$@ o^qD.MHN#Scj%ZëxPk̵]4AbSK$@Pʞl[B'9M-!WL E0ϑqaCfγ7bqj8Y&_j(y,L c<&?Ar%ȎK E|qܒ5cMѨ5Hςu2>D,.?D:e>ܐkۄ6&{fut{(&?m']? +ŷk1R7&9@`~j&@DZ|fMZ04|+.QQRMX5aOVJ֒l_bvY*B^R|iE`s9 `ZlaRqcɬ -ج&Ň ;.)Dx%@ $C' m`;k/TC-qBiZ¯t蚮UnEw `sbyTF* Mnv5ً9N!$$0gq_C>g{QОTL ̺h°eu?Ns…ug&X8㏡ f}Y0 LyYݯHLc=ob;ʛM̿ 2o”z0pd ՝pI ~1 6 Hvl"O\)6tRNSىHjIDATx]r9=I8 ʨ5h3>~njh"D4MڭH4@lk4 'O^..& .$e6O'A.3AL~ H+ٜTBS ӻ|%z0;';MIM"_-8_#Hgz9^r&.m,g8pc\c3b`=$7u8[o?[k .HX_ M #&Ls>NLjMF HӨ6 JIP`"C dMٺoyl',M>q6=K$@ت;!0pc0Q q1h4)mC6jC;;H@oֆs"n*AsAίbJ'*MdPUIb^)+(at")*cL<\x32,SF8`?2 1vn`{F *f o*7YJâD GLTJoHaKS%_@Μk*1%R:}&CS O#F͕IF<&Gsizw<65N4‡OdJ2Q GC6YcXV*tU K4ʒEv++ 4Q\E2 ^+N Wcڄd_Ih -*n2T O %^05uj5}> 1_Gd .~63=\z8UUSȍ%N(ŕVX(M#%Hiݾ9BM^MR$/;`hj[rzUS5 RTkbv5.nQ4Un\Smh m@:z7vTO-~ Zqp=4Msk6ti%G?=!lzu2zx|hX~YD~K>Ms / HUИiO?"UoǪgTӝkta:,ąReƵÓ"WW:"Gq5"[OCM GgV#CXgYO#ˤt_&@G&{/t( #0\*xLcj k4ޭwC4iVNU37x/c&VEʛ0I(57nQ4/ 4fKu ^7X9XԹ76Δ@UCRcϩj;'BO$xx){s1=q i=[ PZ`(zԨžd;(;ؔY %Y\RJ)c:wӯksw)<f_˅q{:`ri9D6@/etyo,;|0(n]< _..{G*&;&3;<Ãw8^Iջ 4+'å]kG<|ʵ=R.0Ƅq QNlW5 fOs?"ٶ(P$#|ԯ, ˏ{F\yeZ:wj{.G=cԎ/|}/__K=sX!!UK?k$DT*C1 RLexH,SOSO2-"HQfEc“TQȐ(~Dҕ@mÐm"񌸏"* Ea17F)'=`1i KIrhdIRDfA74E!]# v z ! s &Ny&dA8p F-q0npRn.y)#?Ag|ׯpK觾:V%Qor,\1pjUk)2Y3 t͇X@pJFy%CDddFKXu5o'শeP%IX1I;?<[+v0 2M?%cەDJo-a@ +7bc@K*y㗔0=ݎ!VTĿA Y]8L/KU!fn52YW{T.wd<|ԯk<|[6oUxT*x^@7>=KUnyNG7Ѩ(tjO3e0?3Hx`o3C UM@0`U}b~(4C"ÌbDxx|1I)ET'5)ZYIRO")Bo Ȗ%Mm$X>b=Wa ډD[\(^=oDI~[<[ 'kD)g {K! rx؛ 8 7(_;CϾxĆp}g\ lGX2|_D5liҾlj?s2[IN/YStJfo~R5.#8v4^=>X~D&E} M%T7&KO1eBBgY'@0@:!_R%ɣ jrۻ0ݝnx-; X1/xΤ3ۧfE1T׸ل*)v`LXL*~gIy-Q煉 ֱ)7gVn@eQ`mREw+,.Tb=؁D孇 Ad<)<ҟ%9"+s`?w<0,)~aWF!t"I΍dlȼÜǔ#9/rE&v0" 29( US\>e+ i (8~S,T2q7T/m(sV"( s||4ڕZA[MpXX =!n5fSx?mJ V+w,-77; (c؞&v=wg:h!=| #[/lHفS煹_RAMORcwu]G^R*9sa!kl6!g D?[/PȖ?Uhv%cS; *v'_7Ý f*J2n 2tI;Ext-63M,i2e\l,-:ŮҴ xUi/XUQzju%k7١=1ם&\XJI+bGӘ`NPI^XIO)Z\Z@8-m9wlw`:M/o^-l)y<׿T.KY-jc6|mڎjNsm,5[IK˕2lK!C)(QվV}ᚻe[Uj#?2oUgUXfFvsZBz&3*U,]һQ)*TJ M%<YXJfQ *o'.#g`/;[`q:0IENDB`perfbook_html/img5.png0000644000175000017500000001131711672746144015151 0ustar paulmckpaulmckPNG  IHDR<#*0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fMIDATx]m$Gy~gvvfwvc%'٘3$? Nf_VqvF=L|s'%`+^Yցay|pȭ :֛l̥>za.G;UO=;= +ƅ9("2tbaDޞ$ @%HӁj(^8Ū/HSbN.щԉ RAԦ#.TBy5On Qu *4'mBG˺h#yU"E$^tsiڑD6eKZXHbeUZzT]"xADP$Qbi^!l"D/bPAdz~)L#5W$2y $RI JT)b$5#vDbX_5*Ib'Zװ#3j"5XYdKo&m/y y9>;^o+hRȝJ܅%>*RU[bUDI6ߴ~)nAf +H`ZynDJͭ"K}U頂-Y+#{DO蚧zycV#KVq4$Q?b܍ IB Q,i-Ր@YD۞9qݖ ckRн^H>e-kR`ߟے}k.]2'4njw^J:JO/^(yN)9tQڣ/jz֣ogG֏Tم|$ nd(ȄF/"ΖS'D'4,tUK\^:ROQcѴn1=ѣLzor=~CEFri98PzMbMC~Ջzj9_TsԈfTr}Fi.#.d_QlDMSB=ϤҜz9H@ӃؒzTC7ZhE4EZ u鼨?|^{K7E (&JcvͣPA\=78^/tM蹘ujC]YEB h=wMWh=x5R9s[ЎWWq^zv 1frc/REu(:~C{ Iת޲kp %Qqm88E={X<|񽧰SgU@8iMW"b"z=1ȡVKNAzLi*fDAW6b"3rĈx%y}2Oe= R:"Gfќ|`׊ߔvQ#6uxeM"f:e~P/_yՏ"7d䳯[e_%T _i^~oE4z{?rB'aB/rU_^j[ezP 'ڮ_ ^&믄U/MSΏ͙p&XjPW֪nc-?-1pgHL,.M5jM͉ܵԻ6ӢݪzZC̜xߵNy8=i kUŏG ̝5Μ䎲]C 7Kj{|VN}خhĩ2 k<:]w{F#zx`˽ lP 6 h+4+(3p T]HGyؽ;Q8 U*ڄ.]{Yva;=FLy;LƷƈr.d'mCut{I_rCš{D#CV9r3wU=5KpyEEO͂+L^hq|kdz)Si|Wڽ잚uhzggD6ӻ0jѿ/Z6 Z{7ץn :chw6КZv2U:ZعXVM)!~d@|Oz8jq!eF'Ts+S"S'B`n?|T"a /$ ʮ;&|uʟp,.9m4FyܡhkEP%#"i"w4}! ".5qt_G 鳬{S?VMz t;ڛvU+ar{iR8HcXWJ鹇V1Xe<i纚;d}W!Ĵ[97mC]4GDm>⢩`J{ئI)2-~?@b j$lg~ŅwsK1 V߻OKr!V꼱F<΃lߌe]8_Z "W6.t< 2~yڬ /؀Zݗ G,ǮEs.&;) -pG_cnxT6G"_G'#˫5>c ED㗟\Ef5kp:81)`@txBC/޸+isBNgHQ"Iq%&RO. ˏBB#&Cs+`j 32Q}WEnc66<6Zˍ*號5g!cc<7ֵ;OFpxs8_=T_ 0$FqIENDB`perfbook_html/node446.html0000644000175000017500000002612411672746163015656 0ustar paulmckpaulmck E.7.2.3 Validating Liveness


E.7.2.3 Validating Liveness

Although liveness can be difficult to prove, there is a simple trick that applies here. The first step is to make dyntick_nohz() indicate that it is done via a dyntick_nohz_done variable, as shown on line 27 of the following:

  1 proctype dyntick_nohz()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   bit old_gp_idle;
  6
  7   do
  8   :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;
  9   :: i < MAX_DYNTICK_LOOP_NOHZ ->
 10     tmp = dynticks_progress_counter;
 11     atomic {
 12       dynticks_progress_counter = tmp + 1;
 13       old_gp_idle = (grace_period_state == GP_IDLE);
 14       assert((dynticks_progress_counter & 1) == 1);
 15     }
 16     atomic {
 17       tmp = dynticks_progress_counter;
 18       assert(!old_gp_idle ||
 19              grace_period_state != GP_DONE);
 20     }
 21     atomic {
 22       dynticks_progress_counter = tmp + 1;
 23       assert((dynticks_progress_counter & 1) == 0);
 24     }
 25     i++;
 26   od;
 27   dyntick_nohz_done = 1;
 28 }

With this variable in place, we can add assertions to grace_period() to check for unnecessary blockage as follows:

  1 proctype grace_period()
  2 {
  3   byte curr;
  4   byte snap;
  5   bit shouldexit;
  6
  7   grace_period_state = GP_IDLE;
  8   atomic {
  9     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);
 10     shouldexit = 0;
 11     snap = dynticks_progress_counter;
 12     grace_period_state = GP_WAITING;
 13   }
 14   do
 15   :: 1 ->
 16     atomic {
 17       assert(!shouldexit);
 18       shouldexit = dyntick_nohz_done;
 19       curr = dynticks_progress_counter;
 20       if
 21       :: (curr == snap) && ((curr & 1) == 0) ->
 22         break;
 23       :: (curr - snap) > 2 || (snap & 1) == 0 ->
 24         break;
 25       :: else -> skip;
 26       fi;
 27     }
 28   od;
 29   grace_period_state = GP_DONE;
 30   grace_period_state = GP_IDLE;
 31   atomic {
 32     shouldexit = 0;
 33     snap = dynticks_progress_counter;
 34     grace_period_state = GP_WAITING;
 35   }
 36   do
 37   :: 1 ->
 38     atomic {
 39       assert(!shouldexit);
 40       shouldexit = dyntick_nohz_done;
 41       curr = dynticks_progress_counter;
 42       if
 43       :: (curr == snap) && ((curr & 1) == 0) ->
 44         break;
 45       :: (curr != snap) ->
 46         break;
 47       :: else -> skip;
 48       fi;
 49     }
 50   od;
 51   grace_period_state = GP_DONE;
 52 }

We have added the shouldexit variable on line 5, which we initialize to zero on line 10. Line 17 asserts that shouldexit is not set, while line 18 sets shouldexit to the dyntick_nohz_done variable maintained by dyntick_nohz(). This assertion will therefore trigger if we attempt to take more than one pass through the wait-for-counter-flip-acknowledgement loop after dyntick_nohz() has completed execution. After all, if dyntick_nohz() is done, then there cannot be any more state changes to force us out of the loop, so going through twice in this state means an infinite loop, which in turn means no end to the grace period.

Lines 32, 39, and 40 operate in a similar manner for the second (memory-barrier) loop.

However, running this model (dyntickRCU-base-sl-busted.spin) results in failure, as line 23 is checking that the wrong variable is even. Upon failure, spin writes out a ``trail'' file (dyntickRCU-base-sl-busted.spin.trail) file, which records the sequence of states that lead to the failure. Use the spin -t -p -g -l dyntickRCU-base-sl-busted.spin command to cause spin to retrace this sequence of state, printing the statements executed and the values of variables (dyntickRCU-base-sl-busted.spin.trail.txt). Note that the line numbers do not match the listing above due to the fact that spin takes both functions in a single file. However, the line numbers do match the full model (dyntickRCU-base-sl-busted.spin).

We see that the dyntick_nohz() process completed at step 34 (search for ``34:''), but that the grace_period() process nonetheless failed to exit the loop. The value of curr is 6 (see step 35) and that the value of snap is 5 (see step 17). Therefore the first condition on line 21 above does not hold because curr != snap, and the second condition on line 23 does not hold either because snap is odd and because curr is only one greater than snap.

So one of these two conditions has to be incorrect. Referring to the comment block in rcu_try_flip_waitack_needed() for the first condition:

If the CPU remained in dynticks mode for the entire time and didn't take any interrupts, NMIs, SMIs, or whatever, then it cannot be in the middle of an rcu_read_lock(), so the next rcu_read_lock() it executes must use the new value of the counter. So we can safely pretend that this CPU already acknowledged the counter.

The first condition does match this, because if curr == snap and if curr is even, then the corresponding CPU has been in dynticks-idle mode the entire time, as required. So let's look at the comment block for the second condition:

If the CPU passed through or entered a dynticks idle phase with no active irq handlers, then, as above, we can safely pretend that this CPU already acknowledged the counter.

The first part of the condition is correct, because if curr and snap differ by two, there will be at least one even number in between, corresponding to having passed completely through a dynticks-idle phase. However, the second part of the condition corresponds to having started in dynticks-idle mode, not having finished in this mode. We therefore need to be testing curr rather than snap for being an even number.

The corrected C code is as follows:

  1 static inline int
  2 rcu_try_flip_waitack_needed(int cpu)
  3 {
  4   long curr;
  5   long snap;
  6
  7   curr = per_cpu(dynticks_progress_counter, cpu);
  8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
  9   smp_mb();
 10   if ((curr == snap) && ((curr & 0x1) == 0))
 11     return 0;
 12   if ((curr - snap) > 2 || (curr & 0x1) == 0)
 13     return 0;
 14   return 1;
 15 }

Lines 10-13 can now be combined and simplified, resulting in the following. A similar simplification can be applied to rcu_try_flip_waitmb_needed.

  1 static inline int
  2 rcu_try_flip_waitack_needed(int cpu)
  3 {
  4   long curr;
  5   long snap;
  6
  7   curr = per_cpu(dynticks_progress_counter, cpu);
  8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
  9   smp_mb();
 10   if ((curr - snap) >= 2 || (curr & 0x1) == 0)
 11     return 0;
 12   return 1;
 13 }

Making the corresponding correction in the model (dyntickRCU-base-sl.spin) results in a correct verification with 661 states that passes without errors. However, it is worth noting that the first version of the liveness verification failed to catch this bug, due to a bug in the liveness verification itself. This liveness-verification bug was located by inserting an infinite loop in the grace_period() process, and noting that the liveness-verification code failed to detect this problem!

We have now successfully verified both safety and liveness conditions, but only for processes running and blocking. We also need to handle interrupts, a task taken up in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/perfbook_html.css0000644000175000017500000000210011672746164017137 0ustar paulmckpaulmck/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ .MATH { font-family: "Century Schoolbook", serif; } .MATH I { font-family: "Century Schoolbook", serif; font-style: italic } .BOLDMATH { font-family: "Century Schoolbook", serif; font-weight: bold } /* implement both fixed-size and relative sizes */ SMALL.XTINY { font-size : xx-small } SMALL.TINY { font-size : x-small } SMALL.SCRIPTSIZE { font-size : smaller } SMALL.FOOTNOTESIZE { font-size : small } SMALL.SMALL { } BIG.LARGE { } BIG.XLARGE { font-size : large } BIG.XXLARGE { font-size : x-large } BIG.HUGE { font-size : larger } BIG.XHUGE { font-size : xx-large } /* heading styles */ H1 { } H2 { } H3 { } H4 { } H5 { } /* mathematics styles */ DIV.displaymath { } /* math displays */ TD.eqno { } /* equation-number cells */ /* document-specific styles come next */ DIV.navigation { } DIV.em { } DIV.center { } DIV.quote { } PRE.preform { } SPAN.tt { } SPAN.textit { font-style: italic } SPAN.arabic { } SPAN.textbf { font-weight: bold } perfbook_html/node125.html0000644000175000017500000001773311672746162015655 0ustar paulmckpaulmck 10.3.1 RCU Fundamentals


10.3.1 RCU Fundamentals

Authors: Paul E. McKenney and Jonathan Walpole

Read-copy update (RCU) is a synchronization mechanism that was added to the Linux kernel in October of 2002. RCU achieves scalability improvements by allowing reads to occur concurrently with updates. In contrast with conventional locking primitives that ensure mutual exclusion among concurrent threads regardless of whether they be readers or updaters, or with reader-writer locks that allow concurrent reads but not in the presence of updates, RCU supports concurrency between a single updater and multiple readers. RCU ensures that reads are coherent by maintaining multiple versions of objects and ensuring that they are not freed up until all pre-existing read-side critical sections complete. RCU defines and uses efficient and scalable mechanisms for publishing and reading new versions of an object, and also for deferring the collection of old versions. These mechanisms distribute the work among read and update paths in such a way as to make read paths extremely fast. In some cases (non-preemptible kernels), RCU's read-side primitives have zero overhead.

Quick Quiz 10.6: But doesn't seqlock also permit readers and updaters to get work done concurrently? End Quick Quiz

This leads to the question ``what exactly is RCU?'', and perhaps also to the question ``how can RCU possibly work?'' (or, not infrequently, the assertion that RCU cannot possibly work). This document addresses these questions from a fundamental viewpoint; later installments look at them from usage and from API viewpoints. This last installment also includes a list of references.

RCU is made up of three fundamental mechanisms, the first being used for insertion, the second being used for deletion, and the third being used to allow readers to tolerate concurrent insertions and deletions. Section [*] describes the publish-subscribe mechanism used for insertion, Section [*] describes how waiting for pre-existing RCU readers enabled deletion, and Section [*] discusses how maintaining multiple versions of recently updated objects permits concurrent insertions and deletions. Finally, Section [*] summarizes RCU fundamentals.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node43.html0000644000175000017500000001026211672746161015561 0ustar paulmckpaulmck 5.2 POSIX Multiprocessing


5.2 POSIX Multiprocessing

This section scratches the surface of the POSIX environment, including pthreads [Ope97], as this environment is readily available and widely implemented. Section [*] provides a glimpse of the POSIX fork() and related primitives, Section [*] touches on thread creation and destruction, Section [*] gives a brief overview of POSIX locking, and, finally, Section [*] presents the analogous operations within the Linux kernel.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img3.png0000644000175000017500000013100311672746033015137 0ustar paulmckpaulmckPNG  IHDRE `tRNSىH IDATx콽.w8SK q<'%?ɤS5\'{&ćnwٻ)BZZZZ`SDBEFR>x(v^GK_kوщɜ,QI!)AR$(Aז`;fC($>Iv-~-~-ް RDn `xݶi@}]=XP !cOdˬLH_ ɸ\5⤨?rO/qfT2TTdط-+0_ɛфR]oAOs4U =O>m scf>A7@ma[׈!^8Q]BPDϠKfm,رa*!R|s@?ti[E?XѨ"::FHkf۟Z/\t_H{D/ڢihtݔF,??P}S{vڢfv$)cR!J_-B6&(,(|E,67b2BU) ў9CRd"T!%I<`vw >#U-X.6Խǫ*4RP"2 ϯ AI#J,$Bsl[ e$y%E۾!i %EE R %+}=vJc1~D kLC*jYS M5ecզGH[f$)eNɔܬ}> .2ϒ+b C,c0TTf\hN&^)3 {wv֢GD4v_# "PSB.)})ȶiY`K/[]YnD8pV#.}r|0b Iؖ?Aj0<ژ.<[yg =s=pi<{K?FAdH1ܐ)""mV7jGNݕah̠DZmߢs4e=jw&csdyOaT!]uT!g糐MR"G]w'?gҟAHmN@sG~_'&$$2c7ʗ,TqQЧlq|.0燓ci6* 3n"TF ύVkςGuQ ?|d𻊩+R?hҗ*I);X JƦ3$jl ! = R0d4V+H SM^XNյEKII 7"isb@gE0VD$. *VU}@C b_*=!sK?i:Y":҈;)HQUC9+Zp [tҽ9۹CYFwPM# >zn ]]?__z4/sy,8I|u.@@zp{#5 8ڠEv߯r~'9ȕ뿋G5h#v8yRc2Pq, ^ڙݲI]y$dh؟WWi1G}k_j\RH_3!* H*;\+*E֊91dAt5Z4"}6s>o)"*; |&S4R=3>X}ui|,̅YjQΖPABj~\JŷqOgQddNd d<\ 8&)>"rqѿYދ Roue)$0FnL̊_s|25Q~ۂd:[`d듁`jlUQ,}P%q+gIL.-⃺O?c/خKWn#Š-U.2TZ5+"ţtk-?hte ^k܉T"搴sߌY g cYHXK@zJS8{8إHw)4q:C'. ſG70{!ڞOiF@c7[o^+I9P̔U( tT 0\"QV5Qz#ݔMjirLc%ܣ3JU Sr`< >B(B}HfKuγ|κgIa9b2xvnTvMG;?$+3! $\ZP^L)4y[1>ԦȗYBRՌcJRHq)}2r׽f٣w)J Y2Tuh<%\$IJ%ZހOMjtDvQ D>Uie hm1R}X)S=4NUzn.M='$õ̼ъk˂rW$]ς`BJTB$4LH!TJYkjX)ǝug ޼?T} ĜDwk_J{t\ԮH!!kxFѨb(pG?ʗ.C$@  > UNT1 YR{Qw"r6D\VEu_ON$]5}W}`l+SDNt@eVm n4"hm"vV'[$c))J\ӆݻ_MdvHVEѪHRә { mI!|>3kxm.#nxlrkVf7f-qjfVqgh3/f9CGC̱?pNH#R j9iМWEBo])]i׾KfTz.:ފ0Fb?н fd@P >oc߮v3n"G{vilKyNm$,QcY,ښm{όaƮU- Z3_Iӻ&8w@cqNpާ'Aq4M5R;g3o3ub6H!AK)oiEŸo"J#]"peQZ]2LD(UwD 9{eҶFBmS nj@n~Fq$m|ԠEi=K*Qc@_Zg77hX{p X  *nv/T-60Iav s1mǓ`fDV3fkD,ޕ5JaUk J EXX!TT~AR9Eaͻ3*eм+}UW缅A~߹%0 U{̡{ud)65 4}4K Qx b-91M~I ]r*ɞ3DkpHU8"ULpO[_3I1"q_ &U?Xq?GI-[7:z]*y37c^x֪/K`X^^bxCh|+x#!dzzpD_k_8L19?}#>!M.UWxJ|σ! J% M: ~w?Ry xВ`AA,V1ǸvɖP'6EA譪Cgp5Q.+Iި'((@!7.i(} ~Kӎg$Ĵ.M9蛨.X0Ze`+C/㻽㇫) ~0:7]k՗Z%V} U_k՗Z%V} U@cl.#[6@4>Uv7cm UpOHu257>UUgbԠP=d@}h ̑n Lٝu2;<Ԁ0V4>=blv],:72X՟@Ç=(#DWR@Qe6@Jh 1mz5~0*2&B~DZl3e|8UBȘ EO*<0F]EtF*\]\:?a:`[_wC?:$-K`٪+|}@Q,w($=Fd# I=OOnd~A4kXzN}eE:Z&IG87Թ 4$)ʳAB1V&yS1/P5,s2E,ȖbKEiG&[υ/L>ŖN7JdktJDZCq:?hI}}Jw3} +YkcfYo2~W\A$alCLCIUa Xi9Nv8V֪/HL& lHMPuL3 fomNh6Mѹ$Iwk ;ȭ R1!|ŃeXt ߔc?#^]%V} YM]M v2ezM|m&P%Ǜ?Քyr܀4y@dY^Ȭ5QAkR1!!%XIYPefOɐE,UD5|zXdFUAotٔzU8[}ru BEDH@#lJl T;dl8EvSgJ#ҕ..~4W|=N}}B"5Z|dܑ_I9כ Ubhr$Y0+U ނ(d <ipyEyWJ,  T.r39ztܞ=˕3bHrPҦ"-J^"k<ӳ[1"9KT8AM_n='nz0~fy^jd8t:$W˶*eUJE"ǥۂE+33RHE\mTǨ *r T"2MtSE%R )ꌎbmv5EF^VUTnBҾ툯/FwQx>@'^l#45(W.xϕ6ya=wS=3|O7 "e01piʉ#W>t}HjEJI 1J*X.AcDY@(G~ kdT>",+ST2 !cî$X/KV?U0/}:yS <)yG.cE楴`ޒgJ2{9IfT~ qe<B^eIJ13j]<%s|}!=űoW]R%BJ&d*+Qծ98,sZ1Ë UQ s}kL0CTgJzS8Ydb)t B^|-QL]ǐ&U6.4/hț4cRTJ J8UZg/>,XRVH27DM )'ѷVHRV~A`Md|"OhF A5:̩2YGH.2ώ;I}Fn]4zs'w6[- I"l%lǢUzHlGlB;] [AW-'cHO v  ~ШD=,M;sը*9.wzuMQ zq1p#P78bh ?U!=uP* #~ |AHj4۹'=Gpq[{W|ދ( 3gQ䲑?d~:֙1V $B\|c0 $2&_%[֌a1(y[B!K%2gaKIӿ I UU)vnUwa-> =$}"U>+~Ѩ䛋3/drԔ/=J3&P !x>BG}}(h#st&r&hy[ggXS .}&/2SƔe\0YĂE\XJIJbd_Pfa{&9㞏k.ȴS7;j9L?Ymos>"9#_ x,Ϸ5LH@t P SR1t] tX_F|l/d>no+gxn L] ´=MP U &d7\H$ʰr[U!&`O5JL_=GxZ>I6 7(E^S_Dd؏ñ#H# `ܼOd+EHi9^Z2ck>.sO8'6L 2RjHW@\[P4ȃyh?>C!Ky>~/>N!洼3@?~UR̸  <͟CCWP6 < E5h\ fTژ*e,]RQEd0W_M/o\M0?V낀];5F34'v+nd}T xrn|BOڝl IDAT[/K`ѪgTo~v# (20C%B<~m{T$HА^d$Pگ!̥o#2B9Go2)@灈4l:  |ڵmGomcH=i`ژ Š X}(KL5x(~lwGV|/yaR} T_+՗J%R} T_+՗J%R} T_w#*w>y8y٩7Hƛ{]aT?o9 Ahu'"^g/[)'(HJsefi%JJh0|aN"+w҇qLcb)k! XoC:eOM\O@K&kHkK4qJW${j$CH07!G~\j`^VFYmE [nO)*GԔ&=Ic  @|a1Z%\'B&2!Id =op(ѯ-$CgqR§44LFT)>. }%JN<|\0vΤpVWf ໶,ȁoXe?$Gzt lX9h-Hr`# Sx~zF[9^;-sy@?6MVcz4_N%R} T_+՗J%R} T_+՗J%R} T_+՗J%R} T_oG;\ͼ. >>- tJ6GZv/G7ܴG`3@wy >ƚ)պqyHۖj~f`"i.Gi8h)* Js4DktR պGhZ78 ~ Q35WCM7k,KՎ'*G*'5 !ˇ&&Qx sQGn&FT}`Mq5*!!#=V}MBJf cgtU,B$Je2($%`l,1%lgT*g˲RY % xD`f3c7:b ]sY 2ҧ 5iU[RQP0WuHd$}V!YQ6+R&l%3 W"}Q$)[|Th m4=]KLbݨH#8<>nTo=4rdr5'઎`+zĠOa^+՗J%T?$EF tkRiՍe7rϠ-6n9=.y}XmJbHŀ5Up-w}!cWmM3feb5)$(UǷ-Ye<{lsLЯi:nsW?`X +G`D|m¾i2ڀ{ny,h%ǣ}n|Fo1WBwYYb/z743KC߰׳|mL}-EtxbRFONA30 FHA;Nڧ{"`S@=q wH@je5L?GlaJgcF H4T~|RY,o,*ZyEƤ"Xʘ e*`(I s,2U@+fK0$*IJQ"˰75Tt񦭮%Cd֍E̐dˌd̉kz+F|GI2xcX7+@ ` i%VPAGHl:h3:$cVY J9?*ᖼ;d^g”Sp]<8TӷϬVf T_J# sT#9[KpԳy(q4:!|N;m4Am' ߰l@lmmHmzFab Sȝָ=՝vrߨGB*N7ؗۚm}#ͱJK8+`Xރ꩓uѵg}o! Us 9>8ctNG)ҙ3ھaEXPˀ F^c¨fI ҙXȀ2J*nULѹ6$̘še[  iBט$-O*czAS)m`X -$3[T#F1p)%C6:hR934m$ shb(.>r5N]'[熑r /Ña>Z1s R-Couzr,g-%eOEIqƒ`ƚ;vGX2*I_1cKJ&TA^SFk6iv:潫\,'kY{1!Ӳw6Y+s *b-FQcy0B%¨JB{չAǼN~%0/k48v8> 9AUxveuI ;~, ,XC`FY9\.<[,&WǕ+ '>.rE/Л*.ZekE,{YE|)2, &s6fޒ4>ʧy,]/ssK>Ǝy y\p]^_G%pu4lN<<66Xٟ;"x7B8 [DnYHp/omD;+vl<]lP>CW۫ƅ{q"JߤkΘRPC`[0mʧ&e0cl'BT>}KdYdʯ)U˶`aHKRgYʗ؅{ah6 SxS')y AfWd!a5weRCAfZvOiau_*Xg% H#9f{0c`6)2K jBȶR%K hbBoc3@* VB)ŒQmGudt9%TUEsoU΋\S2q::a BK(gwvlGi%{*Hٷd*R?+*)hIKaG.>^.ß;Wx]:(nXAa^WLPfV 7ד~dI0F/u4VV/:*t9s`IQ 2sa Mܢz<`R85O\c,:F Wh 9C {J4b)PVIOLh͐(i>Te!e!)̆se!/ s4z4iFXN( ͅr-J7 }ڢBE_e)f*h,:\|ѶCdQJ3g[h>+>**eЅ@ cs >t5 w@3tAou@5`a? qXȑNx5yM>0xF,eq_~|bŒT-M[h>㯡֣wp)'uGKZ Cef%]HȄ )[fDѹF4n-)uy Uf 㔙/=*Mf<7vz ̜kdNJEe|uaϪ dXײP,Ί*T vz|rj,ds2Lv%:U/4'QH??5?OJS =EvWT) Cflzk8;qR]q D*I:jFc0{zl5Ξ]^m蓽n#(ڠϑpEyyH.Gz5y/B#rXV/E=G 774vȊ\YA2lT%y-U3Q(sgYP]&{{|G74 dK ymЅ`]gw_n e<5DM^<5={L|ꊢm wd u,jGZU*-,mb؂pHcO2Yj._=o*ţ5\b%-dѝ0 cPqe=G13vA3z@-"cR匝0ERTЈpRoxGP B#ZG‹ѫ,k/1L @debEpqa"Bx ܾP [RLJ,2c)%p,Ǚl_@^~ Lv{in4 0\,YFmwXm)R1{ȷ6_wm$p>6-ų=KcP,et6pE mb=`;Y98xe= eFJ_;P-HF/C9(;?g`n2`s󬸏fIXK07ALCL#˛yrY+˷!'(Ja2QV@ _\Q JG MU(Y=Kcx\,d6,Ջ^hCS~k칌LHBRwt6Xy| KGo`>PhIR53[jh u,AT*g 2w=($[dˀb\dGrh̒e~6Y {IME1YƲwu,A6Pb`ÒT9% J\ᯍHL+gI], C)p}szhgz~k`RD+&3y0xRw8`=4N  ƇiZ| 1Ӯ[;"lC@ 7"PhtvﴁprD> @$Kj ED5}kǸd!(Zc r9ݪ|eHm8)@_%$}#հfB &t{{&-IRpUۚypG.-炭\aT'o,R|G\v7BħW׍(}}Ԉ-}:-vXf%F8CDV:ӍsI7RkNd@Us3ݡ?]B846cX\^"8Oqz7x%ߴy(է[\,؟Zpj엔M_sW9?y=a>ϼpؙku hۣB&=()w8"uӯiהѵSW/Cu*8t?j`#-j)jhֈmGz 4SR+OSP݅HMSJRYEڵz* ӅjNu{Xhkl](OE||aȷH^Zf/36l6{0vwW|DSܡ_|Q.5ĸb0&}o (u,1lg>,$eJ8AҖ0V0%`fT$b+&J}FuAuY^2ÙHެeP.fiԥ2)ziGbfKQbk$Cn,H|b8cy-qSxO!j|nchlriHG(m=F!k48];Ӹ,o8esy/JTIkѤh9_-Śq~} T_+՗J%R} .uu'ۥ1{{t+҆!xp:@&^RXǞ!?V|ZD74 =J'qtbS+&]GhC]3% ?>&]byE@y#S!EgD.ȋ9s[ouclCjI1AH,QTKr]DOh(*$)Q:c~3ACp?( ?ij`|u4wBBO06qaO6z{[/nB+]t?t w QC ׏ e Cb!*Lr쪍}}6$%J@PDW$^Aت^>6o+=RuU/Dֹs W^J}D_+J}D_+J}D_+J}D_+J}D_+J-Gϋ =}H\Nj5ٻkѧ>@(8]߀[L\A,ҨĸέP߇Oý5F8DI2+}CkW 2$))uٷ,=K\I aQaK\@6h#l4Bc 'Q `$>`)"l't |\[4 zi t-G.۷,  Yڛ|htOt"F IDAT<<#G:A(l@'@syRނURш :@%@hр0[:'߮@+#t t1@FO>]ۛ =mL>vխl z|xRBhEՎok ~GkK-x_@*t>N^^ON>EM{A] (3;@ہg^Vܻ0dCLzlOi )=Tg#F*jkb{Jwaԑ)6-iZ=9JST#;lm};E7sd} (C`Z"(B ,ؖh,됒%3RµVʰe}Ap rCʌ}țt8S~ ىOutͱ} bA]!6Nk!CLd>R;)ݮTMldvS 2LğHj?TTMP%2q4&,>h4Zk|sSi>AڇN-AIWNC%@#*1;q:.7Hg~ F 0O6H ?KWhw軵t R٭UG8/ypoGtհTZE2دT!m3_KFpZ{?l+J}D_+JnDyЏ? ނ'`='`?n;xf=aTԉhldNg4 Mba:(G/J? EnM$cnk ޶6 启!ҐmP%kK笏,gTd€5& Qw5)&Fó&0.;& cdY 2ɱB4[@j?!@ , 6@t!fg8_ tHNγXG`KlO04jc|eKR2SY2T1"k,V~͸`Yd I+"/e*i&GDfV|`c%XV/ 58>8wP6ނn 57 S9DhU@lr2{l4yfv̠!6x1M^ش ɖrWfVꋽ+\%o橰5Ngh !C`{~L7o\.eRحt;"޾~wla5)󉹑#@HIyʖPD$HV)"DD(~@DĨn I ̐LJ7NaR$ږ8 W*<bjKĎ0/jbY%E- ?GL|8I9:=VOx{ Es/)6i=c7z?&} 6ǣٗ{Wx>fبYٖ9tǦF5S#Y`҆@jh묱SC-t2d&$cu%O:l:$Hr,Sf36c[M{apZ֊)GHF8tǦFBzF앶F`/&8kldGio|M1'?[P et/{K OOyc6McTL*M[ JHi[@ͦd$922&dj8/[Z0.xQԚg5uzF?ŏㄩOeGkltlcicŠ&z/@ t :~NB?;tz8{{6B hP^^Գ {t+wXKC rXA<̈́&+b)v/EyRڮ؁'vmE kXb 5{JG"8._>z%[7@Xo7@ t :xN^z|N;t _ڙGVs޸~+޻dz*<8%1Σ> |ͽCk$e(%$CCokΣ |Hz!q>bD5ڹkȁV>:=@bhΣIc;ki:qկVwe-ژ2t>cw|@ GJ?ػ\Icggי9uhogbcH\7g>`vj[YYIy/##4!-g[6ְ!oeJ%?vo)w7@ t :~ND~ѝlZpoc6cdc7=d`)p ɦ,8b}-1w,NDD$HPS̶vDI: (B:"*3Bl)?BfSITBHe)m5($AIRniFqђ̈,$^H+FQρB!$ *kw,E>r@IJRõ%AQDʓ s _bLɸj9076 [f,C^bW]Ofa!B\H=ts ̯dq:`dr`PP:D"ux -EɍisJYbKJ6M E22XʘHyLmQ\Yb?mD F>y~]%.),804 Tɷn 50۩>$&cfJQA,H"dړOtivXע-%k|D!c2oso/D$$)Ak$v;]x&If jhvۘD3R%iJp h ULn#/ݚNw{RRYHJdwe43;B [RK<.8nMH/I]TsmK`a[MPr@/p>D8fq~DMm$mIt$QJLf OtVTQw:݀H̆:~_&CmD:+;-ܬIUhBJ$Ml{ 7UT.ish4*]ʬK#-:١j]j&աi] 6\5~u}@uaϋ̥~z4O/0̞Mi5\=3PL~g_k.ӿt)c~2h7VIN]]M+G{Kv~RH}!ż!vͣc:+R9ȷ+OLz;dkK^CwXC4j@:cab%O:a5f.OCׇi=<e#:1auajE!n#Hڥ AC"2$nט ֖FD8}—n IO6]>5aNۘ3eGCL_noQ!<6&?bT(ŬqY&RM[PYDDYRƊDqA$YH(J0](3jbì(H(HFu-0qlUɅ#Sl;I{S9Wiŝa[K`iޯ(" ^=+513,,~,kXG> X@=Y@=r{ PL5%:;VcxC{tVdu̕0oZYA\mlwͤ$Qf "9h2}=HW$^h Лd=4{V#=3&x5zP)*kاHkP2ʋ`D몓n}:6սImؘOÿm{eR# fR!/K%&D)Bq0v\ܚf(">VbO5o;{&SQ gp AuaAVa޾™Ci{ftj?9}<,N~V@mA4zi7=3)ki$Tj5!E+FLEu36McHZ?3E1ED*M6McMF(Z|PSKqu?gr|PQ2*j縨>lգǺu93q`mn苴8W y:=HoY}-NC+`gA4~<-C0$n ҟ> T `*wn*m;UNz[4ꊈ2%l $Z E%+y|KdC2Sa {g0wQ=ѝ˔I  \v<;yx fL :B=x5ov'Zkʓ]uHvX'`o ^McK4а? ^o>R9H:WmAj<^iz/ '0)GwwՍ˱fu3:AݰnXgcRM֤noL4 ""Y ZNNn?Ib5ɢhp`B4s|(-R1xrF+<ި-GsxQ]BL꾀>J$=.Hǒ|w9a܏cx蛗ȣ[׀סx#EVפ~6sK藻G;zo6N`檡+Tx1gӤ ߰1{kˊZ]}_1wc7CLf_珶k#ψӈ ]D.S*mJE^-)j S4!wa~n\bԒ EbEqdHPPe$"tK[SFjb6\NRMVK7{bIm|?=,n{X=Bo7@ t :۫&I '~l،u`fKeHz=!2!4Xg(;rK ؕO9OoQίG[?#9ӯD{7B)\[  ΒD=|'JKf(&vlWwni@.$gi \@#৭W뮁~7h&Ң":Q up%x xEWٝfM[C$݈g~y/ :-&5>H6fRZfuRyrXdzZ[8NT HĈ"uRRU9yRC\ROK#p7R֔qPĨnNGi^ mGdň$Q4t#<11`*ޏzZR}x.4-oO朅|p% %V:}lf@ZzX!뵾0Y% LMӇ.]O>,.y3\ wyrr"B_ha$Slsd:rNkLI/ya7\yR$Vqv`wښ6{|)zʟ9y@f=rDY+"Dr^Z.>1|WDnQRJ$#$,9w`̟; @Z{؞Ӟ{d{WtA|dѭMgxʟ;y@)r䖵iSbU4.\ѲHi[l/1MIEs#VH',=7]+Jl4IYli?u᎗ca=Zkck۸>>Kq+8[>YnClMXn_M}qlH$NFʒSMN- Ej*lTD6"rvtskwŬV-f*K2'Xq SM KHX]z+*4r\lF2OR؟D`@g:|}$/[`6]TzozG.a篖Q^cEtY;֛\:EB|7ve Gԏ*B,Hle# niMap=0 >\9~!2\6O7;#ĊS t>^ C΢z 6гlzR<{|E'la^/Rs-f1Z|kY$+Rh=Na*^O^!JJ kOiY$OD M <3:yBc|WAD]_T@K bYJyH*R𝾈ۚJtZ'dۖΛqRPM)qB*NIBK75> KϖN]nN+XQ" *}@ TDIv~0fv;kwHkk3 {M`剝~:w٦N\qȾ7Tb&]7D[kfg5"cj e7 *I6PCQy'ɼ_ b|Iγ55/糸e{b_gQK193asKHƭ9^YDDIň)ʶ jJflS;.Ol?Ju)?:BS*1f^.QKzuk<k IDATZ3͔^z"_^t' Wh.ʢ_r{Vo J?i\QǎHi*=‹Ftj;\Yk?5:1MjxV0J6IGGkėh+>~A5+sd|3EZ=d_cJ4 n[Y]l82M]{~GZ>(M斣.wqq-A/#|%--pi [r\"1\0hҤ<8{s(r\ܶʅ!.Ⅶ--䍌f*M^\ mV,\8:)GWPL?fVYǘ)ef w0e}$r-̟fN#n "CX;L\B9o֞bLQ2p\sqGXx#f Rv݅0zn)3EmF% %K[ \vr{v/Zx <R Aez}m'nO'A5QL RځIPbɒQlj,lkR[9Ɗ4Kt'WO/a 3LxR@ڧgܜ(ԣ=)#:Xtَzo4Cn-.XEJ70730{yZT~(dp)/[GTn"".#EnJeilT4yE$mZAZ)"HYc;5*5٦Di*ΦOQ; 6|vӴ7dfAYJ NJ, {n97A4Q?H`MxߚcUS,L2Y0BrPP)q!r|2V3 LLԵ 1W.4QĥqKw٘:Kz'$Δǂa(^m)>$S6TwX' *sRu^  6ԻK#G55L/c#dD\zÅřX0zv ;S$,ׅrCknTI{ݐl*ܛR\ov(ԈÆ23>1۱H1A`^9B\Bi;3`b&Ɣb4Y%S-E*H- %HFRPBRz4xzd:^ǧcL)+ ާypb;#~_3৳ir3SqAīȈijwy /zO7PP!GsWPNrT.c߲_m.tv$} %0a4_yOZ<+ydȿ4kqljxa2Wr@hXąyhꋞ;FW_?wiD<, oNvk }F)̝f CTxdέ(y@ 窿~[C9̺g:ڰ `iUD}k/ҵ)GWZLDT+HL(qj@RYcJ)HRʶؼ䱀w)(OfaVq9R`}Zh/_%"j;:ccf'- eM s\? "BЯ0D`\eFpbh aCHLOc8v)? ȡp[;#Kw~s ]}I~aw,`#Z+Ddr `,R`wo!61H;D8mUd^|%\y',HRtA>ƛHVK8_ R9wvrӵFs_@S-""r"%X&g;jA\..j>d@\M6LH[4;ZE_T?xktn// ">I ^߮iO{d&GOMǥ))IF;5}@펖 4H^%f ݞ[K: .͜"!Q)Ȉ%! C*l4Am×R*-eBت1kXTs.8 2-N3`jL'Fb)ȒG\Ⱦ*mT!;&)l|"bvX:՗tuPu TGMv܎DR"6=s\USW٠yQC+Δyd!.c(:׋S. 2<'Fgc:@np -σ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<r#{]"f]mW%r19\ɹDWb|ݩzWǪZWlkj> BWoU$|-XɳAp+@/wŭD0Ksj"D*BP'!4Iwڿe# zmAn#wг[HD)}t)!T'L#Tߢ]/O2: L`+:$WQlCӚ"Ђ(f0rlorZwn`Nww]a&O^EUkHM$ YBTEQ) %ڨHILR,ͱd7oOhTdkɘIɚZTƩfk2ՋBQqT3YD$E%"Dlt246sy*bqCI5%QT iׄxOfOH#H!Χ:_AaEHVw6>W-NN_ZiUvwI=6S;XFRKcq ] t',˜~/a5FY6@@нt@ oޛ1b xXR65}o޻QK_kKd>EeUJ6x%Z{'aLkpd8Ѡ7 ;(l;=98KRD-8[ xz.KOa$܁DĜL,\Shu:ٕ:vGirպ;LpP "me5Qk_jM3 W)k@BQ_Ch+|Ӑ´okͨw5Q LփDuڨ-ܫvD"I{TDDuIDTH"j㌈T>Ӕ^!dr1Eߦ1)V\4+ k:z5Q;jbǨ~CUO yCS#Z4mܽI@{ xIcd$DM T$0פ]C]ʈE)N9=/7ekUB3*o=;թ'] wn^KC $IDSq^I}`Q1?Ɨ?'=y6q!@ҌD/jy~ C6I-d9˜EpLkۗ 1=9@@@@@@@{4z/'¿0. g@nzF|C8C0Btny;fgր+0ON?/.$K4/\kȋfG\v@l) Eyu[<< @|h[ǵs=OF-ƪ}m 9Sɦu:R{6X/G¿ >J~, KgQjsenB`z&շ"-=0t@TQ$_L թ/G¿2K{W`űmso(6t;lB`1lpu;0t,]{? d_H6y{G(;~?r?:މ䷑`t;Kk&tRS ֺC4u~o|h@?{ONqs8>x?e/~ߗkß?~N2{0z?^Nn9ކ$Y? ψ; s:t)twAAG5_|9Sǁhn,T-',Fkȿ`wߤ 뉟]nZdZΔ3ǡpM7zof.`-կX6<MW`YEy~!3Xn郤 r-,lDl9e2 ;зvv9?՘r_ |8 [F[\3[e)h˱-ӈ-Zfag/[ 1o&"` ;jf5BCy΀ka!vI]1i-׉۲LiĖZ&ZFagLXx1oZ&2"m%F DDe33y_Or,`˛+Z>X6q t%~΀Prө[e7I::/MV?20!⣏Gx+a*nnUs`(3ZkQ*Uw# xQs Hzs Hzs Hzs Hzs Hzs HK~ok6+̸br { t$IϻSyi`ZpHᨵ[W@s=R|Zx~H&Qu`=5(}tO3&Jn0juhiҒ%YQ&#{IR@4 SЇ&A|LfΏ2--R7F؍ѝ"RȒh}C`Md2X9Z`8%auDm؄f@,4<ƙ2vI4Q`6Kl͈ -"Iꩄ|mj6J--0>Y+gܳ yd!1DylN%aٍ]"LjH[(}zz)ſ7}D9OJєk{N#~lB;LFot:cꩈ.e4G,'}d7 F Gs=zw3x9EFAҟwp4GIxQ4'9 8|f#Gl1ZF}s(Vh8N$Gaq=4}.ѩ.b5.ޔoc5P^HjbBi4;;u@l4mEZ7F3VFsNDa61Z7yFsVFsNL-p7 5lgh.f5rF FHfFҨ7wp'Q5>чY&F9f%ثa?턀nU";Ϋ8N4TjCAa%9$=9$=9$=9$=9$=9$=9Pm^k2 Դ_am5?8hlHV/|/HIxϥcdDL?DE)!j$2TF[&2e%C4CyLex;:Ȑe"~P2brjp8[o|O X<(9$=9$=9$=9$=9$=9$=9aju8*݂$B.2>ςL̒6y<$|!7a4;C 8پ|I0[+iL$dX#w$ S.f 6ds9 =zB.'rt]WV}KǫX'Lu{|򭘆.7Il!0k;7 IDAT9Ty%8mMS,RQwez,G "QWT㰤5eDPJ⩢BJIDDMaGAwvaL{urȣУl:K:!GgP~+;Nj̛54.CQ_PVh?X fxw߻&#uABMXPuןɿwp.FuGPǒ(U?k /__V{f]w4ۿGLR5oت;;wވ`0(УBΣ&|_cqvI \u(.=x;<49$=9$=9$=9$=9$=9$Iph&%)I$շ:e|{UZ4Id1>v|@ ^4 [l:P6VvI06Opx"UJz|k򙶛!0,R/waڎ#H SfM?aq!3ja'3 Ѥ^(sv‘,L+KWfih,Cn Nu#w܅Y;ގOzwAUJɱE]g[;qQQ Ѳ]j?M9|̓L*"LVx%IDLT_Đ_3cJ-#ʴ]ѸD(Λ0;KӬ[~^c]뷻CDBUmyW-98q{ĭצg@//_=x9.uq~CU t;[a68gF^ 6~ڤQk`?.x©v\/8x?JFo ʈ$\Z u,{_ xn-AQ\桤.BTOjKr-Z>ЎurG"J{uvHuُ;G?; ρXh$k<(K1\/[qbFuRmfcly5s Fƣz}$MQ/5l<}]^5<:LTX4MP}sԷA3U+XJE-,OSˊa?-ԟ IYS\i-dfgڷ'J_ BJ) )UjT'iy:t֯-oH][v(+*5n)ӃqVu[U;I/8lE5et &'J" W(MӔ3Č't)Ξ33˴ppk:5 LK}sT 7nuMHgv}޴nߞ;&g!XgVi& ^،D]϶K4ż@"Px8dȴyal8xuoZdG%yp S$zsQ:K\$iUken><0r%f74Iּ04Oop98޾nS[Y;ގ=Y]ӒY:JPz8;|^dr)AߢiI #p J^Ie쎖V?03$i[8fڷ蜍Q+uAϏ ےh.bq\A1]UӸ<_ePM%\ Haz>Niẉ"${e\*`dc~N,&g-^Kd\_kFĪW榧|.#1LA7R>rDXؙ^_(wcLeU9)6-^.*IͶ^:y ?SW=Zij탏ASo[E7 ~:1*p'D}X'm)7xt7#i#SD|WްIS Mc_Wl#ի+\~TL N֥ܰrCԷusmqIhzÍb6 z ɀMu8*.sic=dROsLȥfNoM-GR3?b ǰv/Ņ8δwZϞv&g pjwK"E6!sx|4)R'L9&x6%,؈qi=9<)ui^u[Q?\j^:apEIm–6`Dp7SVzџftȣը+*qR)AC19y>(-f_c=sݍ1> /q,n[N3x1Q5{f^2V6f/^3oJU@҈H)y>cuEPۡJv>W8j:3;: C3fx\Ǚqioݟ_?_tO_|4:l&5Gs7TZαȣhV`HpgPSqJ qGh&3 mCvodxsW؛B8J_ 7eL?G}lGp-X`{'H3xĘެ}&wEǒkq[TNY%IAT=iz]w1em ! ;O wavv靀vK={,t&9^OY摲rO+6+{Rmkim*}UZ-ݿo{0lAqa\ uܿ))b;\jVHEVȚj)C7Ne^5R:nqb-]Ń3d@lww5!69ոM;pKF#C.y }rG3Λ&G8K05j|;.™'!DDC̝9aL9.'8J`O Q}ށT $8cp,=_˱Ӣ"8"9;hI ۤI(\?\t!8s;/ ]ʟd|;ѵg;J]Đ}K\R-I ~H;-Ր ,iΓ#8G83"?6gr{zA?sRo]{sԛC$z^:~q_ӟ muo}62ۤI4#nƛ "ΐlnH~w#m?@]w;8 m!n3H\49tρ ρVw7 J_^[lX03dKt`BPPD S*XB`X/#B`A^ʒ##GM[Eשc23e[kǹɻ #+×t1F@Gxo>Q7ȪZ]z&,je~bXGq#7J\=Ηp_G*XN7H[q6XJK4~~MS(,)dVapvzi*/ gi[4/6pmv;+h5z&ӾW@ -F>t>ا_?p,sӭf~1 f,-̌`IS99qf x@O}6#4\Ok]Dxl0^ $= 49$=9$=9$=9$=9$=9$Iph&B3n w5:e|{UZ4Ie.&6`@XƖYf׀,aP[,T._2)RGa;l )~"Hb;$4?pEHZ-b܎?z[xt-Q*w$)ʚUvӂT/HXϴeDBtk_/xI0i;05go#~ֈ>; ShdG<-z3e?":ɞZorҷ΢j t |Ё9102ff1mf%l.Џ%َSt*ݥm\Ɋbߟ…H-}~Mǧ.S44J qj1{WGJ'6+L'/9We1?$m_uXz MpڲT\z8" q℻!{aiFZX,;]Gh~I8ǂ߿څC=#">g?)7A""VQJ0abr tZ-m3"1H8"h{R'vy=Xjti~[6Ȅ gtЅpVv'(@"@ ژë`2@SJG5H ӬD 3.W:S18NB4S"[SaH8"vd\NtQE4T\=]8'%pȉsF4lS45#4p:dYԣJo@[<pIצ[MW\y""BhdQ : ݦR'""Bv?"O?wc@}Lh oEᲶ6RjmZQ6mPcLaxv wLhJhj`V +1ftO-J3nMt-W:"R7Ea VB,2)}ކ7"#+1X pdl<R0vNkԮR}8K9/*/5caСgiM.'IDAT)=lT5oamGyc[(C,EKM{Jݭ.җFgjovLuULȺMh,dj$Gv _Y:@: fw`2 ŷ :"\7(/x"+gD\̒t6`{~UaAq_.-t*  2 boX\*8;WhFJj}姧]R}(GD_g^Ke{hf:R!hQz59xMGeeb,YE?AϵaJ=|#J)@b@L_.Ks-&M\ϴ_3iAQXM(>hiI cYCZ(\jlKZ賦$[s0\ԃ..HDPG L벊^jwS3&4^0)&4u,4_8&| ϿGm4ar*_ΨW=ף@v...t/}?(5RPk^m^kXj?ZWImhYۄU~k@x'}z\O3i"h9luyl He m@*b>~DgE1",(-M~c&TH|I_-55ٓ4"6\4s&(Ng<;Yl!jH'@bk >z?2M~#t骱7 EVas"TIl]q4w%[9deWIWp#\9"!*E&(CLA`CYq<DCDl(8wTEt U qu?M-i8ׂ t 1e؞J(曰9ɛ%=CZ5| CQsNlCnTt5A'N4j Y_rHӑiڬVF8E8޴#^wYA xdXQx8s&IҌѺtQEZRHw>?52,a/`ȉ;ȼOERfP6%0ۑi g }JRRxܩ)╈7a\uI_TY*iœk*< |Ѣ6f6 3 ,;#qo{`*驘{f6YY_if?zpr'uY<ug} mj,ǔ8bҶY-*m2ہ=)e;MrOJTT0)2eDy,yqLDn1pn~͆-a]73M` I1R9}ɄxR69]7m`\yޤI) \F:BKÔE^˧FkX ӁyN_̤q ne xY5at6i!gɤ%,O5@g{mަUx)ϒۗ3D؀Ixy!". %vzzs9]pItRb̉N$%}zG9M[Reڏf23Sm 84 ݼ(Imqa3&u\gWXD%:KJu@1yFZ%FkF2Bh-`W>_uXt>ߺ?cV l]愘z*Sݶe/x=Cm^*X9a3=s_)nn۲B?LWxK7C';{\Ƿ/H߿_]3Y{J}˷t?7)9y%tW]EMD}LnևB9cxe=W[vﮠGRy`[˙dm:JDE/@ |8,X꼉[ϸ,L )p)N<tև:c6s`q {3i+TR,O\y#FX$E+ j ::,g)\mDqE7[gFWF}!I:qHB09lqmb}tt> Wʆ_ NaGxנÓpy%|➛ 'asb}2*ʗQٌ~ִ$2_k c/O_L98bsmn7)Qݣu*>q6QH>VM@:D;uOD$耘eE'nnAĂcC}Ch:6^Ex/"+ITON*D_ܶEO\OU݋V-D4T0%un 0%jQɒ^Ju”:6Xd5Yx'嬓5-]a쁹0x$ ON) b\D8yH8.i>@ : EmF$_3W U5J_"b&~Ul9N>Xg 3%`ox,C07}e rg++*}\#-𩗥9"-">{qzR5 L$zĻ`+bڰ1)eE3S(i;< Hft Nljz$@jlR9aZiawt:)"\K C*Y=}d@`_qzoZ-;0 :6tS*LؖG 0]6sEKg,9`@Ĕ:cwX=}psz77 ft'DĆ#V˥7t*{f 4l%Du]׼t.CD*z{*-1UQU)$s5d&aY"#>bt]J}˷Qv9FΙw<] ][ nB={q1w:'Lay|z|wxE"$/ 8%~dt? qD͈7 <{ VKc5QA$]4]#X" )mAŜV7C\ |DV;J7'e/TKHK8nE,gZg3"DVix 6 "#C!C'-;!&"獰:NGd&3S›4IbDJ8@8"FT,"%C??QE4(բNtdDSȀwO(8^H WA/ zPOhH)<юNd%uC_FK>>ADW[@^^rr2`^"Y߀h#6҈#>J+=c 􈏁#>J+=c 􈏁#>J?=←c")W4{%A0+>.#>ztmJ3ڧ#@Rޅ$A|z3>_IŇAZ{IENDB`perfbook_html/img294.png0000644000175000017500000004351711672745765015342 0ustar paulmckpaulmckPNG  IHDR]PLTEb``^\\\ZZMJKZWW# hffvstmkka__XUV856C@@A>>@<=wuv.*+rpp\tRNS@f IDATx} %Gۍ婯 nMUL4a}ePDdaQ%D#A8\|Jm3=D6dIѾz1 /ٰs^~3n+ \ƖVVwtg@kAO[?Ka:۩]DOmXO8-Da?y2DveE;jHy'h$԰1d r&/EײӘRt8Ӕ"גDHQHx_@ k8˔-( sɿg4Ve^U+ڌHsEƊOR۔OfD`?)E\6= ~RO^'}gj $nX!4=js?;k(LI ^jЦǘ՜M/;uB<*$4<+>B?fI2Vd(eo V~-ghVޙSEA8:'o֦oMÎϷ4e[\F feOYFйXnS}_#Μ`2~w1YLFl':M%k ӤR@3B>ɵ^QEGӛ`6Kg0, R,)m}jW/@ e~Xy0u9~bڳ?%5AAqU82o%xEFH]/Q~ë2Qz`zl,,4uTm Ls[ijqU;lOPoZhUNoO;*r!ɨL\c$ֺF>#7ӜX ~V°9~Evs[~=17˧~2*Q#]ͨf]}Y?> e?#mI۩A˱LӟE< l;Oޡg &-P`R*S*A0<x- \e?BbJ-FPv6Kh-d {Ga_YlOSsZl'hhɻCSiX)Ktpc aZ_G0O\tl"gM pQt`GDnQs<"63 0U9oJi_T9u1(|R,DGӍ=ـV51x5(3f'Sv GVHЛU^ÚQ`* ѿ4d&CQ;Ֆ]_n L5YWѵ~k >}.bsABm%uۃkq{u_}.^w@.poDlGÛ]JX\Z|?}8by9v'xcDiM3}}z Ź,w<-v C_lx.ĕy'sY~$KP5穿24:@ʬ0)vhSV/Zc A,m]+%ʚ$ԑ:h='ͨھb*{nbRzuP֊ t[sl4h&G֩w sQ[cKra5H1,=&V= Kr!ڤid&*$l\hӐr! sCn?\\;c\=3m?@"CgW[(??pUE} -ϥԛT[o;-=&ش ^m.ŢZ\,!h<[r{|X4+ظ FV9t:azô8V߅Irp >ꋤ=[EV F.>1A"LSv{&ǥ>СtQc P4ǝun!R.1j֥#.e좌!+}pA~;t$>I\-LMCX<PZɿQ ;Q]a৊K(=K )в5M٬pyuYKZj{=,RDz7Uc$,Qfk'Z.K*)z ?7"VOFG}|0kj-?|)q9㭑%叡[at \VmGq̜!q hF6ʈnqJ'+ {f@:+ hde?Wx`8.AA%hC 1LZUvDC )~XhZ%pLM1PpYWvqRuv4n,aAVܑ [ DA !ǁ#okA8x[ P:Ȳ2Z@n(43hJe0fT1.G3]PRf +DG+lܓ!zI{^|5c+O>$,7]*ʎ+4)r:]6D;Q )̫C x{ԐM48,mi{ߟU-';%٩?f&0r1B;üYW"]˭bjoX~Nց<_܌Z/^(k  [p EU"qI /}B3Vi_2 ,|S=2y pHcyD9 ʼt,`iGw.Fm{A< gUE#cy#e/pd{k9ܥ O^#[;)-tx)+1j >,k n32ĵEXe]oh$3!FG)m[Ű!Gػy;gB%]W[!C2z( 징KOD.'+S﨣obTn#Tcݓ8+[f'#a LZ$GTk6xɆq%0[P~s:Gk~+⌗hJ(2?M,@"~^k3q05HB&l/%o0%{!A.7gE&8̇~X3> >26&т !h0^` !m%q48N-) Tzn>0J嬃xg><,/j֍G&l![q(s-?Hxln+Ge! -3sW_7З}rxI) ^5;a|<3lp~elQ%|nx(KY_ ]X ;pp!e=ء[p6pxI0(7;;k? 1] dнWJiR!9D,&vlGshinNU{t˝N'GgWjh!pGs 5pD9`&nRnOv&^fW?VE[9&mیW^}Up +`#4 )|l$\* W/<Ĕ2ufDrAB|5cޠHNd;0(AG&H0'~lsڃ!?S×j0㒈9^-H|4`e=t2a$_iD_)Pd]*Mj4SRhoI<ԘfxmLXҗp)yuQhchq}{N,r C<'68Fdq:~瀮g{,?khpE[?b.x\qƋ',ΣMvyrx{9+9RJk?r/ SZ9){PY@V óf dX1"k^/M~Ά/ s8e,.uϐ} nt;i-+L(p>E0.PZpZ0ڞ;"+[p]Dt`ǰ=&r]$:nB[+Ә4ָD'A97`7N¤5Ii dPjGhJ8[,&t*G)W4n ^\CV !^1 9rF,juIT,)f"B+ Šb:C5k.C,ɵaof3z.\Z)vKʻ W5n+d\}R K*]g]<1 6=Oy"K=,w(O7 uEkdAA1@#j ɇjpp=tqX E* '( ֢cH*+I2/k$-:%;RB_,'$qRv1^꺱po|mfy=ohԸXXWڃ!zpκʯ?=g~M ;C{hdqHbΐ%;|2W]zo4+~d4~"_FRdy'FLA4g[~!g r+e1j!pWy3]4Pub[g[Q UtQ߫nLbE"#n v-"ޭvUI7\qw%N*=M#d@~ zm9gqEhGVrHjSB:n5:Z@Y@mNY'26"e[:p+ƚ7p%ǽtJӺgyGz`!#6 ,~/ .<_bh]e?Pi]*|b`Ed=^tQhO`9{H\LVNry0 rugᘅʝoe:?BS@z.(~+׹ O|5dl&,![R4Fj(]#.?<c<jǑ _z]9?Du,SH!#?0<7$u U?V?@jH-c;%G5"*CG%?XuG^wSU=Nwݐ`?"#^ɠi`\#/-OQgϷ'+n4$t IDATK$|{D!ĿgdA\^3~^H.;kW!)(c`m$׵&|eeR)S \VrْO,k}/eK헕̪%jc z'ë+"}i6g9L,,)ّ;߻Q;k@vU7uVs )˟1i_ ),DmFjّYQaUWNa?(|@_y ;3g9)nQ1,M:PT^?9%xHU9Ph6-Ի)] s;-W cG揮K-Un[0.j-wL _x%/Po rAz/sS|5%k3n}mͳ2)hJ-EP + gG<}Q o,yr]^)즘㣬/2W-M-Hyi}9DZ_d})T2B_jG1?2 ¶'rlI4E5_QSvUea谰#ۗ﷾|:?Fnܞ,9J_e{a^=YˌdhȣYOΤĵBs.B {aeʹl/E.nO˛j$@‸p{njM->_s3ʆ8|ibv 1q"EkŬ>G ŵh4B I#s z%QG-- ~E 8*sF#9J_•x^>8jc4EF0j`|}nj>g95rKd1F(D:[>wz_^_nj/\_rW{Jח W${Q${aMл]s̗߰ė_ėr d/LCNJu >ZyFOjƊ/Y)wSF#Pяc8=>)t?d`#&-Sd 1Ͽ̷L+*ws"cwZ#ZQU(PBpNhX" / ŌA()).vH?6*B s֗HR6m}_Ne~QKix~חqk*LaB ˴$Zdzyo/q^r>M I(/ W aH\" Lo#!TFI!Z-F$<셞I^ />0=RGi\pԄdC{h8Bq<$=2BZ2EG骂ssB юbxo{/2Bދs"[ svGrI]w!>^}p(M*sOõ!s )-W:jM6{a\bc{/ 7*K&\z= Wp% W'{a&U `/}0>x\DHmS/̧z2A[bs1E)YCOC}j|+)7\mX|ڐ=RFC=Λ%-.9/:"k32C o}!wIl-Ǩ0xL@XZ//<)3@ЩQH5D[_LaTjV g%UNycDZ_-|N0z B+xnPb~M[1&]vmhsyp[p7UnA1rX8Zk!Ҽ)7D~Wqcf2kY{K$_P'!',+,BX!L,Y43kU?Y 75aH(3U? hje,0c=dpR^ _зC:׸@/ QhIDAcwʒ)xxo{v:$0gi\Ϡ ɻ)[|l=XH9M"+}^#wZls޾Wq%W iE4}^IN4]iMH8ivJ=4PSӬ5Eiët? wOtW(ѕ,Ƶt1KL7D1v%\g7BJm ǯ4zǩ* ; /~kQ헶=lh(NV{Dq#,F)a+ėzɅEG@}_ x>^0y .~J@M #B|+tqK7?0ʊAd)lS'˗nw+݈_'lxU9cP{gw҇qRA/0Co./Q1DŽbx:5Yg5 s|Fhэ?&!|6}1aТ[0/5{+_~*\wHmzIȷڳa1jrX~}C_Y7B"c eZDer~M)Q3<ԣ Fblc&33YUTHs A*T- 3eT:<غe]%0XT{Űr q d7BrMQ{lB|ߦ=F L@k'T-ht*fx8\oJӔ x_hb| ,gRA&GYn6{,ww#wSQ*mVdzx#v} +OCSr)ǩl|ےy%FSLau}߯rEᕤSgP8ك WwYCJEw8fؐPd_u-, uIv ,Ԋ+CoMܿ@qu£ȅڸU%3u{:]PMPF@wQ`ߏ㷣ƖW,]N^;Iʩ|E1ΡY\.Rj3;SIsŰ*WR4H .65D7V6PE'!dEv;Rtqnk=]\&tXL:N5/l1clxtptoϺW!/>WTB­\r\r Oz7`KwWtɹ]r;xkxJPȯ3]s\rbSܬ,Ւ᎚k{ v-hsfmf Trฬ7/a9J7P||fB…>~65/ Y/ VsA~x*9als,YoвmyWThټ {ʹ *697:ǘcZJC7Iy ,Ex턷@VqP{U-Gl@{,s.2:&p ayk%l@ީ$ZB-uݞ-dB38ȄTU2^K3"@rP}%2"j~XH"iXQ=ܟ'VK~ 22`LbPPc,EL<{4']e/B&[!:e+tpiXE+Ն[#  >NNۀ CnمȄb[{WT)Bp .E&ڝp-2@uUAD&dBW=\ ѯdgƹ1E">ÞW${\(Lk)/p^+R|`K.u%\q]|+o*!H./[Nv()o0wuK.L|[+R|H="+W)GBBLLsOxt>L<́3bk8xT+SMIr $o! ae>lI ?.b¥pFHIwK_<%$|*{x{H2_L{~>G9u:~L{\&G)fw)2a{_yS F"~y|N|ڀUӗ=lȊK S|00R|/W4P: Ղh.N\lK^" cHtF / ?^Isi.ݥx[^!xmG#_Isqub*6\i:=v>Kʭf9 K : W[,> i]P26_LhEhp!S3bع"|"b|L)o9< 1=F=>O&\q2u6R YIݴ{Ps_L8g|2!U`N)YITˆ?}1Wn]5.6Ss#16D W;$NCU%dZx7Dc)][6[)=q nuCݦÎI bwXyv+Z{L`T9.- #~,;::t ?tCxs;ؑ zSP^ >{pS|Ωޫw6qwBwݮ096,c1!ݚnoc[v[F/EXtua_'86|L\uH?zjhlt&d%]# ;Je݂.pMau[v[u䩫n =lϜÄ,ٛGi:,V\-Nba.pqlp=mpm AؑTBvO Y)WlℯL͝A\z-e5 zkNl\xh.t)e5 T!ybеOiky{DO<\xOh.KMpe9 \!Yo 26v̧dEL{ȷpy/؎f>%1{e}[ 7E$$$%7G{DuϡGv\PKMQ~cT6x>c5K.O!a;[B,fcGRb-H??7GPrM?#ooG-Xm95fޖ,f8-,_{VwK.&5NE&rsK"zLh ks#% I&[un$2&2Hd͸PLhU\Fz! B | 2a"~7IS={{dD&f )HdD&=$2aBBvi-t-W,GE] Ru1_U·wӍZ"nvN^)8w-{߯asK.He}Ot*gyt[W_dmG ?s6[VN=wm rܭ{,ܗ9;I_ʛJH Ȩ^bXazxpۃg]Zq0gJP'QbT͡PA AaK.He(Gom`{[RP ]T!!47U_JC࠰uB=;Cs°T)5iU_ > A7Ew44M 9I`1mݡ{wvT]Ne~8|ۯwYFY/gQ[cl%gmij;te|K+o*!@"Ӻڱ-_ j.f2R Pk aqb8ٯ/WqMC(bcL&Ti1xC2.T1TsR5v X=kkW\jp)|SF'1PT$;te|7pk$2Ŏ8QbLj1"3./Eo!#$:ر820R]c'9ؕȄ.d?,}.~B (Ǒ@8GrVW"hp*6%`!{fZ:0oGw&26@RZ>2^RϏO{B-S$.9s.9_.j:\1ZP뒓A_\rx@8' jKnsR.93xYN tt:6Z+8HzS,vȗS:8~f/7/sVj M5ճyX$ \YE* |RyQ F{C]?TiX"bƼf `>tcq50@)x/*2*ML*͍޹',.Wwb݃ =^+VKטl[c)F 12_pUHz3|F{t>6ZWݼHz3$gUBBAPZ{G`7}B~=$y"tr#EqGxmQNörE{!և-uc/ϻDz'_f+Pw<=)<5tr#/gx*j\S _ oò" :oN7$F\֝ g9^Y0F HD'I,MXp$/8ll 2J̕B\;$>%éLHr/It$_Jri4a wDzz HQ>B$, IENDB`perfbook_html/node219.html0000644000175000017500000000533211672746162015651 0ustar paulmckpaulmck 14.2.10.1.4 General Memory Barriers

14.2.10.1.4 General Memory Barriers

A general memory barrier gives a guarantee that all the LOAD and STORE operations specified before the barrier will appear to happen before all the LOAD and STORE operations specified after the barrier with respect to the other components of the system.

A general memory barrier is a partial ordering over both loads and stores.

General memory barriers imply both read and write memory barriers, and so can substitute for either.



Paul E. McKenney 2011-12-16
perfbook_html/img230.png0000644000175000017500000001605011672746001015300 0ustar paulmckpaulmckPNG  IHDRVzPLTE""$8D 6SfDDff"l̈www̙3''ݦUUU*3-EUQ}333cD33U@@fMM"33wZZHoUUZww~fff ffDDD?awssu"""1tRNS@fIDATx C<\dk(>[plI_K&i҆-ghzzOi|}W vZ=7!D@@x]ւhnw z}G/|e;}%П qswf÷:-GVl"ˊWʥ@wlwcxD^G|~"򛴊+[gXΗXql}⭴o([(?wI8!xZH”[! ON’47NbVhPSaa*D\9 {n%xad}%%1_髠y+^/Jɷ-H+#wcL\Ebi. υ|xa& cwtXeN\1軠U̟F,_$JLl+l%;-ؤ+!BR([LIE_RUo{IR7<,_7%geB0 :S&wJa7d6h&X'*n+~o,_۷Dۂ/ mnCY~&QS1+:O#as2~Ƶ=Z5Skߗkl"a9aӺǤ0FծEؒi T!Ji P[T [WU[1(å! + M~)P] {}8P/Fa7YiXHJ^ZtU8Eη fB0y0ppKv9դX]aB)ք^٧t. +iE3ai?o?hZ,K$,Ւvn&hޒhg퀼]D { #QzВc&=\E/U Q;_ \$fbQ/]QhERbJ)t++Qj9[֠3EwQwQ\^T(|Wެ>;iKnoj?0*kU2Z1|֨؜fV3 De=LF(ګFXdyaŢr8+D5Ѳ DUhnBU-)iũ!/FYUџSݣh\iwQ!/K=+Fn^YFB(oOYuӞ}{$^ב@TFw(@Cߡ1jU<]4VJ]:˼QkܪQNXyI̚of5^E -$ͱ ƱGASZC4j͢uRYڞŏ*vo}!{# ~>*'uQj@Wo6yӀ~;fTaU_flX{›pƨԞ7 5FU4jVsfUj jd--NXƨFG8x} }b]ɯEh.*{PyBլG%Xx!VWG}Aje/kfĊ)VгN,g?i+V*iZYzkZ6jƘ&Uٴ5,?&&A5w4}}Rݷ4n`|%?$wB=N`g;b gW{eC?+pbq^}4'?̺u6h6]Epɟqd+5~/!&VJHtg]lbݗXHV itJ]VRXO-JmhB(F[viǪT,VVIʬ:%**٢W JUVP-Q(y4f4h,z3jB) +0]GuuMwͺҟǏxXH޳㤫_H{\:ck 83Ya0=j~Biug$Tά*_&⌖a2cm]I^Jd߁d@j4Th֪Mik[ceX}uʡuk{=#]cu4c[ZiUmP^VFzcibA`.Qč^؉+ap BxtzY7o|}aaΊ_{~Au@6:X!,*TXS|Ȉf8_%YI,og\ ;:$yvRyu t0\*:/kɔt}g_Up&` Xa31VPz L9c5m||}$VRSc+br8qR@ʰzXыkj!P+$ U %X)^[W XZF{YMMh2aU)5և56ZKkjrXLk}X(gZ*Lז95fZ f+Znyc[&\s'fy68+t:_`ud( + b%B]Wf]\f Xe1ZVk'+9V3ֱى]lcAOºZ==,XZ0jsfsկju2;?PN5wotd2^~pCSh ~5ޓ)+y.o>'ɺm`nwyVD֥1RV:< OxCS}fswww?+,1j*YUC8mc!: ":hMF'j^sձ&aPvmڙ:\Ye Rv6*s/ &J~'w#ǖi cm_[jR0(rWX!,Z<+@e޴6\Vy@?Z]k9uRa UX[:c=nr? E:#'!cQU` vxs="+E_"PtmRU`̖+SC_f~xs/o{ KkV,R*ױ1ixO!L$n0n;5Ϛgb Ys RUe2U-)`o=yUe}Ea:V_}>':(od78Xa޽IU+,S-qKY5 oDV.>v%>k-'Nb~ǟ7[o>~\^Vg] J>cΥ1tqQ+OBwT(ē| v'lwoM]l?u\ˈ9YՈ9YՈ+f;*5KԌNV'n2':e/ь Ϣ,"/?ŤipDma`D0)F/pLW8Yd5-8ni.rjTk)}c/!#&NV6YM~qGQ@l +%:Y[ɪz6dYopw@*Vt5,>sȪ\DǠ*k@j_ +NYEyQ:YYY倓,+=xpUY}Ry̩r 2#lĶmvurZ9YɜFȜFȜFȜFȜF mC6L4{eP3Wآ)+~oc>լvO.d-,k]쒵te&$k皦{տ[{dGdϺwmkg=k2h@VDE)l߲}MLZ)5M?s'*a{ծhzbM{vQ ۽6Ekڵ{)5,Э%*e.tXeDXNV#X=شZu zg+5ȺÊсա ?y?K)b.XS~JrO{P1T/WI^YR䰒[ WYE'sWt}Sީ^tՙt|t\85usdє>:f c麱|,dӤҔ%C#c:"j=u ?;rPr?YS%cYKoX CYqiqj4[ llEWŬsnNY4tld@i\ @V5˺ $>Yb9Y`9Y`9Y`9Y`;F*j&NKVETem`OVU'=`ڄִ{ ݿ6#mB nkZVU6ۚ ݿVѵMhm]MȶNV#:Yld5"6_j`hmdDa#  ȶNV#r'kmBjde5eRaP؝]`TpfXVcٟ[cDXOY]mk0Hh'NV#FB[,+}JPV1VH0ЃS` AV-XG~|7 MOUVh yy۷z=:ah: eՃ)Kj>Y/# ~K{q?F3eBW''aY.!{MkHVl>WfU”+n 8,> ragO s~$/l0fgY?bVz0܅XՀյB'o[NgJa!W=V_7]9u#.,drrrrJVS8-F־s,'s1's1's1aY*oJݶ\UڕR,N'YJVJd,$kܻ{%ؽZ K$Ț N{i?^rkܚ n`i~e`Uz-kڻ;{ץ똽LZ*j8NvX66KN85{Uץ *3"\#kw]Xڻ.+3$,Έ<,Nr9ڻ.+3&Έ<,NrIﺰԽ.]z{יUKOgD'+wKz{zי=eci$K[IvvXd'k;,NǜjKXVR,AYɘՈ9YՈ9YՈꬅqdY%u,cIENDB`perfbook_html/node395.html0000644000175000017500000001000111672746163015644 0ustar paulmckpaulmck D.3.8.1 Recording and Recalling Dynticks-Idle Grace Period


D.3.8.1 Recording and Recalling Dynticks-Idle Grace Period

Figure: Recording and Recalling Dynticks-Idle Grace Period
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 dyntick_record_c...
...p)
10 {
11 return rsp->dynticks_completed;
12 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for dyntick_record_completed() and dyntick_recall_completed(). These functions are defined as shown only if dynticks is enabled (in other words, the CONFIG_NO_HZ kernel parameter is selected), otherwise they are essentially no-ops. The purpose of these functions is to ensure that a given observation of a CPU in dynticks-idle mode is associated with the correct grace period in face of races between reporting this CPU in dynticks-idle mode and this CPU coming out of dynticks-idle mode and reporting a quiescent state on its own.

Lines 1-6 show dyntick_record_completed(), which stores the value specified by its comp argument into the specified rcu_state structure's ->dynticks_completed field. Lines 8-12 show dyntick_recall_completed(), which returns the value stored by the most recent call to dyntick_record_completed() for this combination of CPU and rcu_state structure.



Paul E. McKenney 2011-12-16
perfbook_html/node10.html0000644000175000017500000001001611672746161015550 0ustar paulmckpaulmck 3.3 Alternatives to Parallel Programming


3.3 Alternatives to Parallel Programming

In order to properly consider alternatives to parallel programming, you must first have thought through what you expect the parallelism to do for you. As seen in Section [*], the primary goals of parallel programming are performance, productivity, and generality.

Although historically most parallel developers might be most concerned with the first goal, one advantage of the other goals is that they relieve you of the need to justify using parallelism. The remainder of this section is concerned only performance improvement.

It is important to keep in mind that parallelism is but one way to improve performance. Other well-known approaches include the following, in roughly increasing order of difficulty:

  1. Run multiple instances of a sequential application.
  2. Construct the application to make use of existing parallel software.
  3. Apply performance optimization to the serial application.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img117.png0000644000175000017500000001141311672746150015307 0ustar paulmckpaulmckPNG  IHDRC[Tل "zR D#΃JП#gK!Oᖡz W$Oԙons^Vo@JI>}п# ČaD?W2 ۢQ 餌螯h vkMX|4mJ!HHUz Ӌվrs!ONӆ Ux?,}/^QȂ #08Tބ!2"U/=5'k[1N{FJeInخzܪ Ό4h<}PPv3G?]9ljnC!~sQwj/?TJ_#l%m\2th<&Sev]oө;$oLJZV#08Z &1}#"NreLVYJM?@z#A%1kc`鴫&n>ةm&rSȰGw0z3^T36Y5&8_^KBRϸ'GnYo#j|RX83CPK$7Kk(0͜;.h|aڎ RsjxzO>LldajĒN]æƋ0=~1}J$q]>OkEU9͟ѥ=T:% nCwk=MaT\*]TPHHHheiʒÐK" ( ydn. oIR8+]AGD#0և7^[G5jh"%:]OU?i$s﫧VO}44͈˺M^0sDtkv P~%QHI w"Le6?S. 4fkoAV@àuR&qZnjJ]Z ;9naE;$dUOl\a "m}~f=kaXlkC?aMdQ[JIM˚:d6cȞ$ˉXf\I4 \'vFHWfum|\dj(O@E+-]D,QKxArvˡ A :3!vFF[Ӑ}dUHLh#E:srBKrcɶ0\{mΫm&{MUJ9Rmw|I U]%HM%KPDma&ߖo 3(1Lr*C>,a`kGFFg'ۓ ųd^L(r:oau.e5XǫB"CY(%@LW1KB"(e8]:F1(cjc4ZN/ȴPsv0X)'IY8yr,cYk]9&mj:& -=*3}UzέOqp"n$(>S;R.eioc|sZzNԺZ+@^ƯhLэ^ S#8~ }%! PŇ͔# "'~"(aPtk aeFT\Kds3\q"^IQ|$|v"9 ](KY.Oe$e@k9п[~#ǍsH1Vn!"WdhW} - FЂmvgn.sa{R"89q\-ȫM)rC&FD˶SOأdi2Y=ʫREP;e2(~iy,ϋ`,zDrbɋ ,r?ZW ^֍sGeOsaP}*֋`zQ㠢έ\/rpB"2CЋઉ!UrJ{^WKjEPvTq!jѥNlVƷ^k6WY#Z ;N6%I)|(:ǢB æ-r&߻]M2-GlOoO th} u>t\74èoFҰo* K;tM X 'G $6|c*Kr8'xUpKѼ qWo+lGŇyhMM44tZ)ybٍB3Dzo6r9s ƒPr ){ŗa (y݊|tt/>^:9U^Y iYN#ŞܬܲB(/odXr(2WQ&{eٲ9E`!0mG{ i'dE`!/40 AixnX6jplN+G!bgJ~>&nx]`vkSfl7a2䢛1ЫOfv2I}e#"A鬂B1`k ]ӻ"*鿫+**~2)>l;2_gW#\{lf읛\S7ՌY._tY0`<)\eqBLjg&OtB^5>t23$rGM}Mݯ&tnÙ.rZ(" fŧ 4y5"7M>U8CU%y_OըsV]ԄGդbo-7yiǰ FK[0L}@f]K+**Ʈ_Xࢬ@N8+aBgty?]Y䫢XxV8ٞ9^_1]XC7ô̕eױ +':T[gMY$TV64[:z9߄r@?1ve?`t{2RA6e^j,Hqӥt%s+!<%>Rh }6|2t+18tRF V6G$N0Rn픑?MXfD#dFYp?x '_m9sozVnTTTT|#Y58i5 1]cTTT<‚v5]H6NvJ r16_H7nN:Ÿh14v._ls?4֚t~c Jos-NzDŽA|aB "PQcCg>_v>|赚>SV]߀X5t;#~6fbmApWc|<|DZ$m/ Z~b" EcW6yhJ`"$ZrkT ,mn=+t= ?1p)F 4x4tMjzp?!O9ٰCOmM.JFB ;6 vS%9!tvtu 0| 4@+,)H9ByxF{ ^v0Kf1z"Vr!~YC8_WG V @z>#uCBB["i:Ol|LG44?7OUn921i[sV@H%:+AuRq/)1TZR`^rXʐa&uQ@/]B#OQcRR" gd{1E-UNU\")QF69x>R )֛zTL\s+yʩy"Vq} d88v3ͲvX$Uz%Aq^-Is?`٩'IHJrBh"4%ˬ@KR $^O2pWRC7MbjR:G^z%f(N/h / IyD V$Js(͸ۅWH&T52ITUu5oˋ9Cʻ}l{*.c4ױ4PYJ  r=y':+猎E{KS7k0$ mk<Zt!)Z˷S̐2CJYiGZ.&b{6XCtwAXh!7VٙNR5.=zd{kXSa1`\&d \\5Z.Igb3rӌ?g³WLm.>h@YklajfmC(Cݏd'1E%6 $| \(;}rm3+ە"QKQư~JtyQ'bʕ$ m9x7& ڐĴ.Y]%Զl++4&$\μUN V Ǘ*V4ԟ$t L:M pe• 2tM8WZL/> V$3P+j:qt3c&1j ؑ/ZNDCzfT"Nrc+M+ByŶ͸&Kԙar M]!z0.^'Bm<+t0.I7/WZqMz@M~'bի:}O厇,d=)"5 + h˒/>D c}Xn%H+qKʡKÅ+m+OBL&lUSILV$\ȼ80 T[XH,I+wX^td.^)‘Io]T)} vmQs4D0R"bv|dmrDs1NzطNq#Y^j~J2s=DYp}7gKpm_M%l$W!`7sR<6[wܧ7W,̛?u<$\u.M?&\T,7V]4&\T<}0cǒp+X<^ZV[0 b&]6e۟ ;&=k*zHԌxl*9psfE)袔k6(5c@j"D [9%f=Z;+,qfcP!ʌ ;+ϵtP.PJ@>(7Etݡ¤^==͕Vp}upڅxμ#p/}Bp+B0 l^z,Xp'M#\ ֖4Jr{% &}.D mFdKȹ\9sFK*.x^ &) I"8\aA`؄}l8K W=/d:}/W0z2ujjU#JӓE'ӗAdk;VvbBx}g)5p^߸6+ܱI}l{xܠLJUЕX-uPr&OcnCHuRl%q =]X=}vlk3yg}ܛ'[B@ZvPe㋥(Bd 㥷@hp#4P.erl+rmq?XݳGNFYnoӄK_4B7DR{‚> iI]!eZϣ럴n-`[LI҆%f=G,Ӓ347yo`k3E]OVjXCJ~>ρ/myk G ߏsn8hC*;а~v> _myPWY6|IENDB`perfbook_html/img305.png0000644000175000017500000003237011672746007015314 0ustar paulmckpaulmckPNG  IHDR"َlPLTEb``^\\\ZZURSTRRMJKZWWFCCrpq# hffywwvstmkkXUVB?@<9:856C@@wuv.*+-**ighvttrppmjkRܻtRNS@f IDATx]´m.kӲM}w%`֙aX"Qxf쀾z'!8gIVmZ#.Aov_U@pdePÊGw}ZRf8 vt a5ǞleNR}jH-G f._A;a5*2+֮W?Gas`/Cx8ƣeR[Pӛ-M[TG\Tʭ۠TеpW(AE(P[o"cW`WvC8n-Z/U Q%? LAy9=[ G$&b9AL!ѬuǨo[12! zle]|ɮjxU ^VJ@IҤUB=HqZnv SCdYSBr՛-V$@:xΛ3E"~lnYe IӒ2&qp>a.\DuN{wD8#6'`Bn { tn]cJ63iżHb zZi,uV+Z÷wct#.rJןd(1(]YjG dqmn:7ylcdסU׏TRxNKn)®ѣEMD>'ÒX^DuZV";Zt$׀'VC$\eG_|hqjn m9k M`?÷m,t# -3xa:ǘtId9;firuӳ[0z *'n?%I`֩i7sz/nM335Y8KMv"_U)O:: X7Jt]"^5&rnz"#=w@Vo/I*DѠmr)RJ0m%.VpmOM4p?'xƗo`]BngJyŠT* h&E t&MxS[(G%>T6ƎThƚF.cbDTg[8= -ȗU8s O5Qq `½UT;ƭڨͫҵn)g-y Y`@^QaǴ+_3B<|]#WXPX/&W d#kpse0cގ@`gkGTht?{uL(VQM^oT[k3o,&ƓU7 a4<[AhCR<.#Jd/uRQncΉ [e&)AP0yU8+1N U? |HJln!qm4õjENsRu HdmuB0OgYI!w^&  6wޭwCRU- g'{#]xu@2*̸^_;0!-^WI52IђĨ&rl Se DN* GD.ʍkScbȤ  < O%q 4|=1c9+Vu" *B2ij$`@_Bpy 43eQjXj_yRV&3RF~|xb΅맑 zNER&ysdY7;\PfGn"|"%ïJO8z-v6,ޑùZQ0D=…]")tLx-ɚp}}`Z}gM) K8˹(}d]ǭ}⸸$?e@)zNE5tI<]B<x2\:yR6ο>xS%)kjbVk(>op Ns|_V =N WـpaNUDNԲ(XfG/F5#pdI = n5nޖF@A1Ǣ2%^T)̣<#mG_w'au[('St E.DQX:H?'nc4Ey.+bXp)HlX2m 沵 j9Vy/ȢQn!%te1r>`JvNy 1 B9#?,5f􋹻 ߕ|&CA־Gu\9墏0Bp ߩ35c7x fٌ}{Яƛs+W@y"=N!e7uwy  -+|rS1ZCGFo '}ȴjnЯ3|;_ SТ"MvP9z X5#ZK2-*ҤgLP]A>"F&l. urj$置090 ɶA8xIp8}hDJ6I-0Q-H (aI~'Y% =JJJRX jֈs$6='OqTqk J7"V-2\$OCs%ƭfҊ2cɢHY)jf D) Ŵ+,1=A7mid..;8e[2M'dk{]_fk%7yHj4qT 19 W)uK1|;%l"^bFo WG߅G-`x}Ql0L9{۲[N^* '.Ol< V;q %&Pid }$l诉͓r}Ў$0+x`66T{ll N5_{$[DOohsLjGYbFu8 U#ZΌuس(^ިz:߸T |!RN#78J+jDN(,x@nM%1);>z%Zk̯J $Es+AR4Sp#`uQ*B!&]A*bnF$ s}ƃk^7mdb!clNj9XFY;|xsTh몹ͺYF"H]aupCr%R߫c)Ag8w UJ"׌Vވ/ڮC1/%qE:ҥ|X%pV1(@C׶b_dPAvJ=[ Z䫖aA\y r | 2ţET%d<)z8|[Ơ+~x2-x8p >n2~WI vX"U Io@sehgådqCn.c'9oD<!mu0rsTW##!gGV#])5ɔ{,δ&gՍQpRi<߉x BVѻ/)"r.K&fu.QbӞZ밂NE`2JW,DG XbkgaQ2iB9wqȒ-?8HfI/fǕo+Nt H(QԈ eL8'tn릭2bxiKo`%$;;c#> "Y{\g{MѴc ^Zo}Ȋ: {80p.=.Aö/]~VT ûj0Cˉg-ru~u %&Ym(f}[{\)k(;cv)*.>+Bw  Rx]V*&>Vk[rf _*b?d ́a)gv藍Dד^]!G2,N/A=q?ҍU.k ]e+kE܅/u){iHUh;@j *B^[Ң# -T#CQy^Zy;bp(-^2P!L$摴ɂp dRMs]NZ<5{e1@vҢL^x"$[" xC@}ԕHh$"Ak,1E( ^ҁg7w'A+Hj6OCx^0#ܳ}L,d=Ϲ0~UTH1p 7` 8qh j"[_WG!gizƛt D3?r32[]u ^5`S[ȵ P,1xk] d!Q&Pj'O$f?%dֽf&?5z5n: J fYX \SPD<`U\2бaBdDP$`1?j#2@zȦ׬uV F BMc O, =Et0L,x_q"R\ *Nu5@ܤ`͸mܣ`MaF+Xh?*j@1ChD߹cճ'dut*3өTBڬm~J/lT]z]178cX Iӝ|͓k!Jdۡ|$Tto])ze"34ȤaD5dR2DI0YxIurVՌ(fc&oR$bĢeJcЍrk:sk'jF'/Uh תhkS189 KP}#48Mb\b 臣Ʊy\8 5> rg4Г"WqnA3ZPa g5\P Ԕ㌖ȑx[ jr6?Iԯ7 ji O^P۶F^uB*9zEfvJ ug%8^6OP~ڏ6.{tj=V@:. tSaQ ̦I_G16&YNF64 #H|J|DARŴ19jV=gH*y'kZPq$$]hQsI(WjZ} 6$0@˒'Jo0Q-AWqҥͥQ]!f zBI% ј4X|g{Ig?-BΟ1:?m̵^ 4|~:ȹ1T4ou8(jDj[E ic͕V\+ǎsE ?Ϥc1e!3RT 䤂KP*ȐѨkS-%.~,cUpig.2kfoo/u};>NKI+ìe VX67~#䎯َГlAF`c]8jz*TQ5vN; ;KGגS~@UIP9g%WX·RdccHt0pLveL_oJRp)@C _ژ'JhVJVO.Wk7A@lkSD螑3I^ c ІMzP몸U/,M)U'72_Uy;VOm#{;QתDj_il.#BKȾYOzu45tV3ďL\+m{I ! ks[PX+9'&BWǢXn׭iG|/@0 7l0̯LO5{X)k4*("C;ܺL~wxRdfϿIalnZ+rɘgal] М~,mEG:\*H0uh+$1b@6S! Ve9EcLdUtLgJ B V;q?<Ҵ=#41YT_|4 *wC U6C:1S#?olb(XY/w3p An2WBE1}a5?DDǐ02h|6, b YclCy' 1Y"e*B@3yV"G|1mބ0aT&&YaX@=#ZFDD<"U?eDE 2P)5q{MF!,Pp{ TC *x8rteoB\G0ՐE[Lr'f! EcLA@UUq&CT"ހLn*xےrw4Ȭ7008/8ᯬF$ZkYՏெՊA2,xVߩ2ڙZS43H:vw_=V052G4#+:/UHM蜼;jAXT*)m´6}g^ǤC =pzۯbj(b'pDR\hnaYY2EG.P숬0sgFDD^֋^ |mT>CvDAt\wфv=ocHJe3$lGBk71$n#RY1' qjQ oGĈO*w!gX?3v~);ƧgY ZHzTs"Ppٛ^_OLea!=?\k߆} . q!f#"`BC~b0 BC*#Caf2$'LDD&Qey D(*GͪJψ n+Hإ=G;~ufIQ~* 1Y񹚢Z]Vꙅ-?"Sfa~ᑔC &o" 0n[c!D|&ZB^۵@օȥ t/Z+$"" Y`QC q /)d7#[6q:$æ2VCʒb4NgMu7ȓt&>^t2lz/{Z !鈳qɃ*QDA&DQ7' | 73ç9 ZOL:1iia*=+вX4$HİBо8I0 ¿iIϞ҆Xqeh =3E`EW^Bݱ߅,A]EϐRp^41!9>""6fd *pYf~c]g6?7*$""bȄ(Ee.bh6[?dBl&-1qfi+Փ-qPFMms 2! qK8`Į}TDe֬mGF%IF&L) 6x[䧢B7 ITQiez1. yLe<=m-։fu@~*S!B.pպU)OLbwB>B9{W;Hcy@y3_\*6m4J ,iMȜğt6)riʌrGDęV}q?eаBp~S1fR{1wIw<=:*B!VgSX*R(/}n>?Kc&r* . abZzx*厈qY&̴3<ڗDD,f1}tJ7y<z™13%!m{'gf)a CG!.D`P<۟&F&Dz$`Ntrt|K 0!P|P020EfCDּ*Fn`Z3D.ihyȄҡw)UРf?t;mPXgNXx})|y3Tč0&D ')k[&D'~8 RZpY`T0MaEDDdہK%2S!1e=- պ #*9-@sT"? шuK1&-Kz H q0SB57J$lBR=D`w4C|G2ߙeXk< B|)5QZā YVs49硹9i،eXk&9ܜW2M2xD?ȕ$syS}|sLkB& reFG)xh)wa!K,jf3MQ3hB bpfO7{?d% 7͒7b68>~&Y@%]u݀YjfJ0&;v de0&D=!U?cy飖f!B2oX,g:; ?TJebƢph6]`I͒s TCU66xBR["B~,0`į\fXP#-Pff6R3,o{9 `M:%C`flpYުj iͦL23K9\\N]$x$1\oĜ:W\0ӧS!Tr25#1f.3S-0i&+I W[Jff9½1c'OA-ބ0kBVBu@y"2iH߀ awV߂>ۍY"FDD܁EfM3SKR3L֐j3'ƭUCMLXdprWm#<4S.8ë[7OTr'6N҈K;ftr'd!'kI!zD|3P;?h7Ժ!6 d= ȍ hClĆ ӆ$ !v >'B,"" 0d"76ouv %MVȦL"CI/Ľ!Cbex2y*2ְDH50݊IËHfƎvs:w5Uզq1*& eEGodxY8eQJ[O氺S1( Z=+H'Lg.9tR!nP!HhD~|]i 0@{Whcڗk8o`(+cfϙ}:j>3oȏܝb<8D;PZNಷC,TOOJqp$索Xj~QTKpvZ=uʥOk~bf#N)w;Cuj@O p5eM.˂;߈ 6Bt)Ƅ@yZ44n !rv?8\Uln{`C-}v(_z'""@32!ZCbu; dBT۲wDDD6H*;j!@.^ 1]bu. 8ۮnԺyo E.7.2.1 Basic Model


E.7.2.1 Basic Model

This section translates the process-level dynticks entry/exit code and the grace-period processing into Promela [Hol03]. We start with rcu_exit_nohz() and rcu_enter_nohz() from the 2.6.25-rc4 kernel, placing these in a single Promela process that models exiting and entering dynticks-idle mode in a loop as follows:

  1 proctype dyntick_nohz()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5
  6   do
  7   :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;
  8   :: i < MAX_DYNTICK_LOOP_NOHZ ->
  9     tmp = dynticks_progress_counter;
 10     atomic {
 11       dynticks_progress_counter = tmp + 1;
 12       assert((dynticks_progress_counter & 1) == 1);
 13     }
 14     tmp = dynticks_progress_counter;
 15     atomic {
 16       dynticks_progress_counter = tmp + 1;
 17       assert((dynticks_progress_counter & 1) == 0);
 18     }
 19     i++;
 20   od;
 21 }

Lines 6 and 20 define a loop. Line 7 exits the loop once the loop counter i has exceeded the limit MAX_DYNTICK_LOOP_NOHZ. Line 8 tells the loop construct to execute lines 9-19 for each pass through the loop. Because the conditionals on lines 7 and 8 are exclusive of each other, the normal Promela random selection of true conditions is disabled. Lines 9 and 11 model rcu_exit_nohz()'s non-atomic increment of dynticks_progress_counter, while line 12 models the WARN_ON(). The atomic construct simply reduces the Promela state space, given that the WARN_ON() is not strictly speaking part of the algorithm. Lines 14-18 similarly models the increment and WARN_ON() for rcu_enter_nohz(). Finally, line 19 increments the loop counter.

Each pass through the loop therefore models a CPU exiting dynticks-idle mode (for example, starting to execute a task), then re-entering dynticks-idle mode (for example, that same task blocking).

Quick Quiz E.10: Why isn't the memory barrier in rcu_exit_nohz() and rcu_enter_nohz() modeled in Promela? End Quick Quiz

Quick Quiz E.11: Isn't it a bit strange to model rcu_exit_nohz() followed by rcu_enter_nohz()? Wouldn't it be more natural to instead model entry before exit? End Quick Quiz

The next step is to model the interface to RCU's grace-period processing. For this, we need to model dyntick_save_progress_counter(), rcu_try_flip_waitack_needed(), rcu_try_flip_waitmb_needed(), as well as portions of rcu_try_flip_waitack() and rcu_try_flip_waitmb(), all from the 2.6.25-rc4 kernel. The following grace_period() Promela process models these functions as they would be invoked during a single pass through preemptible RCU's grace-period processing.

  1 proctype grace_period()
  2 {
  3   byte curr;
  4   byte snap;
  5
  6   atomic {
  7     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);
  8     snap = dynticks_progress_counter;
  9   }
 10   do
 11   :: 1 ->
 12     atomic {
 13       curr = dynticks_progress_counter;
 14       if
 15       :: (curr == snap) && ((curr & 1) == 0) ->
 16         break;
 17       :: (curr - snap) > 2 || (snap & 1) == 0 ->
 18         break;
 19       :: 1 -> skip;
 20       fi;
 21     }
 22   od;
 23   snap = dynticks_progress_counter;
 24   do
 25   :: 1 ->
 26     atomic {
 27       curr = dynticks_progress_counter;
 28       if
 29       :: (curr == snap) && ((curr & 1) == 0) ->
 30         break;
 31       :: (curr != snap) ->
 32         break;
 33       :: 1 -> skip;
 34       fi;
 35     }
 36   od;
 37 }

Lines 6-9 print out the loop limit (but only into the .trail file in case of error) and models a line of code from rcu_try_flip_idle() and its call to dyntick_save_progress_counter(), which takes a snapshot of the current CPU's dynticks_progress_counter variable. These two lines are executed atomically to reduce state space.

Lines 10-22 model the relevant code in rcu_try_flip_waitack() and its call to rcu_try_flip_waitack_needed(). This loop is modeling the grace-period state machine waiting for a counter-flip acknowledgement from each CPU, but only that part that interacts with dynticks-idle CPUs.

Line 23 models a line from rcu_try_flip_waitzero() and its call to dyntick_save_progress_counter(), again taking a snapshot of the CPU's dynticks_progress_counter variable.

Finally, lines 24-36 model the relevant code in rcu_try_flip_waitack() and its call to rcu_try_flip_waitack_needed(). This loop is modeling the grace-period state-machine waiting for each CPU to execute a memory barrier, but again only that part that interacts with dynticks-idle CPUs.

Quick Quiz E.12: Wait a minute! In the Linux kernel, both dynticks_progress_counter and rcu_dyntick_snapshot are per-CPU variables. So why are they instead being modeled as single global variables? End Quick Quiz

The resulting model (dyntickRCU-base.spin), when run with the runspin.sh script, generates 691 states and passes without errors, which is not at all surprising given that it completely lacks the assertions that could find failures. The next section therefore adds safety assertions.

Paul E. McKenney 2011-12-16
perfbook_html/img118.png0000644000175000017500000002757311672745770015335 0ustar paulmckpaulmckPNG  IHDRa? HPLTEb``^\\MJK# }}hffvstmkkXUV856C@@A>>wuv.*+mjkt{"tRNS@f IDATx} *%63 >h:-|$٬o1 Xh/JOK@ݞϝ25*TW^6}lY~r _@~l+üzeJVƏ-mUb)w<쟌gp'*OV7ܹ~fx9ϡ.q(/Th9_8~M`:04<͵nackWW?p<}'Ze oܼ-:tUET'H=h*#?3W}^@ i;8r_SU2'ډ\dG37EaaR)P(y"ʟl>ǥVRb Nm N J V m*mi0~|dv]hse?j]|k;{O[^;+{IWN<|5~E\ ~gŶv@]_|XxO2kh^`n/C||_{YGki,и +_3H v҇rR:U48-,Y.!]>VRl?_ϚVd915&zwNwCo-[7 w~y}'\c]$wY;7k_6/sfa'gEns;Zl)3Up~ߨ* -M{/_d 0̀ZL/o&; 5畿sU~mh4 cmap+>YNc vmskMX"KM oOkywB[Io-k5wOj(ͥ_)@#Zoj/]eʵl5U0?/@Mu ^L4~Ć%k+p+/z)9(84?>U,?EM3ybTj<7~j4i+ĸd[MnP.nim{0kX&3t~㕨) R>Sqnfb~^]mYDOB=L@[LGI39) | $`KW@m'ȠQȊG]pth5r_ۉicxWEh.7'~ fY ^%KFz> Pp N B`aa3e.scW\kZ8k,.ždF@ Q^b9^!8.ml\@ PParC;[}e{U7 +M/kBSI[Y Ӹ!\}E>v]ċs 5W3@=qpm{0XaT ŌtLWAao.K z;=V_QutҞ<=s?יӀdPT0Z!vO9eag렺A ]bTvA" QAk/?a0WCŠ‚.t]^Uq)7W p׃sMmY,n*[v9t?{+{^UIT[_dulOsNf9;1k}jv0FhkJպábP؟/F'l'4A5bS ~4CL #DO F6 1'L{KQ5R.7 ̣3Lp^T#aIbhըABy)٢BYuTݐce u/Nڡ&b|ekpU7yc$q eJh ~# %@R1ӃS6ͦ+5Ws\+#>,`t.|zթZ 'H-9ջ5Ӝ3g0I c<dj?܆LQܩ̏alsӃ,1tlqhQ/HTn 3w͂5F4,tT4/ZipExT9D憭)#_5}0'x}/Y`./hQ6{a˜oJ;`f4ǽo=(C]:"/cp~O`6;#q4r$Q55U ? _9谱hr>HkV*YiQduNYZigWCAM;[׻/4e5Pq^7Afm`ABƩnaXP\[!r/IyxꅂJk`>@57DM8鷄<)*[e욪bfUK>ǎUK][1G k$c N%B ?tZ5rrޅu8l8v`I'}/cNc: WyIpn* R P.@:ƢZ|A|cllzOC!n!gp±Ɣ]X@wb% ,ƥW/1 *v͜pwԂjLΉʎ+G`X( _*V&*Vwe/֩;  X/E#b&t+6h_7eTk3_,8$+D.#inzy~ky:2#R6E9E缂*dU[Z PmRmՃ8::({lN>NK>@ IВТIZՙn6ף/{\Dn;5:p_TTGcSEMo_o-#̽h)t'^7 "a ӽw߾" O}wK%JyZkI>Zv9fif/͕aLiTb<_V^X0oipgûRHTH_[zn<6}*$Dʪ1 ?~~T4ͭ$|w7EBڜiߤ40 mΜ 狨t`Gڅo l6pD—!#4,Wβ#U8X| Q؏Zi\qӫd Qf?Kum(X,D,|C&\Tk7{AfF!LcЂF=iJzj6.b@C;b}4>_oxr}20~`:X&]ּFg Қw@Է҂u' ^>vL3ĻfQsxAZ+ "bhA`1PPsP=`p4jf|" b]k34֧dD nÈ%\Y<Vb]#'nB4=,lf!Ԉ6^f¿xZǮzD p;||`ϭ1: Ea~#v[(!X"-FBOo]" B7JCbE3@M!h^*VtR+Loj (1E?(\ ?h >csv~Qެ:mbN~_:K^T|Cn%$NNk_уrK+e}"M8reɂ,\z K|Ep梖j ѥl?:K51~C6oh^Lm?jRpa4;Q&;*T5yl u8f)"NV<94B3fjq!K|zl(ijE7. ֊&s=M*d?( j2;+i nUry65)< b2=vIg=Q<ǠZ ]r3ny!# bQ.HR1z:?(e k~Ra4?"hB|qnX ^a?r`0aT\KxWxOm'kKRꢯ [/ڪu K 0xԨ jiV@y~-S4'aRcK 1~>.@mW3O{]tiOW{!O)\OåBq `(g7i~HQ46o(Cdid.4@_HcwШcGôBCΓ#Mµ-~0/G)fɣPjE\Q&\C#ep ),_ex/] ?qy /tM8A&Vf" )!6 W`c?Wկ\U (>" )͜F-HZ\MimkcMi!5:0gb/ل^3c4uXqmR*[ '}4Ý߉@jsgء" 0 > tѵ ?1&Y` 3256,Z!Q1M}M5f:af_M_L?<߅/S9yfopb_{p ?KtݿQ._w}UFɊf >k/XqţKlX_?,$:CTV3N>Zj6Xӄ=Q3u").6D%(+i+6Jm;ep=Xk̠d}NB]" QŷØ%{XoT1"O+M5w>f"Nr[#Q;5eV4Ń»ñÆB$gM^9aOq롏W]2pUƘ{cӺpgXOXhxG9S@ wb/ )R1NU5Ap9.Yh@>dO,$xBÞDX!ܪBcApI7,1K{a1B* xkǃwg?K|',U= 誅2GUhZ'&9&prrPp t1K5X&4.pS}p(hcI];ޜQ,1X/! sH!5|L <12Ȏ)@! i&\:G?G-l) f_exP yM' #:HͭvNKgv;,BS" 'vkK Ct"(0]k&[ך8( ;2[nh01Z ךi~F%t/mݝ #s y G;@4Իڄ& (Ja2Xf1Pb`?D }7n6d1^"'>`,rJ6ļsW㫜0 -58^"#c939#W N(+m0ՀNa0;W2A",1%ٵ~'UgUjMuKtM!,bLj5ƴֲ9etQ^Iߢ! vQuc~' pp?po"U/냽(9o爋1O@ -ۺ.zr~Knylߦ0apeNrppNH!nʘlnL4?Tħ $IrG=cԾw5vcg;hVc"0;j_d׷AWT<r Ê3+,-+t/r"5\{ ?Egbe>|BBt h|+nOSt`,m4FaZ<@6^'}f7 k: 򒅭kQ"UT`!0e?5mKA9@i2>y&$y>fQZ5(PY\*wC#.{%aP"Ћ٨D{0#aUxuC8rv #YAmCU{W#KJW-:L&GyˢaP ^lZcdUFjJoWd=7IgS@Bϐ曳6u4 1,==z39">Oj,Gd3*Ey6umyÍVƅKuA)_Ix\Cی~$ϓ>u×j&*Cc8YV6ku&P7犄fVK1,Cќת&IDATE0K.?F K%TO%oZpnSOˬdeQeV|6"$KuTM;٧UMlvaQ#(. PA4G?vn1JOLRchRQ2|9&OS{1㯡XCp_wXl.sHȀC-+f+ Vz8+3sW"ϑoPsə\X8-%$ iq;g5=l)bGw%RF:"W'VTİA\PNv* 0ioH#aqϷ'>ذ?F?\wUOE+I w%AcsHwc]g.WLn4T-?>gHa_Zfl޻?cS j$Nk-^G?볅5a 6/ ~Ʃ+?02]{E5L"#Vڇ龜4?LEޭ~To"Gaݕ<8|WR E46IL`YjA/҄" B"':+9]_K>k^p={-2GǕ?(\DTtrޣ<4!@\v^EOtVF"6/G&OAKHK8j%2]έ2x5X(|t._~Ga!b/;@)4CJg#'$((א8]j~"5+sC~WKY"!o̹Y6 #dDjL'ĢS> Y"!!G;4l?/8`1F # f5?`I6%agaimb·'1ҼXh&!.9O5Ov9GłIdjX!I#eaBd}{'k1 1Z/釅?pH6 rpb8&u:KPG``DnDq( ;Nc\JpBBQmRҞ1t142b;!!!!X~,tC We2aVďXho˂=5qVBS04ʂ$ABBB4j~J$F .q~->_уD7+[h|N|լЬR/B%5׶!"apf?Wm 6-˨-$ BeEKf^x뒿l.+FtD:ݤg_d֡wegpT^c&~ ʢW*gaj/ .pH.ޜ) o%=8~/xꍄGF˔ ytK ?"mD)`L?zP0N>? e,Ei_맦^E۪(*W}^o3=EiHZ' u [,JXآ7ɶ6p~krh%Ȗ4~nz}$ b57ޔ@ +s["`rz]+( `}|f(~,Dٻ7AV߄!Ϩy)2 f2 ^5,U?If6LQ +<8tQȦ 8q<{PP'0,4Z_B7tZ4_=l'xiTB&&f6DXl cx,CՄr oÄ)ȏaN8YۺvN? '|!2pY vd[OxYNHHHx_s G؉g!R"U%aKiȃ*-h:0J$p^˧5`PxԸ:=Ui !!! |»Y"s.1%<)'$$$dE*OMl]2}j"BxAVndw;Xtld-'\45]Xk>H@5gs 0],ZD$iQ"ņ`y? B`Y-R 'H!Qf@ckQt0H\464EI(2 WI|*iF*T=JE8T0gVH#= ̪zrF~j*IjI??zV0P)qAQUi%= *z4)He#Ns,KJG/JUv[iHb-28?W; jI0V<4<6hx(X9hD:RFf P/)2^ɿ4wmb-2$?xx=??Lz G{)T9#+?22*ϊ+He3 Y*J,Oj$Wj\42 ZLVݞbR# eRB Yj1'AGG-Oł~mz.zH,zxYb۪d:C%2+yybN%LURx2ֲڂ`7k ZY0Chw?r*FtrX}ke!>7 xE Y#6k2 J`d:` py>|'Jj_O4 Nl)Sj)HHHʧ`)"R,ҡ +R?HH 1؊& "!emY}tXh>Gba 2(mb̔Mwt-l&d+2ǓmU}&RQJJ9mV4K2`OevM`ن#1me95W(ј_-j0e\/It>Xf!Sh Qvm26f> L` c+t'jq:̬Z.?, ȉ~NHHe *̂I00b"gg#"%$$HfV,˴2nůyC\cЭ*^Ydi_\He% 2+2+u++XenZ, l$ۄ{4?L)ᄄ&`]e%GODVv~G/˾DԜJT/ pD,Fzv"8P,'x#̴i"cw$lE*w (k<:|WB= m+.鋲 lfS)ΌHǖ'*?NhR#g2R/>b |0k#"ۑ`.ZBC$/ K>:Ka(I¼YQAq+:C٠(HOlud uK#Ya" 5~7~*~I5'_,\/F!O#,K$-^wnJ0~^; IB5dH,4Cqu_@S&Bs4=H,4ڙ~IENDB`perfbook_html/node270.html0000644000175000017500000000432611672746162015650 0ustar paulmckpaulmck B.1.1 smp_init():

B.1.1 smp_init():

You must invoke smp_init() before invoking any other primitives.



Paul E. McKenney 2011-12-16
perfbook_html/img89.png0000644000175000017500000000157011672746136015246 0ustar paulmckpaulmckPNG  IHDRS2d0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAThY1o@~_4]CQR, F2B"Heg aAKX+!*102"u!Lwmug7IN|b?g'0.rɧyIT ry"v6ZK#^@@R(=XFun3b.Kc&!_".iu afhBeGbOEf:!ynrTmPETP5ï UmxH(QEE* z38GMW9M$ȾUOUmh|UOJ*ʅƪ:TKQU:dN9opk#ui/fD^m:JTGtPVw$ADZJeM[g^vl׭e?aoJZ si M߽_ >vpCReW7m3ûYXU zB:1f~VspIWb~d/>yP}¦[œ,DBV?Y>Q-VЦs^IENDB`perfbook_html/node432.html0000644000175000017500000003230511672746163015647 0ustar paulmckpaulmck E.6 Promela Example: QRCU


E.6 Promela Example: QRCU

This final example demonstrates a real-world use of Promela on Oleg Nesterov's QRCU [Nes06a,Nes06b], but modified to speed up the synchronize_qrcu() fastpath.

But first, what is QRCU?

QRCU is a variant of SRCU [McK06] that trades somewhat higher read overhead (atomic increment and decrement on a global variable) for extremely low grace-period latencies. If there are no readers, the grace period will be detected in less than a microsecond, compared to the multi-millisecond grace-period latencies of most other RCU implementations.

  1. There is a qrcu_struct that defines a QRCU domain. Like SRCU (and unlike other variants of RCU) QRCU's action is not global, but instead focused on the specified qrcu_struct.
  2. There are qrcu_read_lock() and qrcu_read_unlock() primitives that delimit QRCU read-side critical sections. The corresponding qrcu_struct must be passed into these primitives, and the return value from rcu_read_lock() must be passed to rcu_read_unlock().

    For example:



    idx = qrcu_read_lock(&my_qrcu_struct);
    /* read-side critical section. */
    qrcu_read_unlock(&my_qrcu_struct, idx);
    


  3. There is a synchronize_qrcu() primitive that blocks until all pre-existing QRCU read-side critical sections complete, but, like SRCU's synchronize_srcu(), QRCU's synchronize_qrcu() need wait only for those read-side critical sections that are using the same qrcu_struct.

    For example, synchronize_qrcu(&your_qrcu_struct) would not need to wait on the earlier QRCU read-side critical section. In contrast, synchronize_qrcu(&my_qrcu_struct) would need to wait, since it shares the same qrcu_struct.

A Linux-kernel patch for QRCU has been produced [McK07b], but has not yet been included in the Linux kernel as of April 2008.

Figure: QRCU Global Variables
\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...

Returning to the Promela code for QRCU, the global variables are as shown in Figure [*]. This example uses locking, hence including lock.h. Both the number of readers and writers can be varied using the two #define statements, giving us not one but two ways to create combinatorial explosion. The idx variable controls which of the two elements of the ctr array will be used by readers, and the readerprogress variable allows to assertion to determine when all the readers are finished (since a QRCU update cannot be permitted to complete until all pre-existing readers have completed their QRCU read-side critical sections). The readerprogress array elements have values as follows, indicating the state of the corresponding reader:

  1. 0: not yet started.
  2. 1: within QRCU read-side critical section.
  3. 2: finished with QRCU read-side critical section.

Finally, the mutex variable is used to serialize updaters' slowpaths.

Figure: QRCU Reader Process
\begin{figure}{ % \scriptsize
\begin{verbatim}1 proctype qrcu_reader(byte me)...
...rogress[me] = 2;
19 atomic { ctr[myidx]-- }
20 }\end{verbatim}
}\end{figure}

QRCU readers are modeled by the qrcu_reader() process shown in Figure [*]. A do-od loop spans lines 5-16, with a single guard of ``1'' on line 6 that makes it an infinite loop. Line 7 captures the current value of the global index, and lines 8-15 atomically increment it (and break from the infinite loop) if its value was non-zero (atomic_inc_not_zero()). Line 17 marks entry into the RCU read-side critical section, and line 18 marks exit from this critical section, both lines for the benefit of the assert() statement that we shall encounter later. Line 19 atomically decrements the same counter that we incremented, thereby exiting the RCU read-side critical section.

Figure: QRCU Unordered Summation
\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...

The C-preprocessor macro shown in Figure [*] sums the pair of counters so as to emulate weak memory ordering. Lines 2-13 fetch one of the counters, and line 14 fetches the other of the pair and sums them. The atomic block consists of a single do-od statement. This do-od statement (spanning lines 3-12) is unusual in that it contains two unconditional branches with guards on lines 4 and 8, which causes Promela to non-deterministically choose one of the two (but again, the full state-space search causes Promela to eventually make all possible choices in each applicable situation). The first branch fetches the zero-th counter and sets i to 1 (so that line 14 will fetch the first counter), while the second branch does the opposite, fetching the first counter and setting i to 0 (so that line 14 will fetch the second counter).

Quick Quiz E.3: Is there a more straightforward way to code the do-od statement? End Quick Quiz

Figure: QRCU Updater Process
\begin{figure}{ \scriptsize
\begin{verbatim}1 proctype qrcu_updater(byte me)
...
...ert(sum == 0);
54 break
55 od
56 }
57 od
58 }\end{verbatim}
}\end{figure}

With the sum_unordered macro in place, we can now proceed to the update-side process shown in Figure. The update-side process repeats indefinitely, with the corresponding do-od loop ranging over lines 7-57. Each pass through the loop first snapshots the global readerprogress array into the local readerstart array on lines 12-21. This snapshot will be used for the assertion on line 53. Line 23 invokes sum_unordered, and then lines 24-27 re-invoke sum_unordered if the fastpath is potentially usable.

Lines 28-40 execute the slowpath code if need be, with lines 30 and 38 acquiring and releasing the update-side lock, lines 31-33 flipping the index, and lines 34-37 waiting for all pre-existing readers to complete.

Lines 44-56 then compare the current values in the readerprogress array to those collected in the readerstart array, forcing an assertion failure should any readers that started before this update still be in progress.

Quick Quiz E.4: Why are there atomic blocks at lines 12-21 and lines 44-56, when the operations within those atomic blocks have no atomic implementation on any current production microprocessor? End Quick Quiz

Quick Quiz E.5: Is the re-summing of the counters on lines 24-27 really necessary? End Quick Quiz

Figure: QRCU Initialization Process
\begin{figure}{ % \scriptsize
\begin{verbatim}1 init {
2 int i;
3
4 atomic...
...: i >= N_QRCU_UPDATERS -> break
21 od
22 }
23 }\end{verbatim}
}\end{figure}

All that remains is the initialization block shown in Figure [*]. This block simply initializes the counter pair on lines 5-6, spawns the reader processes on lines 7-14, and spawns the updater processes on lines 15-21. This is all done within an atomic block to reduce state space.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node420.html0000644000175000017500000000563011672746163015645 0ustar paulmckpaulmck D.4.3.1 Testing


D.4.3.1 Testing

The preemptible RCU algorithm was tested with a two-stage grace period on weakly ordered POWER4 and POWER5 CPUs using rcutorture running for more than 24 hours on each machine, with 15M and 20M grace periods, respectively, and with no errors. Of course, this in no way proves that this algorithm is correct. At most, it shows either that these two machines were extremely lucky or that any bugs remaining in preemptible RCU have an extremely low probability of occurring. We therefore required additional assurance that this algorithm works, or, alternatively, identification of remaining bugs.

This task requires a conceptual approach, which is taken in the next section.



Paul E. McKenney 2011-12-16
perfbook_html/node41.html0000644000175000017500000001167511672746161015570 0ustar paulmckpaulmck 5. Tools of the Trade


5. Tools of the Trade

This chapter provides a brief introduction to some basic tools of the parallel-programming trade, focusing mainly on those available to user applications running on operating systems similar to Linux. Section [*] begins with scripting languages, Section [*] describes the multi-process parallelism supported by the POSIX API, Section [*] touches on POSIX threads, and finally, Section [*] describes atomic operations.

Please note that this chapter provides but a brief introduction. More detail is available from the references cited, and more information on how best to use these tools will be provided in later chapters.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img102.png0000644000175000017500000001115311672746107015304 0ustar paulmckpaulmckPNG  IHDR<ZPLTEb``^\\\ZZMJKPMM# hffywwmkkcaaXUV856iffC@@744wuv.*+pooa_`vtttRNS@fIDATx] -ٍ}$bk"rr*: j}+ZHR|]fPͨn](k2 .w3J}six.Zf`0Y@lԒue=R!NƪHoo@aT'NB ;>жV#ߎ!R;2 nfns"=)PRq }p'WTUgPCæG[֬\VŻ(GvT_x*ܾx"bOԎA֑CJVl T5mJ-Wel1 FoyHB 8~/ϸ"j:-@3U.ZWSȬa3ŽPYf 2|sM}:}*vvGtb[? ?pk$v`_ݵ^Ŷ%=]{~^TUEAǵy^76ܭdQ1"+:+L*'B-^ԿN[bDy= ӱSdPA_a!L"S'H\<{Q8Bu-DArszX/NU“'oM=ߣ|&M;tSmᢳ଻U*jOm͢' λ \El(V$ ,9U+-oB,{7 .f䖌#v6,30soɎes!q` @N @>11r> ?z{kSH?A+{ (߳bM%F9 C?{jgBD7pq?*Ū_%e1 yvd*ř:b[0jyv"$ЙbxRտY%K5:tOgq wr /kR6yG#^c'Qi!`$QůB 59uBQ JI_dET~R#:~XB˥4ێ1-Vo|/.O3bY儻rF:aՖ|ƒŖ8pE+>kǸoI^< :BXRLR8'*2ꂁi)<$D5ǜI#G'/.'r6$L]Ꟑːȷ-(ZXlZ1=!)I% }oh m"ޞRPZ11O6\xfyɏR_1  MY&cMn<)X5 Q5Tg>-KUC^V+x^76eeQZˁ3qP{i\#럪|0}zl[n^RVC&_ NcMM9dBڙܪ+I)r¥,1{msx"$-<2Yw&J&{.~~"~! Zڦ gš 4g bey^RIRx7  2+c3¬aTtOrDS$J}N~Iv  #nOen:(HH4`3- _d+tmQL- 2sխkd%fF6/$gw]e=rΤϲr(峤 @MW/׏@)&Qr zz<&#'(rxmJQ5Le>'ՂNo+G9+N*o%&= h-4M{m8{;Vw6Zqx*4{D8_8D|OEmU౤o. lyjMr_: |nHd.q_ ,<<^D~)' G׫&@HIiOz2 rl螔I]Ϫ4[{v"{nߖ,/?+C$`5kC$8p0g&m&ņhPcƁVᳲe9諤dgb.g 3.5.2 Sample Source Code

3.5.2 Sample Source Code

This book discusses its fair share of source code, and in many cases this source code may be found in the CodeSamples directory of this book's git tree. For example, on UNIX systems, you should be able to type:

	find CodeSamples -name rcu_rcpls.c -print
to locate the file rcu_rcpls.c, which is called out in Section [*]. Other types of systems have well-known ways of locating files by filename.

The source to this book may be found in the git archive at git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git, and git itself is available as part of most mainstream Linux distributions. PDFs of this book are sporadically posted at http://kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html.


Paul E. McKenney 2011-12-16
perfbook_html/node20.html0000644000175000017500000000632511672746161015561 0ustar paulmckpaulmck 3.4.6 How Do Languages and Environments Assist With These Tasks?


3.4.6 How Do Languages and Environments Assist With These Tasks?

Although many environments require that the developer deal manually with these tasks, there are long-standing environments that bring significant automation to bear. The poster child for these environments is SQL, many implementations of which automatically parallelize single large queries and also automate concurrent execution of independent queries and updates.

These four categories of tasks must be carried out in all parallel programs, but that of course does not necessarily mean that the developer must manually carry out these tasks. We can expect to see ever-increasing automation of these four tasks as parallel systems continue to become cheaper and more readily available.

Quick Quiz 3.13: Are there any other obstacles to parallel programming? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img306.png0000644000175000017500000002135311672746073015317 0ustar paulmckpaulmckPNG  IHDRF^EPLTEb``MJK# hffywwvstmkkXUVROP856KHHC@@wuv.*+q=!tRNS@f IDATx] E*eoq5V(QD=. h6ȍqۇKsh$t]ml5P[Eͦ o<7K'E:tI[J[gHf\u/[%BR6/u:7~׽8tl4ꊙM4T߁EAe6|mXCԶvU:-Lw.3V>.$?uÍtj8z0ˍ}iwml#qdqwCZ5RW4 haBm4Gi?={ֽ{Jh5p{T'GڷBʮRTUk򨓾W]!5kV!vm+<乡Q i\Qt/TԪP*tA>M= Wn>t[;y`N D/?SkAUEAW- Uf@(TefqX~ Wq.`pB{!K;I~t%HR*xgv,Ami|tKK|ZO?[iᲖ4ʎԛjR_5vV M _*\beqH n# _SPp>#5f[fPSfƖ2L3F.8E-ͼQPvJ錝[K|4p0` ~4dn>Y\l+ml ڴ"m?*[M~0#~ ;CJY.Vlp5~vĠJ/1'8+gl]y] Hps 4RY(B5A8A3 N9u_wj=8.KɦνteO|`6B%F5Cx Dy\g2|ك4 4cksz]3t"vpɗ{/v' m*?+3^d/0QZD-H0G=l ;WƴS<{H`Z)A=+4r=vXpa^At z4#$NxDTc+&?3|1op?jyf r . 1ȂjB}tT)?@k崥N)"1.NqSI a ?CZK1Iy* u7Cwo;cOR$qv~ %y8صdȬs"B;IX"ԑ#{'-\sX۸%2௢ԋ탄I u)< hs5;Xk-w%HU]].k}gt#U%(+O/d JeYМC{d^Z: oWQvT]9z2-x*17a^ DS׺oI4e;ƌύ~ %RGXaܔㆀ8Cl}9}b]" >_ő Z`}B2iq!c: 94qSH`-iChFmÐV )#/fj}?(+!u`sngTx);I+F oPEN[]2"!n[RXP+ Hq,JZ|׳л䊐x>n=7D ]Hc`EMb rf!ݕU?\14!h{؞A)nF ҎȖ k‡Raм$ aI{]7iG' uIH o6F3Fo*g8B'y]+=X(r|y{.S-c2wwmU)2,z ufv dd/`9}A;\ҭ8--sQRgJ<F%QUmv2~pyuNWHs/ZtA_HRG}3/p uuq'bqTԯCڢiUbp!dO噺ɯ]qi`?ȯ]~/ǐQyd1Be靸39QsA) -.9l)՘*ʴWr<Δ XV2 X"aE*0<5㭝;cw~S$qOkIv?:1~t ڠϡE;N3R[o5čTM<L* }r܍?HbLݖޯDЯ^s)c䮰,Wk%&K_1δ/Ӛd;gdF)nG<;ӷ 餝Vwdzךufaݪ5kJ;ᬢ(_&ut-nN.=D$rےill@:"\SԹ_}mb1{~;n9(|ULNݯd* ԽE&L8e ,bё}'42)Sq u񌏠*4W/ ,xb0322`5Ld-…a[z,fD0!ֹLPv %`KGD99P #yxbi?! @XG <~M"O5g>00IdAcs0x%Ѳ¶U(I hcATy;R.,)K>sOkaCL/P3F kMgxDuI\xLXkHZ!5|:qk[k/₵Fm_g|=&jv鮚ۭ z a#J@'v V95Ϲ%ִxձ}i, )g-#Wi ,d# vZQG%;ed|%,f̩oM--} xpַ0V}J3!Ih[dm\#} oַ0v_i2G%`4-<}[({ g`5 P7hY\T}PطPBѠopE߂+5[zU7QTM%maƯ0 B/E#_ni]s m V4FkwDh~&v+Lf][9.VB+$uNf8W*D JO|-HH1G$jP T3 >1q4 ͈$G،=6nFP/F<|i; Լh}ݒ_w"jtv?0##42܅1[['y߁#d[GҌ;"ٶݧЌtJNИ&L)ʦf."46ƱT9kp،f?|fd.S@5ػ^X*9ʯۊdd Gg03Š~01!%Z&Hдʅ93322|~ NTޭr_6De'4Z9FŞ].j,nnw>up Ani32222.4L%tL VBe&YLE͵6 |lpJJx.Q̥0(OĒH]9TV~oG |8æ4C^23V%mLe51V( |1uak(Z7%R]Jڙ{Ҵ{eh1 ōwt5ߌ& @,ľHL⏰m$]Qȍ ې=ҟ;MՕtͰ  }/ 8JT);?۞dWj|zy$)flQ6֭ZRTB H{87peC8K2E۽!_j, Jfddd\|mކt,Wn*Z_ ؍~t|>z5c_"QD9`3vvR *~!m_2_L.k_vԍ'N L=A8HY؋aaӲ~8ŗ%vxx)H T QcaD>'6cC3A$)Ñuڌ?ZKGFoFDAfKn+`DPvr~8A5)[/RΞ4DRtwx0J?$)bDi'9pgAQIN%? d~nG-w)!%Uv! Ǯ-({W{c :@w0*6#ό7UUK! !%aS0H6g$Ŋ6no3nD!£>%aJKČ0H%wd$HSqdDWfR- ZFBo6/3BJ8#OIe$) ÌT`@yE1Z‡\#`D! 1%aKă0H%wd$JGE܎) uptJof"ğg$ĔaFB,ox@BJ8#!*n_D\מr"uH) BCͼ/} Gmjbn ,N96˖NzxVZLm49 7"-&6f<#ekv, CJ56]na.ƺU#!i\AJlPڮ%x+LYZ!/ %? 3;m5mu?GfoF6qISiŀӞTBRV+L\wҌ KK陃+ gnp=%i%u]/)җ5 )##g~5ɧn,;rXtט3N81‘DRa2;S'kk攜5^Cs0bHIDATL͎3x)kd>y҅ݧ1|1gSG:naBALrOY?%}#zIY,aYAXښY{v?MEvֿW32΃ϧaϓ"yq?K P{S&e%>9Mg{#Ψʤo322222@ ]IYÁUHJ<9,=z9k@IIȰp c Qh 'xwIYC3T#2@7:N:g.eg-v>zR c ioDv}zvVK$y#e %NX6C`g=u\0vLʚ,;_'e;% `v<%eev7c&eFofdddddΫlXBp"WN ~.4f;NyP/!8zg f<,'fdd ?壙?D@!)k^QfneN23NZA Vjwl*̨IENDB`perfbook_html/img100.png0000644000175000017500000002416611672745767015325 0ustar paulmckpaulmckPNG  IHDR&"kKPLTEb``TRRMJK# hffvstmkkZWXXUV856KHHC@@A>>@<=wuv.*+mjk*tRNS@f IDATx]% \1?PU`4ф>("P?bf3Psӌs(ew<ǚt'M)ZkʍWn@e:jji~$.M:LtInfb-~ֹk?$l8=@mZKQkK(\~5WJoxMu{|- OC35r_p'ynM{\6p5lhj#6p1xnd,ٝ7hQ?[J|S_8G|Tq,?w̓>S0/-طcb;`6XA UbXM_q^^/~{mS>Aɷ􆤮̝jV .Y*ϓ*T8eV+Ǔj+%K|kj2d|e ,Q-*c˻ň< \+M^5eB,N g}kPM%ӝSjw_K{z}_Mzӯ=M+o} Y ]H'\#K|i[0wwftG쎋=ڋ; K2Q|`w2:$x8qr s;0Q Zr7r +gHqC8\3 a.* q j~VgNߞ?'PκcGWF!_)>x3iDi{j5gE;W筅o7 +kD+U3yO54kOI&OyMgI*#vD4ݎ2&YߌvWP8j+ wP;+oaN ,WBgt~5J(3'yiBj'ϙvڮiێi[h_y;:_zk J ւ9b8])+c}#xaT)VȮYkP|OڃaU;;PvTИRzHj^ˁqٜ!-#\Jc`i(=d!hW1y1d6ez%Y:="x-\Ye&Ku@] Cy K#DϜ:Eml1\k$Ko;uـ#@jѧne$ Yva29k6^Uj:O&\H/;^_oI B48?WVIh6+ڔ#w0oʼ>x5,P|FޚSBsboil1mA3R|[Ch%oT<,+WryiGFtI)Fs}w63r~q~x}1|Y3.C!tP?wX;Sqݭ'=wA^Q:++j֡#)]*,1!8nЃ'Ӊ֩aЩ& ʶ8Jh={3E[N TNJ'NT X5BT/ۃ1y%,Htn?86>.h^U5>֟{?ė.C5*Mt_LC*EC6cA]f )p"3ئ71kk^Zl}џ:` ̡o 6ow46wnMz^(=L{㸋[;qqq*^pu$Mo<;wx7+7gyemYգwI{6 hˤUQ걷잇/g X_8aɲ=s*R;UqU(!#i݇xt4'jGRin)r{=w;xaտ9ɪy4iv"Y6UnQN|IPm֖ҰpmYr!u">23mve -ܶ,m-(33:\XY係P5[2I$l.YbՒB٥6QkTZnܧ.VMZUuto0&bBC.Hg2u+Ib.R˂ VV?!6?Uts<̻c WޠDOi1Xxw^VMxx )~R; gg~JaZ&!OٽU <#ycYVg8\tS;}%/y%Au[M :*9}6+޻jyw%Ц,\g S&i:,aOM`3; 3;氯 [ftiΔ^iQ&%h$~*}Q+HxAtߋ+tHZ/D'=ۧ^ڛlZ/qWg7/ 7s=L3jᒤspOvW|Q`mƆrF9w⢣O =DuDl ̚:&2~\k%ƾrsn'&~nMڋx$2#!Ry \H#q 4O HV@n\EXW-筠t `bqI=@iEBy'3jy!ek) T#*؁A!c /;(&r9O|4zQ훀PR9'Df921prDqdS9 ]W ;35x@ǍB `m9f2ߋ?Г͓B+5j 1E!Ԗe$f3+ #զtK<}Lf{~Lu @]p$ ^/[t~U `杜9hT^]K =om"9m(b.}'?M` c !)1Rrhea(;_4tRfF ~<{rBNL 6aq wBܐJ+fVԕZR1Ù9cNfkbIFĪ&WHǡa:}mfAA-(Vyqhϻ=(".Ï,t?V9LN뭦J>-ϗ ͙KH!6t*NU"<RYfyqA9c,pUzK5`c77bB[~{^q{2 +HT<ӅݶJT -yyv.4E 4S/} |[olԛG_NΉw'Ҁ:J`}KȈfIvxdK6])X!#M+}Pk69.?Z~*VHtHhv_ i&b74( 'iue+=g|N~4Gl]j 7D>'?s(Wn> &t |]<BP116,O1 dE ~yhwZҔk).\KjC:ok9lvR~hUב^T+ks-Ļ Amn8vx݄5rӆ[ro5 k:چnPq+2o^ ZaT^VzMee4BtY Wcgtg-e}mu$W@͖k 4JaS@Lr-x{ ޠ߾A^븐ϽqjIsh9o+k y<-x NGvkls.@Ƶ76ށ/͹L7Vqԟɞ6Ⱥ~^\R򍀧)̋7Qc>-lm REO8t߯S٠Ԏ>ƛY5m#&b^0.y:it( ᙂm&ς^\(.䥃qN/䥟EoESY5@]vzk5Mq4hUs*)( vGM Qhۻ ys7m,GR֮2퓸M['e0_6tϸCm&6Ly@x_7D~wӒ01}4%0C7rꕠkH>(ԔvoH BeOwnm5eF`cЏF󶦟^ v̠!L5)勀b-](߂(ݕMh h&7| oZRM%wu~*Y\NrkGe[ix&WH+9:Pw@儨DR{J[է`noB`7yo`h{{vU)˩t=eouhrFo<RmcI|fU ) ji%^ݭ7Ruh9xH)x[2ᢅi]L %DZĪ}𰒎uɚ0<rJH-@“5 2y"kGK/v.I:#b,Us+w\îJT"q-=lj'eIw,`M`<2uv"!;ǁ{GJ~g#庐#_?Nގ1J )h;a~1=~RnMMN.vc ƑWk%G mh)c=h6/3ѸBmYK~r 0Wk썻wDr]ZsD-T 7ӳN '3lBMբ<[6nrN޸ )o7ܪhZsW5Kі"?+,xe;Xٲ[Mᘼ͓L\^9yĆ9ӗ}}$:c/J7u!/șڰģ9˾ϯ =2c)!% %`Y}S~ 8Pҍf4ݹqr9sSbeFe}7,, \v>9ykBRn%"+C[.-zJ}߿J+̃pYɈxrׁx3"6]J0 Rwu{lP0?/ʱȃZW n7Q=rbcPmSrvS@sF l򞬫lݠ@@@]ρcPfyOWz)9|mq~%>Hyd:|go7~k%W(</uvoq,ANޛ~oJ`w/Oi>2&+Mh9Ҭ3&OJJCrZW^D2z&+᧽߂st?k:q7uM! D.1.3.2 Initialization Implementation


D.1.3.2 Initialization Implementation

SRCU's initialization function, init_srcu_struct(), is shown in Figure [*]. This function simply initializes the fields in the struct srcu_struct, returning zero if initialization succeeds or -ENOMEM otherwise.

Figure: SRCU Initialization
\begin{figure}{ \scriptsize
\begin{verbatim}1 int init_srcu_struct(struct src...
...);
7 return (sp->per_cpu_ref ? 0 : -ENOMEM);
8 }\end{verbatim}
}\end{figure}

SRCU's cleanup functions are shown in Figure [*]. The main cleanup function, cleanup_srcu_struct() is shown on lines 19-29 of this figure, however, it immediately invokes srcu_readers_active(), shown on lines 13-17 of this figure, to verify that there are no readers currently using this struct srcu_struct.

The srcu_readers_active() function simply returns the sum of srcu_readers_active_idx() on both possible indexes, while srcu_readers_active_idx(), as shown on lines 1-11, sums up the per-CPU counters corresponding to the specified index, returning the result.

If the value returned from srcu_readers_active() is non-zero, then cleanup_srcu_struct() issues a warning on line 24 and simply returns on lines 25 and 26, declining to destroy a struct srcu_struct that is still in use. Such a warning always indicates a bug, and given that the bug has been reported, it is better to allow the system to continue with a modest memory leak than to introduce possible memory corruption.

Otherwise, cleanup_srcu_struct() frees the array of per-CPU counters and NULLs the pointer on lines 27 and 28.

Figure: SRCU Cleanup
\begin{figure}{ \scriptsize
\begin{verbatim}1 int srcu_readers_active_idx(str...
...p->per_cpu_ref);
28 sp->per_cpu_ref = NULL;
29 }\end{verbatim}
}\end{figure}

Paul E. McKenney 2011-12-16
perfbook_html/img45.png0000644000175000017500000001304511672745762015242 0ustar paulmckpaulmckPNG  IHDR3]/J`PLTE^^w<<3wUww3UUf33"ooMMU++ fDffDD"D""-tRNS@fsIDATx]낲*=eZ&FST0P ֏).w6`1pL~ p^\ nḵ(υ4BE{R~"](eBH/!< cy2DP+(W^՞}|.j{ot~(яGԏ]Fp|K?Y?\*oFpRҚ%칕2~$Q>Tp%~I{R1sw>7\U 烏6,c`6X[v;h]`#b3 VDq嬺!VW0a ,0o-xS}jքL;) ¦QBX0ʰ;PЯj_DuKxPyE 0u7QPHY2k[}FFTR*L`Uz>`fQVLlb Ƶmж6,5C֒^Ѣok6l̓@̚8Ek=gZo1uӋk1`jrݳɾ[Q琪SqTZk$ӴӿK315 Tk3iuYަt R!,n1@ɚ~ Zn} s/l2Օ|`OW֔dkCnϽZAe8s0enrIkј9QkUƔInufY[[ιLQjҜF4k'[K&Y26g+YĩTڹPZBkYWqT.? ȹ'mPƝFFlNyѦI?FsHog֪44} Ji FZbJ 2I"U|ojIh!PyBd>*PskF%?I@dFnXO*z Qc9Ĩn-h&0%qi:W;8!ՠm&+ PPVܤT,-hYi7YY୉7d5C&YT0amRYjtMȸ,v H5C d^gؗ!gͽoemF7]k{Z8Y",ԽzۏAk`lj*WzM\k 77q1h7< Z̛<{MY3 ;`ըjʚT4mjaklddZw6ϝh~FFU##S֌S9[NL&"g_6yX؇r{j\jLQ##g  B8kEjP.?΋Dsf0A9ɾ!z>I/GY>[jwD/J ՗<@mBŽAs_ZPA/V7y-EUոQwUP'-\BgP &hnR[ZOc .%۱/Ayo Mr\ }o^=y[luhĸ2`˒{&%mh' 8A9~ l qkCZD_`W|=;}| F{ecϣ & M򍴟^OP]8)Q[3|a׹ =yA@ϵHMX htAVuvF[UZ PSk ‡봛֠vk  ̈́v1ayTKOSeiObpcf(uUo=UÅ[-d}L .nV+lqګ^㸭⬝G $Aqg/q}= GJuk@uok?%o Ľ܅U'śꔿm^;PnyjchߕP"ovPhW  tr=.Rcm蘄B"x8KU l}qQTI<"5Q.F`&#)j]8Fw9Fw9Fw9EKpZ555QAQAQs8A=5OS~!5 <3L1gyfٿL5Y\]Se5`QV{$3+`f2lGė} 7\1UPݫ_gk{_-/ik3@woiLc!3>,5q˪*2-* rbUmevX]LAɰ6%W6v<5O E&Îkv9pgaǙNY@1xjB1f+=;-f6IMIMuOj9]uYZ|{جtiF(5-4荡Qf]xID@x hKĤH('$o1zLQM6wx?l p2!,tP;C& Sn 5J<[.q"v}ޛנHك-&a;Hvfee0Ŭe|2}qO2"huca-m lQ]|bF QlO}gd"ECFPmSʏX3Ht5-fU"3Z֘iE?1q_̾VXg&*T-Դfvh)::XLP`ov.~[b;vjw[c3O˜3ߊ KȝJ wЛZC a67r6eE0ȘDW{31SkLw (:y{ }m]|af8ڢM;n1p3wR2w GS>V:әf!.c`6uwevjr7^aflNtWd^ ]`)ʸhʸw%@we\d|e)VƉif2N8O43qyřa|ˌ?1fՄjCl sjZKz,bvb=fF(XcvbB3_MaD+d$8낎.2Af^.24 N1[7YŌwFŬ\X7]Ŭtt>sۚdFG75Լ8l ; d[s-f:p.ܹn6W֧ʵ%W`dYc'&~լw)f;N1qw)f;N1q5m[;N1qYgS:{wblu8Ŭw)f;N1qYg[<33<33#4Xu~% }Ms*G/q &CFǃO-j_}8^fI>%kB"Jg)wᵭhv!wufnEOPfwZ` jɀ`fzEsh&ak'`y#TYf",H3mDsGr3汘 @7..P0٣^:75je&+D`Wnrowd'%,BZf znJD$!LcαZM ޺5q㇌fϏy2s;Z*EJFJׁs׸_e)̷8%1d ү4jE*2 UAR%#Aĺh!ds{x&)-BͼOf): m \*I2 %Wa(j ݏ|ŀu| L/&9* d (  4;ǟPF??^=?L f v+.w5I!j΃LAnݒ?*v33b0jh~\qy/ׯ@495H!<?ٱGiv+>ߧNڀof#͑P.a !bv|u{/4ej'c˯yaak%S{v_ci@sjif5ڊ}Q%Ҍj!%fiux?XcdݹG̬?@} :.OA鱆c'f>gRm4Ӡ51 b ~ 쟇l.-~q>Y^i1\3ٴLlZk&L6-5k&hƶJNh68-f?cS{!>3 7lVG3'giqա? %p.+u?3Ϊffiq74kXgƍLϬ?3=@r{Fk8=ͬbNtfz߮3v kf8[¥^>-{d͟ 3]FZ؎0Caއb;Füvy->1Zlhy>|>`lOJ5KA#nC Oݦk`?c ~׬LhN;Lr^|>f|sL|sLH81Z5m5m5m5Ok;Fcz}3)kvaݳIk6Yqc>毥߻c;Fcɽ;cfk>fk>fk>fk>fX!;IENDB`perfbook_html/img224.png0000644000175000017500000001375211672746013015314 0ustar paulmckpaulmckPNG  IHDRM)EPLTEb``MJK# hffywwmkkXUV856_\\C@@wuv.*+rpp@YW}tRNS@fSIDATx]FJ}G,l&oP:L6 -]u/FߨsRw4g25:TmJI/r^ќcE릢֑K`{۳~inἨ?BRLлt*.jYu,'y)B<@F>=tWlcU)ըielmjn{Uya+ {u׵'o cV5&yn⾁cJ5?^3RFy-W]Gt*9/W:UD@@BӝY_H[1wd&,bSm) Cll1P|pƑl5fgsT+q-w~߯{:q,؀ Pn*Bj gLSPk-i7?4P?.X.+fuOz.Akծị\߈la*Tr A lEns ᨀIHēpv͝:Je\DW+%ݿa,ټhh3oiLH#-Q 0d"o ;<Thm~xwNOyʰZ0"HȳBCPՕGEԺܶl.,C2ZoG;:Qb@Q8;z 5 y:CjC!!(<2z'[yMu`r@]D^U+cVjUDf5V=j;-VSfZiRW0<&YզNХlnwͫTE<̆K!o-}Tl< b@}OVwJکwYv7e@)߄vخ6kr^J\2^7vo4ƢDYt>Th`Q{=5=rЄ>=TK7 4\궂)SaGU ~jZPֆhe ܋NtUR <0N(ʷ*Udj>qxAP㙎PgAMCBp1uHL, :U֕QpPo74>yۭ5whbR=A7Yz@dCeXĊalq|h٘rJt\O[+|7i|T(*SVyyEUUuV} ':otV:[]uXUE4&xoǬe{y_ t,*[a+}i4nn|S Tctwh{<ٍSuĴڔy,s L!|i&/6,AR geauТ(JfiV$jcH?67r<3|ɨK53{ԇSOZNzJ9̙۾Ψc;mQe+E6̛1AKܦFɁ0'CiQxj{RhP-Π 3*1SFeЮՠTb@{j,{ڦmQt]o18c+*Nayz:UoTq:̽g* ~3Q=sd9`h;)(2?:R''bxC+m_O)cYO]n;6C$'t*-Poh`p*I2jl꣍o_EJZrmE!_ jzƁžճ#r ovrZ7Q♴ob/ݶTuu !9krҋ:On P>[}w[8u&DC~3+P&^0<"#{nPi>ZsXJe tJ /TCWyB(0O;NPn2H0gZ ו8֡g+\Ra*zj5҃ox(\| 1 /}N S#,:'5hWdJalPd#qW4]#K5"ևߍYZѴj KKJژʹ^Þm{8#f)̅Eig5l!V`64"AYU{+QLDFFq=o-\7qe;q\@,(d32j;b(wLhjhOYr;2F^IHPQk'M,z1qie^C,p4 GOsN=3;UJ~ڷgϝ J0ê $o|f ZP*S%PhiW7MwpG5 2*2E3EE2%rpU<,dJbd+.!pDQ-53Ua.dtM@`2E؜ɋ?iZΫxa/vo۳\f+}o4`&.roNC\KogRozC3^1>vvca>v2>W;pKN<-M<8\M< \Xu 'R?AfQPs}%H vP~%P  wuƊwuG rCadJ`6(8tYjyWטF "*Tsd:.;t~~vT5h0MQ98J6Zwzi'pr4Y=(;) f6lLuxhcKڥw_o -<\'`%,h=4 3%6<;RK]°u/f3;M?72 }BҸpF_-˞x;β K׺ܰN:j3%ٸ䜁ʴt7f.tXmeu;(y:XVgIgx؂D ۡ]5(-Lp .<]$}܌`ds[iനmҜ(y"3VyƑoHK fqkx=Uљ 'IF~`ao@TH.\p,͌b#)'J#*/Ok^κe2RdQPe pCABFjFMNgFsq\RZ&)>,\Im|:1Re =aWg9ô OB#d&wN\3nONff~`X (BdT"`<Цj$IFXCr4}HfQ"Rg@;Ȑ_ƒx|Y,y {ڍq|u)go`h4?hh.gF.[;mh4ܲ.Yм,oػ&^tDd#GP| 3o7 Ceݐ,..49N.Z/lj|AOQ`.ɦߓ5w)2T3)_6~A˽…ot^w7 ij]aa"vO/ܑjǥ8lVesP|NgQ-cfz$l3:e`KC[|(T_qPل|Ni3t莆tw:1+3~ CCLkXbtg#SweLE2g$uES׽^L]wo۬\]%8,Jż9f d`k4͖eL9e&$ѨC,Gup.;Y4GnD9<{؛_M-n\<)h7Sk ;S' bXgo w *w K\xgv*}*+iAyy; 隹븼i\ PòY鐎NK7v4 Q׌VM2/>W3pVz}!*x $ O1LkK؅8ƥ.Igۢ:Jd i@,N3FE|7v)q!y:[h%3G"g9(<'BZ(Yv6&\3FÔQ;፝1ģ}Vx+.~ V(w?"a ߍfrKlv8ruzfa9:4Cc2-(':%=ۮbuIk*gL\3fa> g>s5c99Ca\3ޒ>D1 O,MU{3&U1{;s=ihIߘMJ?L}y;py;Ӹ&pM̎/w FCiwQu2f^Bύ<}<{μh06(9[bw &C\^/qy2㲳/Ů)sJ֭RC։1 1ϓϊGBWþJe )%J;'H78H7D0آ,`ίX|rk]?j3i䶾 `IENDB`perfbook_html/img69.png0000644000175000017500000003004411672746062015240 0ustar paulmckpaulmckPNG  IHDRPla;6ZPLTE^\\\ZZTRRMJKFCC# b``ywwmkkcaaXUVVST856KHHC@@744wuv.*+|zzmjkCVtRNS@f IDATx}ڳ s-m6[+,3 FM0/{?Q r氆5ԫgFvptmC#߷V4e>=cٶ`{ ldMg5<):jP𵖵iOhSC}bt\,$Pq%5> [5X㳞ҋy~v&v=p1?k(R~-.i!eƽp*ZŁ1!Ìesviv1MzN-KS/JoA(yu2&{2wv bZ#'7%;(9}F\;so;;vo+꼥L4Ӳu0 gM|8 Tlqm%?k[}v6-?zhS &%sa`~d}SL tQ mdq"5E3X-͋t W0X;OdUkwCiFxG)Ȥp&-ZDcCfݳTmY65%K1nP쿟}KFOkE:F,@yGvqk Rg"z4@1o16q3<cPf 2r&h?xno޺^<6"bdߍY`#Uׁ{"g ƥgڻ e ]},׬l@9%$Snn{Z[M&V(^as)YQj(t+Vb'2q){jvX@*y∔{eDAZS^foJ-_&B 0^u: m48鯕,f>Rh.vpNI_7UY&NU$~y+ -&X9o:xokO8ux;1 auP4=5^ډ.R1Qپaa]زA1[ Svj><2> 5EiSnPl!c0{V$a$M -yFtj͗Ql\G6^Sa_Voj eS+()6I?(iQfo6}S5p^>%nͶL^TPo|zj!(Ig kmMmʊ=6|<ߩa8wP.3n(R2_Zpgq *a>sPq -%Y9.ɦڵ&e8qfSh2Uvek_w@SU%7TM㐪zzK Si%%.ZtϻkalrR,qɧe+FL8b 4P'IP:e5/V4[2^ [fLVjP AohQ-9 MyUmk&)#zYdJt܋ M`X[ehTkuVN\1"L$Bd!jP-Ɍ^Dߠ TmzdxV `(z|̨1ќ)94)A?͸vJ۸~CxCGAv1 ܴoۛ'6,/V@`@5R+/O+K+hLz.ХS=GyEiI8ɱ#Fufj5 *F3K.VWt&[HW#=_3 8 &2=e'K[AEVť٣yTGV LJЙ@xCr:M^:@8GSDTTQDML8QVNC͇f6c':{yq"ԭ@Ppp IJ:}5hѽs MI;vQ,:1/ը`o; >o^[>d"ݾ24-XQנH5ڣLݺAÅu P(Kc]jYI_[S7*>r_!c] N& psɜ%'o?҆P3dOLg 1'1OcL{US œ?Qat©U;O?әě`'XQ<7U@}:޴oUHjMx^ti%6)("D(! Q?? A07F>ʧ91ЉYmNJ=Nۣ+(|tu* ک[u;q5m'f}% r}4m2Z-[=e0"l4&KR-"/||z| ?@/ iaf<[^^q5 gKygwYw`?|ZiTRLnF2%ޖ%M͢OM]?d?-MfE#G29VBX4DAȠ^W:颒_?zy 4:m P9_^UsԵD9R7feH;6KTffjUXӦ/2kM[0j|7f(vgۇ.+M; [bW2SEKO'[] Ԥn pg8 :LO<8vo~yUٹ⮏7}}L)Y4vYed!h~ ;oR\N?J tڠIpqw4POue6T|d'#!|B*]z`* T V "CٯP5f"RR{f.%O?*m̃M ua/uɧ Р/!{]w)[`$ Gt& cEo@(IiDȢ(f#$q 4.SNoWQ|ٴEtX>UɾoɾE[*d &Џ%gQfZҬ1͉o*`cشj8aFQ̭a6^Q-?EkToӪρ@ާ鳥gQ3pLnI_/]%AvmVjKݘ@Hp#r.R50CkbS ¿ȴc/)jsaý?2KQ36]oxˣ_Q(ތ!ĢO jf03g]5D>Xhb~QXhNy2͘p@_1maBfoWlQvXq[T_0!_~@~ M}5P`jx_qF%^fm!{mV"CUSo_kV=Fʴ0K5뤑{H_z[ HQ2}Lp~*mfEt&[$ӿ=&.&cr}Q 22T=SF,]>5}ug5b}}g1f$|ȯۏcF+藠[&p)LHfa2sܡ-AJQ5$'i 3JýAιYH KְC[z+:Gոn}ޚgrZ10Wd<^;X! Ixl2*fяȣ(Jd2B8ecɜ+Ar~_Ub lWef "NŬAlW!ɽxK@F+ђ7 *6\C"x 5~*=N:>='(pٕ{E4mFƝhy2ߟz-} #vq}])9W}[{YPc@#zFj`}FzUuFex& WTm4lԡÒ?f/u<ό*5UӚ( mYZQ0MjZ*Cz [3cz)|=RkShG"h0,pu#ƺLʈ8nJPzf ON^$2Ab5q2]Df~5.YDi $LjfNg(/'GPq}1浙E+J{q<>&ޔn"ưT2˾f-{ƺ|"[pz4pbW, aXBŅ!4)!dck;< UьD!c^ t`?&&Y#fC2RF g`/[yGP Xm"Xе"ѩAEzK" ZY En ' ^ePђq\vK8~^I;gزp66| aw?:M-KH=6J]PY!UgB*hl!Ag@%:U-]pຑIi&v)Q sp6plF?6ӥ6-Q ]5xYyDc *o mmU)P{8?|B||듗1j~ϵSb@A:[~甡ыA)tRcʓp!J|(gŬXS@  `r(5J bѡeˢYVuwe'n2]ʵM h>l^ZOoBoBiz}̸=[y\*dv8Hkk,EHzM#ԕG{ŴG%4qѤ,}Y;[V[=Gp#ez3=H`Y8h%Hgi*zGiλobk VIdPڣUM{="=9R\Nn#=O XڣRdi2AcpDLjq "iIĐQ KQī/uyJ38dE@[^^i#>(zZizWi2.Y1%xtrڣ`ygΥO6#Jh>dL>uA˧L~W>͒L{>H=ԏ=ii@~DcZg ҹEAY3XG>b>P60-0-|eHcZ(#uT1EGُ=aZiIiRO n#l|ii2>'ix=R.-ī}?e e$*7aU&<}Q}_p^>vb$h6 xO؇?joBj+֊wiۥJ᩟ר;_V0-,%2~d>bH$e>u\FDfi,_ fCV# #ypE>G!^_cԉߝ;{1 M{I{4ӏG [Duq9O&^P#[zr^b\??zk__=\4nr[짏E@% \'ycf{AWp{͵As\K}lUkUW梑-xH,@'Q+" <ϾyZ&ڗ%|ݷJr1x5 ͼEt7誶 Oz"g$5o(2ͲڬEJͳuc+38=p#KE!xZnJQ}f%QArof8)_Xn+m4's8V! Ûo63Aꥀ޸@~mK -ZNLT/{ڤ +E9(/#? Ԅ4& }R㣢sƋ; CN4*>y#oE `FWȂf(M5Y`XZj&|ѱ^MX30c*w_B22<NOĠ̔dddU\+.zοXۉ ~hLExA$)*-x BRFf55T- c0njgYsęlXqcC3K\C\rp'kt[aEdm3h^(F_EYOZ ǀ HO)`d; 7Mx3nԥ |2HUC[Y:I<8PlIDAT,!1򠓝baޑ8;/Qo߂ޚ.3: *ԏ[Qj=Ry.$rI%:[-tUBRXeJ4*KYԥzCch^gY;qRG}:xl>E?^j,4R\qg=ʢ4^TxޜrVquƉ ' 4TiNLVh1;k;Ahr=,BMˤ3/|@+6H\Kރq"#ׁdmŴp h.bW&,Hխ><.ml6PH[) 4].lKQ#D5 <%b]],FAfd$+7r>?kTf%'{ _ѵKo+][hp]w}E_ξsdЌoGƀ?tP9Ni R8h~/T]Bh@H::|Ń$V~ӷBiΫDq)cRpC >7h|BOF~9`]ڋc!TOsl$)zeWneS4 y(G@ҳm3I)2 t "Cq|FFƋk>P9Rd >r ]@Iw#2+j/+T")ԮANv.2EFAk3LvKAj4h\+)i6D,9h<" h&84#=X U3&l',҈ zj&8PAyI'^R` ]}x-ڃx E /xkd j%[VBWb^@oE<Ơx zҋY ! >xNsKցj% w2Օ؇B"NME$Uc hUA7 g 9M7 <ؔ-&3(ˉDj@њm? ]cH9zgGI"H)SXj ˄jBdMWڥ7W|l J1dGF׹MCo7&ш?2pjBBUC32~vƏN0[3eddddL B٤{{{%t7GG&|sn'^Ҍ/QOm"WǾ؛XD^ur_G܎n;ަ^~'~9]hu{ ӈ?-YЌ?~>x=2K H=C' w-dd嶂y%4rxs E~0:RDXv(ږ]6 F{,i+s7{Qzg~?aQ8^y) k#4Ƌr$ȑ@ +?VL޶2DXKkk0 H9*:׆@ Dh_T`w422V1oGB'@"BȘcYK4"b\{kZc?t"5Z 9] !<KlRdF@ݵ?-KI-n Z Z4KΟ@#tѦ݆iDgefq0GK \.#B:^AK"5Ymx'Po's:Hv<٥3rDo#!h@М( Cs =9QjFc3YY]S&io%###b͊p_eFŕsuf囇NU1X[y,bœ2?E}H#d4gz ).8eGzֈfWb'@ +IFB\ɁB#O*4|gs5u2Ǭ'7EMgdlFݰ-+u͘dқUEH6x(1c3>zmy*] qWiyIGidB 5tP,Nq@?vp]x@Ny'z!E A}[TO/8X͏SiPS-@v5n#mN~F6rKQ4{០T!>OߠsToiBsŠGgVn<똝W`A YҖ>M>kdx0$&iWu/ 8~@㡧6NZc4jZ`IB[#j$qvoQ vH}G,?}f k:&[dΠig-pU,`XݔHEEFUqZt8dcZP̛F@ NT|ܖ[ck+sh9_ҤW3lh83e-%8 6隒,gijX?m?_L,XL8ZU̺SIw|lyаAnƠYQ|x"S"" 97e JqT0VgȨ5ZSaHj34陲 c i\puDaZF&~̬&ۄ5;_55~ZAlu0=k P+=9Op_'g e\{.W"b!%F9 `%(gh(fФـJ;~v}|v[)QNh6O u 7z iH&Cn:PjO%A,t`SBȚ/CҪMd>w ]W]]vu-ti9Narq]ƇO59e=t`2-v1* jF,**Ml3E$zÑ)LN*\A4g;-\}':ҏAH5؋,=/6UE J0B Mċ%qa;~O1%+;a6W4fqaF7vIJ!me EHx+vM_|bx`[%* t6~Cځ%.A('-O-1~F=iYT#p"#8ݮHWC5t'Ҡq&]w|bHؔJY_5-Wf;M,lKݷ_k?-xT@1:*JфJLdݕan[6du aͲm^Q>iMYbZ˫" ZCgsYUۀ 1UAURUT'ÂoU-юUޡ&)6;ZA&aZ:@FeKd]4)?TbQ߰6wȧlL9Hz Ug4'8B Q y)[jiT&f>Aѐ#AvT? (CMnRSGn>N=SLAN}SS P.Jiw^awk4 xuB"f7m= KZAg, L^^O-U_0+}NO{SxI7d Ѐ$IK<4mߖPWtU3 eE+;q4_eߟ{ +)slmbڢ FpOŪ B aQerԔU K{SgسQg@7ei^Hgs" =>dA/^'usEv&R5]M+,fY\?L'(%PE5A>\OPaG2U/*[wɾ*_f\%#t<n\8M.rk\nL#RnlF5j9CX=MƝV)j_=һ*ƕ,X-CewU7((bĴ =8DkڪA~iyE3bV@ ƞq-'ƹiA*3.a i;UJ2uWkZ3_g#7f*nJUmU_I_VXToͱF;Tqn[RA66&wDu)PU]ҤxƹF`߭FoȤuYŪҪV4ZޫMBP"uQhXl&ݸݢRr.Ų#oqRPUBNiٷ+^?bIk{ӷh'ӲoHϹb~6jћ~Ɍ_"0% ͕kaʽD:M.!4&K10.eشv{V~ 4@)S'-RmbYh}q/"Vݘ%5MКW=y O2Mcx=q hH^2Ʀd>u%HQS)u<'GtOoh 7y{*8A[ҋBϠ|hǭ$}y&rYM1Ѻ5=+ 9ʜ?+zm-uohwr4fiTMMSh-+9KQWM.Mj=:rf<-r⭮s}v#˸/!֣O"zU~u+UWw_푭_Xn馛~(ЪSfwߴ[鶘g̫ڎLw!|+Y'9qjSuGj밮2_&Gƾwh؊yML}' ?sɡ9XStKWz>YXVxhЂ_ qrCb~֦}!;_x|>*0fX㔁? X]zhTD(*ޔ@G6Un0ئhvˇoNﰳ}FTxuWR͂͠\ZSuMRdf5˭P@pX.tmWӖ8|Uyk<Ԡ~c+Yʎf7b|s:I,W%"h4V&y*\.+Ђɒ8: 0Zy_YԾf:eBq\ 7?6YH|x7tMrn)xD.V5|ܧtz O*Yz}!vWol'‰glU H# p֐;Ⱦ\M!Il+xUZS;V 5ex/J5ZlGN܅}+ʨ2cȾ\MJ'JYWh}QL A=畕XګR$HdD9MgDU,zC>A*#gm~pߘ+ PSҊo'?ey"r.-2] *.KbPRāx,1]\9]kVRƾ) 8Nϊ2T N*n_{XŔ/νW |} wa=1%,-qJQg3\U4n Fsof7~ٕ$0eT*H}3/EQoA9t0þ"7cVbBVv{JK˨}~~v}\1| PwŘӫk|7筨LqŰ߂I&tc'=n\\Px? vYzTF%&q^&!7낰pWQƸb5j%PlJ^/#1ƐoZ'{lle\}B WC\g(_Y2jMF^IENDB`perfbook_html/WARNINGS0000644000175000017500000003642511672745743014770 0ustar paulmckpaulmckNo implementation found for style `lscape' No implementation found for style `subfigure' No implementation found for style `url' No implementation found for style `ifthen' No implementation found for style `listings' No implementation found for style `hyperref' ? brace missing for \framebox The perfbook_html.aux file was not found, so sections will not be numbered and cross-references will be shown as icons. ? brace missing for \chapter ? brace missing for \section No number for "MIPS/Clock-FrequencyTrendforIntelCPUs" No number for "MIPSperDieforIntelCPUs" No number for "SoftwareLayersandPerformance,Productivity,andGenerality" No number for "TradeoffBetweenProductivityandGenerality" No number for "CategoriesofTasksRequiredofParallelProgrammers" No number for "OrderingofParallel-ProgrammingTasks" No number for "CPUPerformanceatitsBest" No number for "CPUsOldandNew" No number for "CPUMeetsaPipelineFlush" No number for "CPUMeetsaMemoryReference" No number for "CPUMeetsanAtomicOperation" No number for "CPUMeetsaMemoryBarrier" No number for "CPUMeetsaCacheMiss" No number for "CPUWaitsforI/OCompletion" No number for "SystemHardwareArchitecture" No number for "PerformanceofSynchronizationMechanismson4-CPU1.8GHzAMDOpteron844System" No number for "LatencyBenefitof3DIntegration" No number for "ExecutionDiagramforParallelShellExecution" No number for "Usingthefork()Primitive" No number for "Usingthewait()Primitive" No number for "ProcessesCreatedViafork()DoNotShareMemory" No number for "ThreadsCreatedViapthread_create()ShareMemory" No number for "DemonstrationofExclusiveLocks" No number for "DemonstrationofSameExclusiveLock" No number for "DemonstrationofDifferentExclusiveLocks" No number for "MeasuringReader-WriterLockScalability" No number for "Reader-WriterLockScalability" No number for "MappingfromPOSIXtoLinux-KernelPrimitives" No number for "JustCount!" No number for "JustCountAtomically!" No number for "AtomicIncrementScalabilityonNehalem" No number for "DataFlowForGlobalAtomicIncrement" No number for "Array-BasedPer-ThreadStatisticalCounters" No number for "DataFlowForPer-ThreadIncrement" No number for "Array-BasedPer-ThreadEventuallyConsistentCounters" No number for "Per-ThreadStatisticalCounters" No number for "SimpleLimitCounterVariables" No number for "SimpleLimitCounterVariableRelationships" No number for "SimpleLimitCounterAdd,Subtract,andRead" No number for "SimpleLimitCounterUtilityFunctions" No number for "ApproximateLimitCounterVariables" No number for "ApproximateLimitCounterBalancing" No number for "AtomicLimitCounterVariablesandAccessFunctions" No number for "AtomicLimitCounterAddandSubtract" No number for "AtomicLimitCounterRead" No number for "AtomicLimitCounterUtilityFunctions" No number for "Signal-TheftStateMachine" No number for "Signal-TheftLimitCounterData" No number for "Signal-TheftLimitCounterValue-MigrationFunctions" No number for "Signal-TheftLimitCounterAddandSubtractFunctions" No number for "Signal-TheftLimitCounterReadFunction" No number for "Signal-TheftLimitCounterInitializationFunctions" No number for "StatisticalCounterPerformanceonPower5" No number for "LimitCounterPerformanceonPower5" No number for "DiningPhilosophersProblem" No number for "DiningPhilosophersProblem,TextbookSolution" No number for "DiningPhilosophersProblem,Partitioned" No number for "Double-EndedQueueWithLeft-andRight-HandLocks" No number for "CompoundDouble-EndedQueue" No number for "HashedDouble-EndedQueue" No number for "HashedDouble-EndedQueueAfterInsertions" No number for "HashedDouble-EndedQueueWith12Elements" No number for "Lock-BasedParallelDouble-EndedQueueDataStructure" No number for "Lock-BasedParallelDouble-EndedQueueImplementation" No number for "CompoundParallelDouble-EndedQueueImplementation" No number for "DesignPatternsandLockGranularity" No number for "EthernetBandwidthvs.Intelx86CPUPerformance" No number for "Sequential-ProgramHashTableSearch" No number for "Code-LockingHashTableSearch" No number for "LockContention" No number for "Data-LockingHashTableSearch" No number for "DataLocking" No number for "DataLockingandSkew" No number for "SynchronizationEfficiency" No number for "MatrixMultiplyEfficiency" No number for "Parallel-FastpathDesignPatterns" No number for "Reader-Writer-LockingHashTableSearch" No number for "Hierarchical-LockingHashTableSearch" No number for "AllocatorCacheSchematic" No number for "Allocator-CacheDataStructures" No number for "AllocatorPoolSchematic" No number for "Allocator-CacheAllocatorFunction" No number for "Allocator-CacheFreeFunction" No number for "AllocatorCachePerformance" No number for "SchematicofReal-WorldParallelAllocator" No number for "Locking:VillainorSlob?" No number for "Locking:WorkhorseorHero?" No number for "DeadlockCycle" No number for "ProtocolLayeringandDeadlock" No number for "AvoidingDeadlockViaConditionalLocking" No number for "AbusingConditionalLocking" No number for "Per-ElementLockingWithoutExistenceGuarantees" No number for "Per-ElementLockingWithLock-BasedExistenceGuarantees" No number for "ReferenceCountingandSynchronizationMechanisms" No number for "SimpleReference-CountAPI" No number for "LinuxKernelkrefAPI" No number for "LinuxKerneldst_cloneAPI" No number for "LinuxKernelfget/fputAPI" No number for "DataStructurePublication(Unsafe)" No number for "LinuxCircularLinkedList" No number for "LinuxLinkedListAbbreviated" No number for "RCUDataStructurePublication" No number for "LinuxLinearLinkedList" No number for "RCUhlistPublication" No number for "RCUPublishandSubscribePrimitives" No number for "ReadersandRCUGracePeriod" No number for "CanonicalRCUReplacementExample" No number for "RCUDeletionFromLinkedList" No number for "RCUReplacementinLinkedList" No number for "RCUUsage" No number for "PerformanceAdvantageofRCUOverReader-WriterLocking" No number for "PerformanceAdvantageofPreemptibleRCUOverReader-WriterLocking" No number for "ComparisonofRCUtoReader-WriterLockingasFunctionofCritical-SectionDuration" No number for "ResponseTimeofRCUvs.Reader-WriterLocking" No number for "ConvertingReader-WriterLockingtoRCU:Data" No number for "ConvertingReader-WriterLockingtoRCU:Search" No number for "ConvertingReader-WriterLockingtoRCU:Deletion" No number for "PerformanceofRCUvs.ReferenceCounting" No number for "ResponseTimeofRCUvs.ReferenceCounting" No number for "ExistenceGuaranteesEnablePer-ElementLocking" No number for "UsingRCUtoWaitforNMIstoFinish" No number for "RCUWait-to-FinishAPIs" No number for "SleepableRCUWait-to-FinishAPIs" No number for "RCUPublish-SubscribeandVersionMaintenanceAPIs" No number for "RCUAPIUsageConstraints" No number for "Lock-BasedRCUImplementation" No number for "Per-ThreadLock-BasedRCUImplementation" No number for "RCUImplementationUsingSingleGlobalReferenceCounter" No number for "RCUGlobalReference-CountPairData" No number for "RCURead-SideUsingGlobalReference-CountPair" No number for "RCUUpdateUsingGlobalReference-CountPair" No number for "RCUPer-ThreadReference-CountPairData" No number for "RCURead-SideUsingPer-ThreadReference-CountPair" No number for "RCUUpdateUsingPer-ThreadReference-CountPair" No number for "RCURead-SideUsingPer-ThreadReference-CountPairandSharedUpdateData" No number for "RCURead-SideUsingPer-ThreadReference-CountPairandSharedUpdate" No number for "RCUSharedUpdateUsingPer-ThreadReference-CountPair" No number for "DataforFree-RunningCounterUsingRCU" No number for "Free-RunningCounterUsingRCU" No number for "DataforNestableRCUUsingaFree-RunningCounter" No number for "NestableRCUUsingaFree-RunningCounter" No number for "DataforQuiescent-State-BasedRCU" No number for "Quiescent-State-BasedRCUReadSide" No number for "RCUUpdateSideUsingQuiescentStates" No number for "RCUandPer-ThreadStatisticalCounters" No number for "ModernComputerSystemCacheStructure" No number for "CPUsCanDoThingsOutofOrder" No number for "ParallelHardwareisNon-Causal" No number for "SoftwareLogicAnalyzer" No number for "AVariableWithMultipleSimultaneousValues" No number for "Memory-BarrierCombinations" No number for "AbstractMemoryAccessModel" No number for "WriteBarrierOrderingSemantics" No number for "DataDependencyBarrierOmitted" No number for "DataDependencyBarrierSupplied" No number for "ReadBarrierNeeded" No number for "ReadBarrierSupplied" No number for "ReadBarrierSupplied,DoubleLoad" No number for "ReadBarrierSupplied,TakeTwo" No number for "SpeculativeLoad" No number for "SpeculativeLoadandBarrier" No number for "SpeculativeLoadCancelledbyBarrier" No number for "Lock-BasedCriticalSections" No number for "OrderingWithMultipleLocks" No number for "OrderingWithMultipleCPUsonOneLock" No number for "MemoryArchitecture" No number for "SplitCaches" No number for "MandelbrotSet(CourtesyofWikipedia)" No number for "ShavingtheMandelbrotSet" No number for "``After''ProducerFunction" No number for "``After''ConsumerFunction" No number for "``After''ProgramSampleOutput" No number for "EffectofLockingonSnapshotCollection" No number for "Locked``After''ProgramSampleOutput" No number for "ThreadAPI" No number for "ExampleChildThread" No number for "ExampleParentThread" No number for "LockingAPI" No number for "Per-Thread-VariableAPI" No number for "CPUCacheStructure" No number for "MESICache-CoherencyStateDiagram" No number for "CacheCoherenceExample" No number for "WritesSeeUnnecessaryStalls" No number for "CachesWithStoreBuffers" No number for "CachesWithStoreForwarding" No number for "CachesWithInvalidateQueues" No number for "ExampleOrdering-HostileArchitecture" No number for "MemoryBarrierExample1" No number for "MemoryBarrierExample2" No number for "MemoryBarrierExample3" No number for "SummaryofMemoryOrdering" No number for "InsertandLock-FreeSearch" No number for "Whysmp_read_barrier_depends()isRequired" No number for "SafeInsertandLock-FreeSearch" No number for "HalfMemoryBarrier" No number for "SleepingWhileRCUReadingConsideredHarmful" No number for "SRCUAPI" No number for "SRCUUpdateandRead-SideCriticalSections" No number for "SRCUSafeCleanup" No number for "SRCUDataStructures" No number for "SRCUData-StructureDiagram" No number for "SRCUInitialization" No number for "SRCUCleanup" No number for "SRCURead-SideAcquisition" No number for "SRCURead-SideRelease" No number for "SRCUUpdate-SideImplementation" No number for "FlatClassicRCUState" No number for "HierarchicalRCUState" No number for "Mappingrcu_nodeHierarchyIntoArray" No number for "HierarchicalRCUGracePeriod" No number for "HierarchicalRCUState4,096CPUs" No number for "HierarchicalRCUStateWithBH" No number for "HierarchicalRCUStateWithDynticks" No number for "GenericRCUStateMachine" No number for "RCUStateMachineandHierarchicalRCUDataStructures" No number for "DeterminingShapeofRCUHierarchy" No number for "RCURead-SideCriticalSections" No number for "call_rcu()Code" No number for "rcu_check_callbacks()Code" No number for "rcu_process_callbacks()Code" No number for "rcu_needs_cpu()andrcu_cpu_notifyCode" No number for "InitializedRCUDataLayout" No number for "rcu_init_levelspread()Code" No number for "rcu_init_one()Code" No number for "__rcu_init()Code" No number for "rcu_init_percpu_data()Code" No number for "rcu_online_cpu()Code" No number for "rcu_offline_cpu()Code" No number for "MiscellaneousFunctions" No number for "NotingNewGracePeriods" No number for "NotingEndofOldGracePeriods" No number for "RCUCallbackList" No number for "StartingaGracePeriod" No number for "CodeforRecordingQuiescentStates" No number for "Codeforrcu_check_quiescent_state()" No number for "Codeforcpu_quiet()" No number for "Codeforcpu_quiet_msk()" No number for "Scanningrcu_nodeStructuresWhenApplyingQuiescentStates" No number for "Codeforrcu_do_batch()" No number for "EnteringandExitingDyntick-IdleMode" No number for "NMIsfromDyntick-IdleMode" No number for "InterruptsfromDyntick-IdleMode" No number for "Codefordyntick_save_progress_counter()" No number for "Codeforrcu_implicit_dynticks_qs()" No number for "RecordingandRecallingDynticks-IdleGracePeriod" No number for "HandlingOfflineandHoldoutCPUs" No number for "ScanningforHoldoutCPUs" No number for "ScanningLeafrcu_nodeStructures" No number for "force_quiescent_state()Code" No number for "record_gp_stall_check_time()Code" No number for "check_cpu_stall()Code" No number for "print_cpu_stall()Code" No number for "print_other_cpu_stall()Code" No number for "BuggyGracePeriodFromBrokenRCU" No number for "GoodGracePeriodFromCorrectRCU" No number for "Classicvs.PreemptibleRCUCallbackProcessing" No number for "PreemptibleRCUCounterFlipOperation" No number for "PreemptibleRCUCallbackFlow" No number for "PreemptibleRCUStateMachine" No number for "PreemptibleRCUStateMachineTimeline" No number for "rcu_check_callbacks()Implementation" No number for "rcu_check_mb()Implementation" No number for "rcu_try_flip()Implementation" No number for "rcu_try_flip_idle()Implementation" No number for "rcu_try_flip_waitack()Implementation" No number for "rcu_try_flip_waitzero()Implementation" No number for "rcu_try_flip_waitmb()Implementation" No number for "__rcu_advance_callbacks()Implementation" No number for "__rcu_read_lock()Implementation" No number for "__rcu_read_unlock()Implementation" No number for "PreemptibleRCUwithRead-SideMemoryBarriers" No number for "PreemptibleRCUwithGrace-PeriodMemoryBarriers" No number for "PreemptibleRCUWorst-CaseScenario" No number for "PromelaCodeforNon-AtomicIncrement" No number for "Non-AtomicIncrementspinOutput" No number for "Non-AtomicIncrementErrorTrail" No number for "PromelaCodeforAtomicIncrement" No number for "AtomicIncrementspinOutput" No number for "MemoryUsageofIncrementModel" No number for "ComplexPromelaAssertion" No number for "AtomicBlockforComplexPromelaAssertion" No number for "PromelaCodeforSpinlock" No number for "PromelaCodetoTestSpinlocks" No number for "OutputforSpinlockTest" No number for "QRCUGlobalVariables" No number for "QRCUReaderProcess" No number for "QRCUUnorderedSummation" No number for "QRCUUpdaterProcess" No number for "QRCUInitializationProcess" No number for "MemoryUsageofQRCUModel" No number for "Memory-BarrierFixPatch" No number for "Variable-Name-TypoFixPatch" No number for "VariablesforSimpleDynticksInterface" No number for "EnteringandExitingDynticks-IdleMode" No number for "NMIsFromDynticks-IdleMode" No number for "InterruptsFromDynticks-IdleMode" No number for "SavingDyntickProgressCounters" No number for "CheckingDyntickProgressCounters" No number for "PerformanceofSynchronizationMechanismson16-CPU2.8GHzIntelX5550(Nehalem)System" No number for "DataFlowForGlobalCombining-TreeAtomicIncrement" No number for "Per-ThreadStatisticalCountersWithLocklessSummation" No number for "DiningPhilosophersProblem,FullyPartitioned" No number for "ConcurrentRCUDeletion" No number for "UsingRCUtoWaitforMythicalPreemptibleNMIstoFinish" No number for "MultistageSRCUDeadlocks" No number for "DiverseRCURead-SideNesting" No number for "DeadlockinLock-BasedRCUImplementation" ? brace missing for \url perfbook_html/img8.png0000644000175000017500000002114411672746004015146 0ustar paulmckpaulmckPNG  IHDRKh^PLTE$8D6SfD:UHfVlqqqggg̬MMM*3-EUQ}c''' ""3+HoZ|||we~tttsZZZ ݻ@@@?aw444u݇,tRNS@f IDATx] tiz6mDcݤu[l2 1I3OMTe>fzPԺ`u$He o".Z 쵤>ԭT?Dv'{?>~%%"bUqNx%#/o,<ţ|#|=w_:ю%GK+/s?(ybTޙv8N@|  2 8hG,"XQN p 1VTzu񞹈0$ -GS{_dɦ4lI˗9ctVUWU~cd**g릎dEplSǟeGP3L)[Q (|$\T:Y ǤsO1gO~ڷ2i܉I&؞g C/Boe>3It'&Lz%!淊vV( 'b1(:P9H1C}zSuooa{2Cu*>n?)=INǗm;OTq>l yn늧5%y'}; E.אXy-H%*.-+ԟTLj 2^lX*b,H0'ɎUy/O+[7(1LÌ"z#%QBBBTn܌Ʉ}׭-y4dN9f1Yf9sAI$o;ȓ8 N. zR2gBCq`CjZn [Q,&q;"gFg"jZuy<(M0aFwSN2p'0q_;`˒9ܒƥ!.#̘"u֌=TwMDp swLb$.ӱ8(c Eх$w j \ 0ڦXCKC`iy٬ իSOD!h8:f3|/=y) Bx>Opa zz:p&7'Y-R|4 ,SJO<Mz0=h8jGK $itX>{U0wR'ar4' QspYP)-rLeMGgL~v95B wfTtɆɉT9H\b Rziȉ\ kri>ys/ q*z@5I,˝G0+$k_췜׏6;9~7ں1^s&R|/w:=R~XÌK^Z^M,&3P \< yzXj(&AY!It-1BmDope/{ŏ+\G1Rh_a[vgFH2 -`H/ȉXk8}=F3(?0{p/6z>nNix`,N#sӴp= xܓUv0>ϲfzSKE9$?\q(ܦ;;0'_V=X`ڪh)"+|[)@K*#b+(e!y gɍ/=Zk2;n8 0Uvǜ=aQU ,b0 A6cJA0{G4//#%7Í3W|5+  fr@Ke(gBG=ed~x`YOrqd?&2czҀZyeT xov7tiXGKA%8)wwUT0|εͿ-kAˍ0c:"f7i wx3I7ć a^1e_`ĨzxAJr\kזI!Gx[AˬZ_3Z8V C-W7`2D')xxd]u̢+drVvӍMx٣@IYlo^t:0yl8GpQw]_EQ >P Jp.y">)E8twalfA4C i1-x o5! #Rf(l@o-j- dXĐ[†{5$4qAq&T$;,)8fa,navfۦ{J_ԫߺ2C;_,(7-/M?qC12$ΈVf3vX9"t gPBck\㭇+dtJ^Xaw_[(߭}"dpSq"dG {YI/oߝVeKJQrPu%Ca _.{\p'lSCS~$Ʈv k>,Ca=8S:nh"-m*wnײkGa~d.pvfi]4Upv4 rC9&I r ^ǿ%\e b/ xc6>ehJ hR*` ]t7gh+k j4LGyWo&N7Mꙕ]} =xiQkؒE9C9xtNdSQ.s2J E9fk^m'0 (-<`p}۸]6ǣmA>.nk_97σ eIjBI]BQlphEirq!vp (vQ,O3Vf)3+ W8B(^2Liun'`^f&/'.2Av"1lXQ^wC/tQ>VP'MخAl!²Ͱ5C/O/O?^!B^nOcS<A9N\gMNUE,tĨqTp3q"0J7ĻD TJ)uJRpz9Jey [yԫoGM/$2U=hTD4ų Y ,>@By,1mNe@ g,d)LӐ5t|J5n3CM0ϓN@)$eź9NP$Q3^x[rE/EQ"d ݍĨGrDd_0UDSA4-'[uWLX?+\i , -tZb8EhYKZ&iw>y"[Ha)jSwH*%zir0w0p JG9 | 6/iKl³YBQZp|y9fxi%t9 Mg WLp &T.y k?",*3T]1k 4pXD@@A0!DtWPr>e24e ^mAN$)rКTY`V˴`TEtI\ vZV`jxVN 08sI6^_Xi֍"eȂ,`S-~9/Vw'|62ja;hPh3Xv#g` NI=9EʄAraf͊m%tz^~يDR^NR.S{ۋ2xQ1҄A?§jLfjD wsMY{DԬ[ͧw3KpgYNH\*=aԼLdac\RLp9; މ|OD>/v{z{zy#n2/(/cD4fQκ`IQ\8%V !Z+k֬ث@8S?2t=L* ,n~BH@:]XUR1I!b3a2dio "US[)r!.Tv en&@HqN)wKi@pL\b0X[ eK,_bMm˄rhSv Z+| E*xK<\YJ{t)~H.DcY15ڹɋ瑋aV68zv6GF`77G7R&CrǼ Qtps!d DH#d'I|Db!70GciਛSF9eh-fG@NsvP4ܨn8ḭnXynf geZ~>5*)K^<$QV0pޡ|X\îbYw>L"\)l҇KzwzqVŀ)xAu[~lj3_p:bq$(0Q|w8ǃ+| r Ceء{"koY|\|@q@GRnX8eʇKyw"AsL8wy GςD~sHbVKʇKzwaXx&xKG<"+/hHlOdL; \KAF#o?]/j_b|N3k0v%0ǵ8_K[*oRCN~C`'ߞ5E_Y9F.un-=-cx]^r^6_o~8_srnu[ܔ7wxWƯNt0>L~󴫖Sc:v=;a)ض߼suDKZyhS;}TW S;∔;^up/ _=)u;|wa9Yf&mL2d:NVs[XvXc*$H{.""wߛ_X.:alRynq+rzK o}9w:|wq¹i+-DIjw>$^@LZ.niɺঃrsc9)>++XM.OHU,hBq.qtWM?O8/Z?#2)56,JS/%qrffNpn99E4Ca9,]RͰqiz:/Aьij8/IEz9x9ﺾhn^ܸX\O/[}1^^,t;$7˅zLJ] /_7p}DTp\#+7s^V"GD0/=Ԟ"D@stRzЎ@s=z8yy}|z>wuv.*+~~rpp- tRNS@f IDATx}ë.ieASEcs=QD cPq(e6q~w[ U{T_Z̓ƒK`ԓ?r>jj?M&#ъyZ Mٕ=:uvheo '.-~Ƶ[Eװxy#ÞF 0Miji`ʆ 6"Ś*;^0Vgd ]QEtǼZoDv0쀪٥sjJ_aخ>^;=2[3oEm;kR`L΁.)Ffzꃃ7 jS7dlFM|)<Ҹ]zGQw;E)r};tN&!Db|i1Q/X72iy8+״s?ɵI?' Y&DphEćШݿ;pЧy‡;Z7nݸgw[c0tvv,{PRSXNi'yXnS/qn؞jY 7zvS,&|ie>^`[{v!q%ۜn jvqw5Q^ۑ &Gk03Hu!ZOf4Na<N0@8K*'qj6Z=F/Fپ]\QbK{-#yg $~pb-j͹4=mСovKV=x Wi{ڡ(z PqxV ەڝQ{waҔZ'$#P6ȟHpdbg[ʎLךөk3َ1DjԤ+VJQ5?yW!=U'Rgw#RWD?0nx9%mZn["?f7-Zm(CK-K RCDjjLĵ!^MMC 7(g J*+yC#&YL\#%n>~)[j4"~ +oq Xhdۉh|@`m+03oj*ТB;\86DۄPY sɩQ2CvjO[xZfJ{a|HalT:Z\Ri fh(6IP .|>;/J,mv~sl*tTXNi^ע+\K[bnZP [(KA;x ij&||cD1U&۽(Tg!Gj ',x YDQ<9fv\3ozMc 2|k*5';!R`zK* c5čV~Cuݠ'~s7@J6$vk>(MM\ |]&>C8 rL ST]-랳=^x_#' YBy%(EL'8OîV`! N;J-1bVzj=͘RoV\"zENM!7}6-?i%$3.-ca3 -RV9N#e 8M\Q-*+%}nǾ {/@1 B@()iS:30skrˢ#p^}D5-z6!3!\`3{Y%n'"BX߅CA,M2L⍬/EkVqIs~F`ntĉZT@R$v&@_Fu\_g:/]͊ WɐvIT?[^_5D>CX0TZ Uã+LKK+V-U_bB_ a<(S0 VN׬z2\vF),Z>a9z~-k^"iknnVUr7*Uвƽ>oE?J>XAv:j h/X=Gks@w꽏8QuRs} "" )9rl$ؿƧ26keCeF+D G֒y*%/q FH-V_%7~kuD|׏.!D։T)uxڨkƍ^f/i"~ԃ_f9Hv:[{Bź6;YRRhkXiكAOYm- 9ր9cd@ÈV̞Bq :jO(d@Fkg UxP};c*aqJ@0sjIr};dv_o̡~ ~4UM~)Ѳ#nn=bf*YHէ9~vG42 $O+6 w^F9ttTCKl@D;];$3f G])S ]IQJx>sk:=~4HY>+eď~PWjg%NC閍sP{j^_=(9eh4o x @Av&@Ьߥ20$c 7ܙYoD#XS:&3^Gk2b4a3v;ԇỒ nvnCId7 r\z\)$ =H0WK{kFws9k5]bJR,ХOeS]&GV,?Z rݷ3j`CpH:.mn1sR| eV_sեpdht^((۪apii50Cr Үn^XS@~Wq,@WiGȕ BȡPDcn.iTRM8RNi+'\DP[vTաJ d (H>>8M˛g#!fuN$6ǏNg:rJ?P}P`UR?"JJRcxkEdSaBbgFqb\ /VJA4Zs+~) rі]ZGE?$а322XRrԱ0UZ ;5XJ#j]Q~ܹjx۞p50 x5 WsIv3%xċdVk}ЀWћ[u sگv'q^"t|J}3Ϸ* ֐LCŠDuq.YTӑ3Ggu@1b}, ZԮ=zeS_rD;nHpJޤ"ofxH́&8d M1^co*H/ NnEXpn6l2j;"\GJ؂!³A5AZ!Iz1|HQLr׊^3MH+P/ba -|t3d<`&Cd}wCQ³Vx5e3;aTGqZ۫FP@6݉ ΍/Cg(c~~ֹPWѽTV>)^GUSSUcM?^c-tX>k"Ox :-k|_;OP~w'D> =jkxX2 U!Bp2's׭ᯂLUоOp+8l`G.;mz-Q"ZG?{>n~СE p:JNG,eNRVRa~X-:´csw>3 C,/} {#].3{/-|ZMͻˠ){;_P  㹺]DrZ.X7 z eYUU$Q_MŊAYZRuNaU6b;8]<8V-so\>Ֆt?1nHPX=k؊jzKdXB+ fdD9Wm8~嚃 Ə2d6"q |`N$Nò\E9+$N&Ж&<>u`sPQ،_cƽQ񬉦~*u-i}Sq坝s+Y+}Cc:w]64^㹂:g8jxroco=5>yz,1u/c1oQ?XU!C=WxzE7B_H)Q%iD.b`jRF,eқAIor!--g꧃Kw-i0s@VcBɹ(1`~n5ϐTe.x?NIj܂kcf>k<8}.-y G*E0`r uVwAZD5z1'~>)!!F,?8&bV7oj~<-8-TdMΪA)Q槀++Suz"p&I(f\j\$}@)FnB)!x\|BÞ䒤2v=ę2xcŃ~~H(N`#on#@)v> U3Cb 83@zR!ؕ5zfj~pM<_m^/Hyx<9^%Ƿ]/JYoErFkmCr O ݤ.7C`L> |)t V.p (^gE`0s320ڥ.U-<;ڕJ\tADj'TBb6<6 Ą4"0a#g֭x׸r=u7"2zLŚq ' k9`J䎅JtH ;sK0;J%prGG7[Ce^1z\DcͩŸl]F2ZX=."o%؊3k7wxely\l"ubQ8qQGa K6 Q$xe1f|@aZdy]YaP!оg >DsB,yxˊɆ8qwڑGވpd|=$L:\]̎f]Lw3OXwH奌=Qk N. .~+gNb~/|u>xv?2˵/ qvy5~׽(nVk QlZ].XQjzt.:@ aC"w7o8*̬/Z/kM`go3{d?f@ PgE{<_ oy7n(Eԃ_$<_,[6I X5-q=[qgՒ|;wx!%pA/_W0߸q:]aPJg` ڹ΋V|_D b>;~#1%*Bkjo7~0 zxt>3柧8 (;antx*]Tܞr<D;n~7 /x:#(^1j8v6iqL&HbSV(_ؚsYf-ʖreVwi7fP&Vr m#u?L;#л$'_ -)!5H# ~/(&<.?bi4b|um~6T~D.)!^ad,|ߟOi t)>K^B@ ;cgϵo~op1WBu_HmfB]R0 OP]{q%r'p? wLJGS!DQqIs7,A։'B~v ,N~Ml^Tesyj) \JwP|D}^wnjtm:Y֙L9`yJI<(in~>*J?9tPY'16rym*bG\i3J@*!9/ \ѯ$-Ue@./2*zv8G̭E+D4lqdKFj5d ?gotgh#R.{Ci)qd=?ƨ`jGsvIa#ȣb(-EȢ;RvxIudޝ7inōs{V%Ju6 %pay!<(Ɔ.ar9.a{'=PI5/ꊩj5;s ~1ڃ6Luԥ&`ԇHη"FNe{S?\c|T>fT׬<)#6NDs*q&7B"ޡYe֋Y9QS+Z5q )X:gg JOJA WuGJEZ%5C!Vy[:e }\G\(ӊgYQ̛yЅcs94B\ޡPyjH+N'nHL]z GH;_ ac ZJN_疷Mꚅ(0j4BᘂO`IHRrKOB*aqc/\|a9Ǵ?gj",$ɛmè2 PchhКC6E Q0kHP(}ʥ]TFX' h NΖBJ,&Hı491rFciF) LecxP*%d5e04 Tlq{o޸qP")< "7>{_2]AV!BS;&DFC*!\ lZT_#$*u CZ>Ѹ'E@p,HT_Bj?PY,50v*c+ړ * }P\ZwL2: 7@5Djy$bg }?~'!]8ả%׺/1&!xbaUr1|6{@ʢ's'\~+ѥ00F7dzgŸ2/ΤX.b \šX.7H3]ćV}?*_&X @ %Ͼds~{uLJɱ(;b)kLut>; W $.4RU/UHJEɱ\*,i9kK ;rƍԅg5}8.JN)"QT SoDMe涏.L,}tN))i,jKjbk$xJҶ>doϜ>dmMڗ˜{3g>$PmN#ׂk{C&M:d3j_ )"ɛ4dS3j߸qׄ$46,!}J.Z:f&xчC'E,[tfԇQc!7N{B?KT0~5w>jGߋ3` 07S8d:( R_ăTBvRSW@膃=z';?,N'D\Sw_P?x-Dpt%O8p}L",N'^4NhcSp<Q?Jg *Wd҇$\}}h*8@er@ ޱ/g0¢e?YTF6yBe19r'lȈi W}S=rrg"O(|$,w? s .Lu\jTpq?݅bEx'(f9R.5hlkB xǐfǓJd㢩j.zc5^wA+M!a1Bʻp"gbޱq#zjqv-"r9U*V Zw,s\3~"8;A]Bݙ]8d_ҧ2ǚRåĈ=-`M4utz`>#zS)1¼Msl%Mw<5} C8Kރm(5P8gwJBVap. 0^nةIѪGri[ -L4%rޡ{V!Z\G+NR{x -xm(I,3!YC:bLM\8҅R{2Nbgϗ0gRå瞫U*`+g:^:ERjo\:4ՍdPgک$X]X>f*6>($}wQ7zغE"d<.`KZ.oޞH}ޱsq6HZ[8tߜ"mN8{GUon_LTwLy:BA[l:C}7dkq4!9Mw5!S^E MH6=?Ď7n|7M [3_w D.4.2.2.1 rcu_ctrlblk


D.4.2.2.1 rcu_ctrlblk

The rcu_ctrlblk structure is global, and holds the lock that protects grace-period processing (fliplock) as well as holding the global grace-period counter (completed). The least-significant bit of completed is used by rcu_read_lock() to select which set of counters to increment.



Paul E. McKenney 2011-12-16
perfbook_html/node474.html0000644000175000017500000003340211672746163015654 0ustar paulmckpaulmck F.14 Chapter 

F.14 Chapter [*]

Quick Quiz [*].1: 
What happens if two CPUs attempt to invalidate the same cache line concurrently?
 
Answer:
One of the CPUs gains access to the shared bus first, and that CPU ``wins''. The other CPU must invalidate its copy of the cache line and transmit an ``invalidate acknowledge'' message to the other CPU.
Of course, the losing CPU can be expected to immediately issue a ``read invalidate'' transaction, so the winning CPU's victory will be quite ephemeral.

Quick Quiz [*].2: 
When an ``invalidate'' message appears in a large multiprocessor, every CPU must give an ``invalidate acknowledge'' response. Wouldn't the resulting ``storm'' of ``invalidate acknowledge'' responses totally saturate the system bus?
 
Answer:
It might, if large-scale multiprocessors were in fact implemented that way. Larger multiprocessors, particularly NUMA machines, tend to use so-called ``directory-based'' cache-coherence protocols to avoid this and other problems.

Quick Quiz [*].3: 
If SMP machines are really using message passing anyway, why bother with SMP at all?
 
Answer:
There has been quite a bit of controversy on this topic over the past few decades. One answer is that the cache-coherence protocols are quite simple, and therefore can be implemented directly in hardware, gaining bandwidths and latencies unattainable by software message passing. Another answer is that the real truth is to be found in economics due to the relative prices of large SMP machines and that of clusters of smaller SMP machines. A third answer is that the SMP programming model is easier to use than that of distributed systems, but a rebuttal might note the appearance of HPC clusters and MPI. And so the argument continues.

Quick Quiz [*].4: 
How does the hardware handle the delayed transitions described above?
 
Answer:
Usually by adding additional states, though these additional states need not be actually stored with the cache line, due to the fact that only a few lines at a time will be transitioning. The need to delay transitions is but one issue that results in real-world cache coherence protocols being much more complex than the over-simplified MESI protocol described in this appendix. Hennessy and Patterson's classic introduction to computer architecture [HP95] covers many of these issues.

Quick Quiz [*].5: 
What sequence of operations would put the CPUs' caches all back into the ``invalid'' state?
 
Answer:
There is no such sequence, at least in absence of special ``flush my cache'' instructions in the CPU's instruction set. Most CPUs do have such instructions.

Quick Quiz [*].6: 
In step 1 above, why does CPU 0 need to issue a ``read invalidate'' rather than a simple ``invalidate''?
 
Answer:
Because the cache line in question contains more than just the variable a.

Quick Quiz [*].7: 
In step 1 of the first scenario in Section [*], why is an ``invalidate'' sent instead of a ''read invalidate'' message? Doesn't CPU 0 need the values of the other variables that share this cache line with ``a''?
 
Answer:
CPU 0 already has the values of these variables, given that it has a read-only copy of the cache line containing ``a''. Therefore, all CPU 0 need do is to cause the other CPUs to discard their copies of this cache line. An ``invalidate'' message therefore suffices.

Quick Quiz [*].8: 
Say what??? Why do we need a memory barrier here, given that the CPU cannot possibly execute the assert() until after the while loop completes?
 
Answer:
CPUs are free to speculatively execute, which can have the effect of executing the assertion before the while loop completes.

Quick Quiz [*].9: 
Does the guarantee that each CPU sees its own memory accesses in order also guarantee that each user-level thread will see its own memory accesses in order? Why or why not?
 
Answer:
No. Consider the case where a thread migrates from one CPU to another, and where the destination CPU perceives the source CPU's recent memory operations out of order. To preserve user-mode sanity, kernel hackers must use memory barriers in the context-switch path. However, the locking already required to safely do a context switch should automatically provide the memory barriers needed to cause the user-level task to see its own accesses in order. That said, if you are designing a super-optimized scheduler, either in the kernel or at user level, please keep this scenario in mind!

Quick Quiz [*].10: 
Could this code be fixed by inserting a memory barrier between CPU 1's ``while'' and assignment to ``c''? Why or why not?
 
Answer:
No. Such a memory barrier would only force ordering local to CPU 1. It would have no effect on the relative ordering of CPU 0's and CPU 1's accesses, so the assertion could still fail. However, all mainstream computer systems provide one mechanism or another to provide ``transitivity'', which provides intuitive causal ordering: if B saw the effects of A's accesses, and C saw the effects of B's accesses, then C must also see the effects of A's accesses. In short, hardware designers have taken at least a little pity on software developers.

Quick Quiz [*].11: 
Suppose that lines 3-5 for CPUs 1 and 2 in Table [*] are in an interrupt handler, and that the CPU 2's line 9 is run at process level. What changes, if any, are required to enable the code to work correctly, in other words, to prevent the assertion from firing?
 
Answer:
The assertion will need to written to ensure that the load of ``e'' precedes that of ``a''. In the Linux kernel, the barrier() primitive may be used to accomplish this in much the same way that the memory barrier was used in the assertions in the previous examples.

Quick Quiz [*].12: 
If CPU 2 executed an assert(e==0||c==1) in the example in Table [*], would this assert ever trigger?
 
Answer:
The result depends on whether the CPU supports ``transitivity.'' In other words, CPU 0 stored to ``e'' after seeing CPU 1's store to ``c'', with a memory barrier between CPU 0's load from ``c'' and store to ``e''. If some other CPU sees CPU 0's store to ``e'', is it also guaranteed to see CPU 1's store?

All CPUs I am aware of claim to provide transitivity.

Quick Quiz [*].13: 
Why is Alpha's smp_read_barrier_depends() an smp_mb() rather than smp_rmb()?
 
Answer:
First, Alpha has only mb and wmb instructions, so smp_rmb() would be implemented by the Alpha mb instruction in either case.

More importantly, smp_read_barrier_depends() must order subsequent stores. For example, consider the following code:



  1 p = global_pointer;
  2 smp_read_barrier_depends();
  3 if (do_something_with(p->a, p->b) == 0)
  4   p->hey_look = 1;


Here the store to p->hey_look must be ordered, not just the loads from p->a and p->b.

Paul E. McKenney 2011-12-16
perfbook_html/node483.html0000644000175000017500000001516311672746164015661 0ustar paulmckpaulmck H.4 Original Publications

H.4 Original Publications

  1. Section [*] (``What Makes Parallel Programming Hard?'') on page [*] originally appeared in a Portland State University Technical Report [MGM+09].
  2. Section [*] (``RCU Fundamentals'') on page [*] originally appeared in Linux Weekly News [MW07].
  3. Section [*] (``RCU Usage'') on page [*] originally appeared in Linux Weekly News [McK08c].
  4. Section [*] (``RCU Linux-Kernel API'') on page [*] originally appeared in Linux Weekly News [McK08b].
  5. Section [*] (``Memory-Barrier Instructions For Specific CPUs'') on page [*] originally appeared in Linux Journal [McK05a,McK05b].
  6. Section [*] (``Sleepable RCU Implementation'') on page [*] originally appeared in Linux Weekly News [McK06].
  7. Section [*] (``Hierarchical RCU Overview'') on page [*] originally appeared in Linux Weekly News [McK08a].
  8. Section [*] (``Preemptible RCU'') on page [*] originally appeared in Linux Weekly News [McK07a].
  9. Appendix [*] (``Formal Verification'') on page [*] originally appeared in Linux Weekly News [McK07f,MR08].



Paul E. McKenney 2011-12-16
perfbook_html/node253.html0000644000175000017500000001507711672746162015656 0ustar paulmckpaulmck 17.1.4 Multithreaded Transactions


17.1.4 Multithreaded Transactions

It is perfectly legal to create processes and threads while holding a lock or, for that matter, from within an RCU read-side critical section. Not only is it legal, but it is quite simple, as can be seen from the following code fragment:



  1 pthread_mutex_lock(...);
  2 for (i = 0; i < ncpus; i++)
  3   tid[i] = pthread_create(...);
  4 for (i = 0; i < ncpus; i++)
  5   pthread_join(tid[i], ...)
  6 pthread_mutex_unlock(...);


This pseudo-code fragment uses pthread_create() to spawn one thread per CPU, then uses pthread_join() to wait for each to complete, all under the protection of pthread_mutex_lock(). The effect is to execute a lock-based critical section in parallel, and one could obtain a similar effect using fork() and wait(). Of course, the critical section would need to be quite large to justify the thread-spawning overhead, but there are many examples of large critical sections in production software.

What might TM do about thread spawning within a transaction?

  1. Declare pthread_create() to be illegal within transactions, resulting in transaction abort (preferred) or undefined behavior. Alternatively, enlist the compiler to enforce pthread_create()-free transactions.
  2. Permit pthread_create() to be executed within a transaction, but only the parent thread will be considered to be part of the transaction. This approach seems to be reasonably compatible with existing and posited TM implementations, but seems to be a trap for the unwary. This approach raises further questions, such as how to handle conflicting child-thread accesses.
  3. Convert the pthread_create()s to function calls. This approach is also an attractive nuisance, as it does not handle the not-uncommon cases where the child threads communicate with one another. In addition, it does not permit parallel execution of the body of the transaction.
  4. Extend the transaction to cover the parent and all child threads. This approach raises interesting questions about the nature of conflicting accesses, given that the parent and children are presumably permitted to conflict with each other, but not with other threads. It also raises interesting questions as to what should happen if the parent thread does not wait for its children before committing the transaction. Even more interesting, what happens if the parent conditionally executes pthread_join() based on the values of variables participating in the transaction? The answers to these questions are reasonably straightforward in the case of locking. The answers for TM are left as an exercise for the reader.

Given that parallel execution of transactions is commonplace in the database world, it is perhaps surprising that current TM proposals do not provide for it. On the other hand, the example above is a fairly sophisticated use of locking that is not normally found in simple textbook examples, so perhaps its omission is to be expected. That said, there are rumors that some TM researchers are investigating fork/join parallelism within transactions, so perhaps this topic will soon be addressed more thoroughly.

Paul E. McKenney 2011-12-16
perfbook_html/node289.html0000644000175000017500000000437011672746162015661 0ustar paulmckpaulmck B.4.4 __get_thread_var()

B.4.4 __get_thread_var()

The __get_thread_var() primitive accesses the current thread's variable.



Paul E. McKenney 2011-12-16
perfbook_html/node196.html0000644000175000017500000002227611672746162015663 0ustar paulmckpaulmck 14.2.4.3 Pair-Wise Memory Barriers

14.2.4.3 Pair-Wise Memory Barriers

Pair-wise memory barriers provide conditional ordering semantics. For example, in the following set of operations, CPU 1's access to A does not unconditionally precede its access to B from the viewpoint of an external logic analyzer (see Appendix [*] for examples). (the system is only to act as if the accesses are in order; it is not necessarily required to actually force them to be in order). However, if CPU 2's access to B sees the result of CPU 1's access to B, then CPU 2's access to A is guaranteed to see the result of CPU 1's access to A. Although some CPUs' memory barriers do in fact provide stronger, unconditional ordering guarantees, portable code may rely only on this weaker if-then conditional ordering guarantee.



CPU 1 CPU 2
access(A); access(B);
smp_mb(); smp_mb();
access(B); access(A);


Quick Quiz 14.6: But if the memory barriers do not unconditionally force ordering, how the heck can a device driver reliably execute sequences of loads and stores to MMIO registers? End Quick Quiz

Of course, accesses must be either loads or stores, and these do have different properties. Table [*] shows all possible combinations of loads and stores from a pair of CPUs. Of course, to enforce conditional ordering, there must be a memory barrier between each CPU's pair of operations.


Table: Memory-Barrier Combinations
CPU 1 CPU 2 Description
0 load(A) load(B) load(B) load(A) Ears to ears.
1 load(A) load(B) load(B) store(A) Only one store.
2 load(A) load(B) store(B) load(A) Only one store.
3 load(A) load(B) store(B) store(A) Pairing 1.
4 load(A) store(B) load(B) load(A) Only one store.
5 load(A) store(B) load(B) store(A) Pairing 2.
6 load(A) store(B) store(B) load(A) Mouth to mouth, ear to ear.
7 load(A) store(B) store(B) store(A) Pairing 3.
8 store(A) load(B) load(B) load(A) Only one store.
9 store(A) load(B) load(B) store(A) Mouth to mouth, ear to ear.
A store(A) load(B) store(B) load(A) Ears to mouths.
B store(A) load(B) store(B) store(A) Stores ``pass in the night''.
C store(A) store(B) load(B) load(A) Pairing 1.
D store(A) store(B) load(B) store(A) Pairing 3.
E store(A) store(B) store(B) load(A) Stores ``pass in the night''.
F store(A) store(B) store(B) store(A) Stores ``pass in the night''.


Paul E. McKenney 2011-12-16
perfbook_html/img198.png0000644000175000017500000000731511672746111015323 0ustar paulmckpaulmckPNG  IHDRW38/tRNSىHIDATx?ߓ'iJewipS խ{)2.RH3tiLzX@ #+f#{, UdeKTv)OizF% Ds ȯ}n{JkMb[Z}uKlMUn#mR LH5|mWj4(?D5WO|=^>7kmRVDu/ս5;hv~:wk I+vǏZvҷ3oOzU ǬܭڋߡV4" {ݍ ?}c:Ý /UJٵʝoZa7O4ۻF:LU}K2<t8el.6b쵵3^0[oM4Ij)&4/k?5E&3ܯMV6TYc o>vv 1SF*oМc[p@zF2(@ #ф+h턨ئF<{I3`{e>Ylgή]yyK_{wxqfvQlrxc|ڣcKq(V~IN>Cox ͥr`-%͈=Xzy_d%cՏū~Gʆ ~RmP 4]K!R ";dl0XPp)vqXb`TaO댗޾{ D^g}<[o]`·?zm=czo!<}q\,Q, ɇ/"ro@bVb&0+gB!p"g*sV^+b@a!嶥\8]r/> `TX*X,Ŋ3,>KI"CLzƨ Ї@0Ftn#ton+(~aTJl[c"wrhF14.̩ŲVX+ k C03u|o-b+zgq'k +5M=lJ|blR xυ4i64'&@zfxEkZi`4VX+ 'GqƾNGkiϭ5CU9iv34OiDk{c16 kSZgNZ5nJ2=CNWY*d 8i_kҚ2zEu#ҺU 4.}8-+W Eh^(h?e!AkqyK \!a[.ah绥)3iE"\{F˵hTeY+O?|(/"iS8E}W¾sDXFg<ȳd#g_cpƄSIDψO`4V4pUֶΜWC&'ZihD47OM}VETn8z.^Ed\ܐs˨DֺgH?%\睛u~"^=u!Ec, Jk4<}]UX+ ?H)0^Vb Rd2KQ lU+L hw,Sqb/2׍İc UvnEEӇ8G[=R3"Έ(ЭL8s k49Zi`4VX+ J3Zi`4Z3C/jä w5WnO~_8ߌot<K N'釹2+OŻ7Η^D \\i]@& WX+ Jk0|"fC3`&6C&`_i`_i`_i`_i`_i`_i`_i8b:|ձw{FW%bE8#}Eܨcz~mJ%\y*s;]K߰F8oj^ː {i}WnH|H" '2ܨ׳}}5ͬ$/{>1YuԈ,|s:Α:jWWWWWWWWWWWWI1zL9zD1z9/-p04uK10| #4t*i\h핆_gE\4J-90$U?ljs% u_gE^l[4*f@|zwНrx̱Cw̩qp^G_i0v^{\Fb)f6QGcnƉZ#)-ɤ Or8qjh\{?$Px{L߁НL#u4m^$ ۰|`c(ȃѩ)_E-x>WڻkCQN7|{4uq ܞw'hcZES5l>Y b ȷa!eh(C?$h(lA8N' CaUl)_P2FǣSGS|Oe:}L,ՑY<Κ+ Lu%;M4;+ + + + + sѹ}}}}}}}}}}}]B#oɱr?@JJJJJJJD}>dbC|3" D 3w7)Fuo{E~~͋ھ#݋7/";'Q<أu6`bT~X 7~`氯44444444444n-O\xCIENDB`perfbook_html/node295.html0000644000175000017500000000637011672746163015661 0ustar paulmckpaulmck C.2 Cache-Coherence Protocols


C.2 Cache-Coherence Protocols

Cache-coherency protocols manage cache-line states so as to prevent inconsistent or lost data. These protocols can be quite complex, with many tens of states,C.2but for our purposes we need only concern ourselves with the four-state MESI cache-coherence protocol.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node92.html0000644000175000017500000000703211672746162015567 0ustar paulmckpaulmck 7.4.2 Hierarchical Locking


7.4.2 Hierarchical Locking

The idea behind hierarchical locking is to have a coarse-grained lock that is held only long enough to work out which fine-grained lock to acquire. Figure [*] shows how our hash-table search might be adapted to do hierarchical locking, but also shows the great weakness of this approach: we have paid the overhead of acquiring a second lock, but we only hold it for a short time. In this case, the simpler data-locking approach would be simpler and likely perform better.

Figure: Hierarchical-Locking Hash Table Search
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...spin_unlock(&bp->bucket_lock);
38 return 0;
39 }\end{verbatim}
}\end{figure}

Quick Quiz 7.14: In what situation would hierarchical locking work well? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img148.png0000644000175000017500000001537511672746075015334 0ustar paulmckpaulmckPNG  IHDR`ߡOQPLTEb``MJK# hffvstmkkcaaZWXXUVVST856KHHC@@@<=wuv.*+6tRNS@fZIDATx]ڳFZZݍ5F9>< y@T,8{zH!*#}YȜi0' ݿΐŭc}?̣MMՕRfx(džl-PPE E8>a[] ƝxX4;M0l^R̬\aXTmpKQDözUx(ōjiO0K'e'!۩j v4~,CiNDW'pRFW%%06*gKHx[KQَ1Haʽu{mo3dDY|Cnfų~7~v{N;}6W 0NT`I-=~ޱZSWۿv3ۏWp|-r-aɭZצzck'`I0OӗYn*% nJ䝷2եfOaHj pxYW bYW60:hai$XR~i=-fn,p ϴ.%(yO_'8܉@;Du{)`R8Y NO//T@t /℣[_WF䕣PtJcO3A Jۋ*Y{>P>[îȫaNHN$ 8/3vJYo+Y7x0V_wcʟҊ Xvp}>=sx^C@y'PrZ&![e#^JmXނ6jQ}  5 $R=C|N4N'vLq W ?6$%)#pG7%-f iOܤ3bX IڷQgAw徍<Ky5ʏ?ޖ7FV5miy^Ш? =;Ӄtȯ_FQ>*, %3VJd4 M03N%5ii JLTބ55_k#ip7%L'M[UÖiK|h'a[1>esr<|O3>q&oay~hӂ$ܣs ..`Zóv[i(Ch$u0? :;w|>BG#4# 9϶A5gf!^qS\c+缒{S]:t4W߆Χ )[|{Mkel[Nެd%쯲tJK>]BILŒޥPz,3E[)[! S6p&uْs@J?df^[T=PaEi{kNtއvہݩnZ,\;1f +h/9]-z1&nOm 0 !&Cu2= -u~&2R! FK%T?Gi 2ё6$293&AHupW¹r)7:`9d(h8Y#W|pb=)Ƕ}SRwdB(_*b91SV=d|ܠT^J:WTqy9PG: rҌE)Ų /@{ĥt>ٙ?k՞c[unxt{:_~9˒EVJOF8Brvb~l8GkÝ)U#{zgJ/wT@*VԌ nPQHӥ!`x;S3}')` y3E#~W?b9h~?Bθ\4rb_R{`㺕+vRr!7I/0vRfឱΟu%K+C%Mj{c 7{-qr &Khtp2|Ɂmh4N2e cb{Ex! 0 <^҃ [\4`kx.N+с[`;dS(v>5>7="$Fis)7.k3AidR[ha7z.>qK W-To_ڊP=0/MZJce 5}\Zϟ<4ri=t>,S Y gUO-K7nP׃H"hChA|.55H@ 6rނc a0L +: (ϕ4乎Z}8jSp 7 ƆьIkvclm`g0H \eg$츂GQ 'i/Fs3~]'eH+(j^ag!_ bk24d*%EƖӣ(i"`?/+3Hݩl_{f#ΒX5N͡% [IB$FMe3CCYG T LhiNd=N\ Bq+3=\n67I`&ʇO 繟zcSf#1x9rY-,ˬ 4~X.j;T  PrF07CwZs컾zU(eGsYFY{R\:d3J-aQo1rү~b0RߒtK GG|D̹r<ʯ:֠ Ƴ#olCZdRG~H0諫dW꒭6m.Mϸrsf7-~^X?fo@tKO~+&~Sc5{Kk~ bUZWsL̆CfSb`-/`@-y<'$=Ôyl _10Θ&GT1 4g?f6NR );l逾p^ 6ڸl̗('Xw;K3ZXh)ՃQ> rK91#g:CD {6w$Qp85e>pXC{i' /\ʍ#}(d/1.h ˝NCϜ'nhf&l 8vO.aІ>du$0uOL}&0Aʁc=3nZ30nyfYӰg)pp|32/g4u0:Sl{3EwU9S~șb|_îs|fJrpfJ!bHI2Sdd@q#ZPOd@gX3)5OLy=k_.9~['.ǓS{& xOdpPHss+|6?B>~^j{b(Vcotӌc#cEHѷr7F_ʝ х4YsNVp;S L̢l,a~+ ~kJ9+f F~b( ގD<h%y1{iw֮iP1eD{>cPG/ -fB>Ȥc0Xa ȓ& ~gxD_ē>a6F1nTr1L-'Mtz/1/"vl/Y_dž ?LlV\ TJlcBRf|:_k+5܄<%xs{ ?UD/#oc0mt!4 8c-+ҊMyREVYI\S2{w]l{q2`!tCR 9ƓjK+nJ/.; t , NW靄`lEc@1JJIk.:d:Maewcmi-QakǶuPjEQ;۔ .O1..WwrƶܼRN Sƌd/Ӹ1 D]:Ak ҃SU ≛!Ro=ƭwŸfwK'|n|\C3Vg*!.ʛ0\*K { 5f|1c'?\^PpZB(eM o(9N#VEͿ[rK)l2^j3P]e)-K1h$ ~.ps3[8{xG֩ÖiS gR{:ߠNM?v33-AxG'~𱏥_%2nsqX#~f_~2…Wg;ϟ_sLWU[֮f?ce&P@*3>*d+N,[xܚt% S@ج1UVp 4yPj 37Ƴq,Pf S@UAP? .<ŽSh"p+ìQrQN3 kղHOuXHeRfLFRtRx< >L/A*kEk֧:HjZ'*-D!Tt׭rK UDHMW΀%(K|#\ əN& ~?(u]p·-z}… a.+e] )6eA4d3Lӽy"1puȟrY I$o1ATl.=a\* rU$ySH"y#%u2tU"a$KOw2.qvHvF|dݯy',OZftts+8ij_x/?A]¯EcԢ?ۺ$Me}4K>(6o8Bb}>7‡L,[%v3qvo`_n&kZ%>`!A &k`2[L_pOHf u_fB鄉e;Qa fBL.cv3TD#1Fd]k;mn&s;ہT3)DͤW>a7NJ?n7dn&$̈́k7 bM0;^KexDבJa:M',lE>Hi2 3tg$mT>M-y.sΥU<;:j⼆bXvo@FQn(0`ۂ} A`t^tqbrh/7L,ZHWn?otV5ʼn'V2~ŸcZ)kaOvbۅ_ @f,]qW Ȍg.bv+l4֛ZwϷ)W N1~H pe!ع=#ʶ:Ya-ܴ6DB2X$֩?7+3"?L_Us%jl|| Z}O}?†/teIENDB`perfbook_html/img238.png0000644000175000017500000002537011672746067015331 0ustar paulmckpaulmckPNG  IHDRUyoyNPLTEgdeb``TRRMJKZWW# hffmkkXUVVST856iffC@@wuv.*+qS6tRNS@f IDATx]v^i e>@|kruDALg W fm)ԕmwc44{!JO0Y+S*ϱ)8vE#56"ˡL.ģΦL5kn'L m& FۥT}t] [=sJ_~ڬ78|nVLlvt[:?_)6,^xm_)c+៫472}ɲ) ˾.Ce˞ OOa9]^O>'"a*?nF6q&4 -|ѕ3Dfq p~@#gGⅺc:-k .}% vT[ǝi@;'5a0hq ~RMpǨ=v΀6swYBA ;,g8cBL6(W JT`a mpy˨ C/2~.8Kp:ӗg}Y4lmij;Q H?c d^d@yh2u9xx 񓢵^ 2?Ydh{Xa3F6 l3-n3&)y:ap/'pVhS*(mh'!wHADC/45%EWe`{ -N6ͨ{1[k}hdN?c {Qu1zVF_@cX1bn0^茋9ܐ#p ^@ҕ8DV"Ț&E` K0 (V$Ti/Qo :9FMخ (\4 |9S2I׶(d#_xdxGӅQC/bg䇸Qbg"[ﯤѨ6SB)i 618,>ĬIn~Szopa/s38ӟ'>AyO_(j'aľ8 XW[@9[wPҺMe5.~|tNl1s㐦ǹ](h"AyD4V6 k,a(J4m{.fY m` \վ^,T3r iе}[@Oy_x +4 Z| QZN:+s#믦Z˞ȺQRs+0t6 ONv*xzj+MWKrjRatG(P<ޮJcA1 -hr;[s8 63uA@Ucx)mpҿZBLkIUR L#u,N "F ⥆&m+X1݂F[/ЗVfK?ќ.oTVWt{ FYK`imdy6gAr0m 8KVbLmQܯhlH":#-I`a~hooYiWIJ(ь+q7/3+eA>+`]}k-|j/ l''etJf`) lC+?[l6T祁gMTWO?G{LuՕP.oke%d> 0ZaȟhBR\zU8)dY>9p˴u/0dLvLe| (ƟTWG$2/=P<[0@U6deyid]4H|U$ {kZd̚fv2# c^xں" >e9+l[`G3 ^Hd*p%aWKPY[J_ j4C_4k ꅥeNɯ*(~6 3$gCvk^yJjTvVTUD"<I($[yYŒyHY>uMj3_ZbgI@lϛ6^WpH(!@j8"td]A4|{(@1!Iυo("h( }'a2^m-:iDEC-i6M}]\۷g]wS>7 䀀=yJ; %1 GTҎlNh>7⟾x`̒,uE v T>u u=ekSoP*H 1p'炉:ؾ.5A t4p 5]o PPy0_O׿832M }=q؝ z)o,;2 6c"+ (حkm$3G2 vuu&᷌RŎ!\:z0>eHIuB,T_{8I_"-1[́] >R-fGJdD? t-zj9nn ۅLQL*#}"G\Z@*[#Q}vL]1yU [x&R e'v]6&,*|W7[9  6xd׺qq!ɴ"eUz 7 Y]?/^ȶt`x҃1-( \jLjf2wN#-?cRLV~[Dj,Ȳ@rj(b~6y^HMYv"nwxxFe'yW6[lU%Acy|oB}e~(-<ԛb>uOusf?b7F!:\`7 Xt2v2`QC4ص[+~x=q 'lR`UKBlsͯרA'cr R ;\>UqYB8ԌRp*%e)T'R~EښҠӽ5X#`h)/MOtyp k)4*>n2G. Q" 1 J3FUD ]gNKZ k@尵y3}8ΕFڰP@a V?y-( 6*QSP @ݘ G; P;hlPLʃ}!qFj%PG W PTR_9r1^́+[ `55{YAWC¡LqxߡNgfY_[U*dt-nX S8zwGzKCQbCUkpU@2z6s( Ka8&_DE90Y~mxIRr,}\1jkTZu^zEOK[ْKrv'3 ^(G;Q4|U_[aFy]&zILbŀlVٶ͔+X8+v/$]B?&WQy ?}qw[Cw ֬%楯R|L(>@Uv@K PzTdO"d#rZ? #uH4Q ~PLY&]#jk9 ƪϯU{őhu M[ٹ~V{d !"3O =UTpqH攪*[2 >/qO1ch{s)03KxW4376fKʡsהLZ}KqAŨ #Hi۴_ y3f yvצ oȲr% /V~,;z6#G\5+ 3U+j23=,|^t6<?9t~ lPeG\ S1@m?[ƋjbvZW&{\x4`}kZ֘ ̑0:iQD TMQk;]U0#`}ҪrW|a$س7;LObvF"s%Gi7~Ոd(dCӓȦUÑij*Wjo'㢠2bh}7-֜b G>nf̂%Ѝ6F_A0aY|H`I|Ai9A&ۼe, FDPú&͌C=G~d'Iw v=RhQ{,lMm7X F b) fD=qf7R5un`:L렭l[gNCfG-3>#5&v4Ƙa* Cl1:ՓVz`-G eLMVU1zَ"aͫ<DU ?ic>۪sގ#ר|վȡ92OF' .wT3k}'74Րz}M"y7N QP\Gʈ:BK8l(z&5hzݰĥbd6Vn0C@ EcА\uC#Ţiq!P[D>GsQlzœBKw! 1T+| 8Eo_sFѬXȠ5$`Lb^\7aU!+ ;/%Y'WcH}$/gC 7gۭ.,$]o=k~|dkWC_}S:~:0ڛ$A[N/.R ֕utO_M(ؚ:HF%CDcPT$iM7TgI6~0䕽N~I|Lo"7 ߮ -i7 ((=p]uRGqQd?De( M*" ѹ^ȶaJArھ ȟ]kWM[piAŕ )V T҂ @Nʸ? #W/+@~`W/B$P]ԏ_CjjOjG8U2nZվ0G(#ͭPR䑙OwgVJG Aa(W\[cПA)} ѩ|2eHoXpv>ɉ/z^ۀxAq_uUE:rQ;#!*(':UfF 3)4DKB" VPus6:xq%%8H|;xBz3+"|P7.y>C$΋ 2 /ڥY%jU1<6w%=D8)/1fz/W=M,~.0!/(/eɰ#yiFy|[`_P^Lz&@ !Éү,ÑA? ıCIi(D8E /X8bJN<8ƱS};^5&3draiBP|ǎ&zA8e\M7%qOBs}]8O\/Uŕg+`q%.a E5W8X\y{Qn9`3ŕ;MJĆVr)L5=|2x~ɢD繠0kt WNf4) Iwzmlrd\a?hANgaoK$"3p#^U$QͩFKJ?͹U{b,f81b>]HJ!a–^EGjäq ,$HQ ;1WzS2["-A;|K2'y b+J[ R{KHt!]FDҪ`3hp(apQ]z nܭzƍ4s0Aam[{dI*ReLX'j&9+}dV#v7*)-I-JRB&1\$5hRᤵeNBb7Fuebg+5?s~xwwJjcN 6/ 3m_=Fˡ>G=n1d&)߀Z)Qp 6 Yȷr >t*B0J"UѺrnaz&LtM伾ZHVeȷB31D礳6Y,Z$8\m_6;Nzo" srj?9 0(2=b,!VzLDS^gev{ LIDAT+N j;\ 2.p!"e4X⺡#;=j-'A/BTڪԔ$V䢦̗%)N-)GJ+ȁ "aG-ۛjJ8M!Pg#'T $#,U0CK`8M/f+E/cJR_ D'||OwDuI^Qc0ҾY>y̩w*̍3vZWɿ:U'.hW!y"*HN)t65'宗z**H'̔Ee.P@]r)U6& O;m9P Zva-M${OZ,/P˷jB`y XeN*{v*N=0tP#(!4J&I#4x)m0%-YXT&-w32@h:O)N&#%x)m0!-\ZX?a[.apey~4)ni aw\6-Щ/rLvҕ$ˑ򝧼a)yXR <)Ew*RGu?]e F)G[mvIU^T}3yxOQ~ܼauqH(3ZK-^ z%l2xySaY:`+K}7з̠8^Xle*oZgY 4.1.1 Pipelined CPUs


4.1.1 Pipelined CPUs

Figure: CPUs Old and New
\resizebox{3in}{!}{\includegraphics{cartoons/whippersnapper}}

In the early 1980s, the typical microprocessor fetched an instruction, decoded it, and executed it, typically taking at least three clock cycles to complete one instruction before proceeding to the next. In contrast, the CPU of the late 1990s and early 2000s will be executing many instructions simultaneously, using a deep ``pipeline'' to control the flow of instructions internally to the CPU, this difference being illustrated by Figure [*].

Achieving full performance with a CPU having a long pipeline requires highly predictable control flow through the program. Suitable control flow can be provided by a program that executes primarily in tight loops, for example, programs doing arithmetic on large matrices or vectors. The CPU can then correctly predict that the branch at the end of the loop will be taken in almost all cases. In such programs, the pipeline can be kept full and the CPU can execute at full speed.

Figure: CPU Meets a Pipeline Flush
\resizebox{3in}{!}{\includegraphics{cartoons/pipeline}}

If, on the other hand, the program has many loops with small loop counts, or if the program is object oriented with many virtual objects that can reference many different real objects, all with different implementations for frequently invoked member functions, then it is difficult or even impossible for the CPU to predict where a given branch might lead. The CPU must then either stall waiting for execution to proceed far enough to know for certain where the branch will lead, or guess -- and, in the face of programs with unpredictable control flow, frequently guess wrong. In either case, the pipeline will empty and have to be refilled, leading to stalls that can drastically reduce performance, as fancifully depicted in Figure [*].

Unfortunately, pipeline flushes are not the only hazards in the obstacle course that modern CPUs must run. The next section covers the hazards of referencing memory.

Paul E. McKenney 2011-12-16
perfbook_html/node323.html0000644000175000017500000001133111672746163015642 0ustar paulmckpaulmck C.7.9 zSeries

C.7.9 zSeries

The zSeries machines make up the IBMTM mainframe family, previously known as the 360, 370, and 390 [Int04c]. Parallelism came late to zSeries, but given that these mainframes first shipped in the mid 1960s, this is not saying much. The bcr 15,0 instruction is used for the Linux smp_mb(), smp_rmb(), and smp_wmb() primitives. It also has comparatively strong memory-ordering semantics, as shown in Table [*], which should allow the smp_wmb() primitive to be a nop (and by the time you read this, this change may well have happened). The table actually understates the situation, as the zSeries memory model is otherwise sequentially consistent, meaning that all CPUs will agree on the order of unrelated stores from different CPUs.

As with most CPUs, the zSeries architecture does not guarantee a cache-coherent instruction stream, hence, self-modifying code must execute a serializing instruction between updating the instructions and executing them. That said, many actual zSeries machines do in fact accommodate self-modifying code without serializing instructions. The zSeries instruction set provides a large set of serializing instructions, including compare-and-swap, some types of branches (for example, the aforementioned bcr 15,0 instruction), and test-and-set, among others.

Paul E. McKenney 2011-12-16
perfbook_html/node81.html0000644000175000017500000000641011672746162015564 0ustar paulmckpaulmck 7.1.2.5 Double-Ended Queue Discussion


7.1.2.5 Double-Ended Queue Discussion

The compound implementation is somewhat more complex than the hashed variant presented in Section [*], but is still reasonably simple. Of course, a more intelligent rebalancing scheme could be arbitrarily complex, but the simple scheme shown here will has been shown to perform well compared to software alternatives [DCW+11] and even compared to algorithms using hardware assist [DLM+10]. Nevertheless, the best we can hope for from such a scheme is 2x scalability, as at most two threads can be holding the dequeue's locks concurrently.

The key point is that there can be significant overhead enqueuing to or dequeuing from a shared queue.



Paul E. McKenney 2011-12-16
perfbook_html/node34.html0000644000175000017500000001711711672746161015567 0ustar paulmckpaulmck 4.2.2 Costs of Operations


4.2.2 Costs of Operations


Table: Performance of Synchronization Mechanisms on 4-CPU 1.8GHz AMD Opteron 844 System
Operation Cost (ns) Ratio
Clock period 0.6 1.0
Best-case CAS 37.9 63.2
Best-case lock 65.6 109.3
Single cache miss 139.5 232.5
CAS cache miss 306.0 510.0
Comms Fabric 3,000 5,000
Global Comms 130,000,000 216,000,000


The overheads of some common operations important to parallel programs are displayed in Table [*]. This system's clock period rounds to 0.6ns. Although it is not unusual for modern microprocessors to be able to retire multiple instructions per clock period, the operations will be normalized to a full clock period in the third column, labeled ``Ratio''. The first thing to note about this table is the large values of many of the ratios.

The best-case CAS operation consumes almost forty nanoseconds, a duration more than sixty times that of the clock period. Here, ``best case'' means that the same CPU now performing the CAS operation on a given variable was the last CPU to operate on this variable, so that the corresponding cache line is already held in that CPU's cache, Similarly, the best-case lock operation (a ``round trip'' pair consisting of a lock acquisition followed by a lock release) consumes more than sixty nanoseconds, or more than one hundred clock cycles. Again, ``best case'' means that the data structure representing the lock is already in the cache belonging to the CPU acquiring and releasing the lock. The lock operation is more expensive than CAS because it requires two atomic operations on the lock data structure.

An operation that misses the cache consumes almost one hundred and forty nanoseconds, or more than two hundred clock cycles. A CAS operation, which must look at the old value of the variable as well as store a new value, consumes over three hundred nanoseconds, or more than five hundred clock cycles. Think about this a bit. In the time required to do one CAS operation, the CPU could have executed more than five hundred normal instructions. This should demonstrate the limitations of fine-grained locking.

Quick Quiz 4.5: Surely the hardware designers could be persuaded to improve this situation! Why have they been content with such abysmal performance for these single-instruction operations? End Quick Quiz

I/O operations are even more expensive. A high performance (and expensive!) communications fabric, such as InfiniBand or any number of proprietary interconnects, has a latency of roughly three microseconds, during which time five thousand instructions might have been executed. Standards-based communications networks often require some sort of protocol processing, which further increases the latency. Of course, geographic distance also increases latency, with the theoretical speed-of-light latency around the world coming to roughly 130 milliseconds, or more than 200 million clock cycles.

Quick Quiz 4.6: These numbers are insanely large! How can I possibly get my head around them? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node156.html0000644000175000017500000001500611672746162015650 0ustar paulmckpaulmck 10.3.4.2 Per-Thread Lock-Based RCU


10.3.4.2 Per-Thread Lock-Based RCU

Figure: Per-Thread Lock-Based RCU Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...n_unlock(&per_thread(rcu_gp_lock, t));
18 }
19 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_lock_percpu.h and rcu_lock_percpu.c) shows an implementation based on one lock per thread. The rcu_read_lock() and rcu_read_unlock() functions acquire and release, respectively, the current thread's lock. The synchronize_rcu() function acquires and releases each thread's lock in turn. Therefore, all RCU read-side critical sections running when synchronize_rcu() starts must have completed before synchronize_rcu() can return.

This implementation does have the virtue of permitting concurrent RCU readers, and does avoid the deadlock condition that can arise with a single global lock. Furthermore, the read-side overhead, though high at roughly 140 nanoseconds, remains at about 140 nanoseconds regardless of the number of CPUs. However, the update-side overhead ranges from about 600 nanoseconds on a single Power5 CPU up to more than 100 microseconds on 64 CPUs.

Quick Quiz 10.36: Wouldn't it be cleaner to acquire all the locks, and then release them all in the loop from lines 15-18 of Figure [*]? After all, with this change, there would be a point in time when there were no readers, simplifying things greatly. End Quick Quiz

Quick Quiz 10.37: Is the implementation shown in Figure [*] free from deadlocks? Why or why not? End Quick Quiz

Quick Quiz 10.38: Isn't one advantage of the RCU algorithm shown in Figure [*] that it uses only primitives that are widely available, for example, in POSIX pthreads? End Quick Quiz

This approach could be useful in some situations, given that a similar approach was used in the Linux 2.4 kernel [MM00].

The counter-based RCU implementation described next overcomes some of the shortcomings of the lock-based implementation.

Paul E. McKenney 2011-12-16
perfbook_html/img157.png0000644000175000017500000000737411672746106015327 0ustar paulmckpaulmckPNG  IHDRUJK"pED̞ "cp"yϙ.?}hWL:iXI8I놲ǃK3lLwLv XoV`""$G}眉#֬+BC U fZ:xY,>KaZ*&u~$Nmܡo MFH=I; |6HGF ьr+!0;A4(lWᦗ_O3̭-6yq/rg+ط) 6 #SNsr=meq "uVN!H)O`B _HEq[}ЕܪQe#YuWu"!bVXL1AE{NXJn~̝^l~͂(Xc Ӯw_uaF|UA )e~c<=[-\>akc4Qۜ NL&aQ_%19'(Y-Z»&M#t-ny¨>o%4+] ZTrm=U _PdSQ%FvTr&JOCX6` FYd$ih 208f?>0ScbMb|WV:ccTDʍY[l{&i qcu ..(X R>ymif/ V{*D1T R#s-pKz0wA x`D?IfOg&m WԹ!ӫX7g Rv X"É/YhJQ=*|\QfXi7n~֕hP[vvw]gRuʝpEd'YҁTr+oُmsAc_oz&mu~prM#LÈ6cC[ڽh`UN+9"|1=mkS3Z.B)505sN t'R[l?C״XE5F:&졸@e$%W$3tɬLhk.{Jc\NGjÈ3TfȲȓ %cW'hƠeun:UɧjM3eɦN"-a*0㲠-B1e2 GȒv!ITdϳ 9:KڸIȖVeR'Z 7 gnK?6 `f,u,W>~9;gߢ>q*̒ct"ޯjL.H~~l"ORQ#%g;!ԣ#Z֑ܮs|%򸓎JAOf:MT8&'J*'SWj&GM,pMkcg_GcG 3mvp(F"]-kuk׆H6q“&t hV"SG*\b ]&;Yo7nⳓ}GnY293u˲Y;} \t-E鹄Eo>;|0~۬Me al|kGS쁅* t6M<8b=(UM6]2q%8Z _ˢݴ1{q `LW$V"ߝzv]C)­dHG `M:0F~P#CL!za0fm3m!2z+$xɫF~ͪx܎ ?kUΟ-խ;K}_K`t6;x u,*YUY}̬8$r3cDDVw>w KxXyگǿ?tRQ6rHe+5e+VhFGx|/ҋIuոE^]37i*3$TTzF5JzN*QPc@Nji7M]:x<>g;'*_Ոg5)X uM)&S3 56:rV{Qߚ~`]Y)P %qLK}dJ %kl,z".vZiBczrI'"g!GNk <K[2bKOM1oݷHsK^Nݗ*as Vw"@/jz!KhŘ NFhKa9jym()|:^S=A0 :ѓQTmbUZ8"?ᖌГ&;{C~JGm_CJhGt?t<1g"m|_Lˌ褣mOH:8IENDB`perfbook_html/node160.html0000644000175000017500000002741511672746162015652 0ustar paulmckpaulmck 10.3.4.6 Scalable Counter-Based RCU With Shared Grace Periods


10.3.4.6 Scalable Counter-Based RCU With Shared Grace Periods

Figure: RCU Read-Side Using Per-Thread Reference-Count Pair and Shared Update Data
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}

Figure: RCU Read-Side Using Per-Thread Reference-Count Pair and Shared Update
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcpls.h) shows the read-side primitives for an RCU implementation using per-thread reference count pairs, as before, but permitting updates to share grace periods. The main difference from the earlier implementation shown in Figure [*] is that rcu_idx is now a long that counts freely, so that line 8 of Figure [*] must mask off the low-order bit. We also switched from using atomic_read() and atomic_set() to using ACCESS_ONCE(). The data is also quite similar, as shown in Figure [*], with rcu_idx now being a lock instead of an atomic_t.

Figure: RCU Shared Update Using Per-Thread Reference-Count Pair
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void flip_counter_and_wa...
... 35 spin_unlock(&rcu_gp_lock);
36 smp_mb();
37 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcpls.c) shows the implementation of synchronize_rcu() and its helper function flip_counter_and_wait(). These are similar to those in Figure [*]. The differences in flip_counter_and_wait() include:

  1. Line 6 uses ACCESS_ONCE() instead of atomic_set(), and increments rather than complementing.
  2. A new line 7 masks the counter down to its bottom bit.

The changes to synchronize_rcu() are more pervasive:

  1. There is a new oldctr local variable that captures the pre-lock-acquisition value of rcu_idx on line 23.
  2. Line 26 uses ACCESS_ONCE() instead of atomic_read().
  3. Lines 27-30 check to see if at least three counter flips were performed by other threads while the lock was being acquired, and, if so, releases the lock, does a memory barrier, and returns. In this case, there were two full waits for the counters to go to zero, so those other threads already did all the required work.
  4. At lines 33-34, flip_counter_and_wait() is only invoked a second time if there were fewer than two counter flips while the lock was being acquired. On the other hand, if there were two counter flips, some other thread did one full wait for all the counters to go to zero, so only one more is required.

With this approach, if an arbitrarily large number of threads invoke synchronize_rcu() concurrently, with one CPU for each thread, there will be a total of only three waits for counters to go to zero.

Despite the improvements, this implementation of RCU still has a few shortcomings. First, as before, the need to flip rcu_idx twice imposes substantial overhead on updates, especially if there are large numbers of threads.

Second, each updater still acquires rcu_gp_lock, even if there is no work to be done. This can result in a severe scalability limitation if there are large numbers of concurrent updates. Section [*] shows one way to avoid this in a production-quality real-time implementation of RCU for the Linux kernel.

Third, this implementation requires per-thread variables and the ability to enumerate threads, which again can be problematic in some software environments.

Finally, on 32-bit machines, a given update thread might be preempted long enough for the rcu_idx counter to overflow. This could cause such a thread to force an unnecessary pair of counter flips. However, even if each grace period took only one microsecond, the offending thread would need to be preempted for more than an hour, in which case an extra pair of counter flips is likely the least of your worries.

As with the implementation described in Section [*], the read-side primitives scale extremely well, incurring roughly 115 nanoseconds of overhead regardless of the number of CPUs. The synchronize_rcu() primitives is still expensive, ranging from about one microsecond up to about 16 microseconds. This is nevertheless much cheaper than the roughly 200 microseconds incurred by the implementation in Section [*]. So, despite its shortcomings, one could imagine this RCU implementation being used in production in real-life applications.

Quick Quiz 10.47: All of these toy RCU implementations have either atomic operations in rcu_read_lock() and rcu_read_unlock(), or synchronize_rcu() overhead that increases linearly with the number of threads. Under what circumstances could an RCU implementation enjoy light-weight implementations for all three of these primitives, all having deterministic ( $O\left(1\right)$) overheads and latencies? End Quick Quiz

Referring back to Figure [*], we see that there is one global-variable access and no fewer than four accesses to thread-local variables. Given the relatively high cost of thread-local accesses on systems implementing POSIX threads, it is tempting to collapse the three thread-local variables into a single structure, permitting rcu_read_lock() and rcu_read_unlock() to access their thread-local data with a single thread-local-storage access. However, an even better approach would be to reduce the number of thread-local accesses to one, as is done in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/node168.html0000644000175000017500000001101611672746162015650 0ustar paulmckpaulmck 11.1.1 Design

11.1.1 Design

The hope is to use RCU rather than final_mutex to protect the thread traversal in read_count() in order to obtain excellent performance and scalability from read_count(), rather than just from inc_count(). However, we do not want to give up any accuracy in the computed sum. In particular, when a given thread exits, we absolutely cannot lose the exiting thread's count, nor can we double-count it. Such an error could result in inaccuracies equal to the full precision of the result, in other words, such an error would make the result completely useless. And in fact, one of the purposes of final_mutex is to ensure that threads do not come and go in the middle of read_count() execution.

Quick Quiz 11.2: Just what is the accuracy of read_count(), anyway? End Quick Quiz

Therefore, if we are to dispense with final_mutex, we will need to come up with some other method for ensuring consistency. One approach is to place the total count for all previously exited threads and the array of pointers to the per-thread counters into a single structure. Such a structure, once made available to read_count(), is held constant, ensuring that read_count() sees consistent data.

Paul E. McKenney 2011-12-16
perfbook_html/node150.html0000644000175000017500000006562211672746162015653 0ustar paulmckpaulmck 10.3.3.1 RCU has a Family of Wait-to-Finish APIs


10.3.3.1 RCU has a Family of Wait-to-Finish APIs


Table: RCU Wait-to-Finish APIs
Attribute RCU Classic RCU BH RCU Sched Realtime RCU
Purpose Original Prevent DDoS attacks Wait for preempt-disable regions, hardirqs, & NMIs Realtime response
Availability 2.5.43 2.6.9 2.6.12 2.6.26
Read-side primitives rcu_read_lock() !
rcu_read_unlock() !
rcu_read_lock_bh()
rcu_read_unlock_bh()
preempt_disable()
preempt_enable()
(and friends)
rcu_read_lock()
rcu_read_unlock()
Update-side primitives (synchronous) synchronize_rcu() synchronize_net() synchronize_sched() synchronize_rcu() synchronize_net()
Update-side primitives (asynchronous/callback) call_rcu() ! call_rcu_bh() call_rcu_sched() call_rcu()
Update-side primitives (wait for callbacks) rcu_barrier() rcu_barrier_bh() rcu_barrier_sched() rcu_barrier()
Type-safe memory SLAB_DESTROY_BY_RCU SLAB_DESTROY_BY_RCU
Read side constraints No blocking No irq enabling No blocking Only preemption and lock acquisition
Read side overhead Preempt disable/enable (free on non-PREEMPT) BH disable/enable Preempt disable/enable (free on non-PREEMPT) Simple instructions, irq disable/enable
Asynchronous update-side overhead sub-microsecond sub-microsecond sub-microsecond
Grace-period latency 10s of milliseconds 10s of milliseconds 10s of milliseconds 10s of milliseconds
Non-PREEMPT_RT implementation RCU Classic RCU BH RCU Classic Preemptible RCU
PREEMPT_RT implementation Preemptible RCU Realtime RCU Forced Schedule on all CPUs Realtime RCU



Table: Sleepable RCU Wait-to-Finish APIs
Attribute SRCU QRCU
Purpose Sleeping readers Sleeping readers and fast grace periods
Availability 2.6.19
Read-side primitives srcu_read_lock()
srcu_read_unlock()
qrcu_read_lock()
qrcu_read_unlock()
Update-side primitives (synchronous) synchronize_srcu() synchronize_qrcu()
Update-side primitives (asynchronous/callback) N/A N/A
Update-side primitives (wait for callbacks) N/A N/A
Type-safe memory
Read side constraints No synchronize_srcu() No synchronize_qrcu()
Read side overhead Simple instructions, preempt disable/enable Atomic increment and decrement of shared variable
Asynchronous update-side overhead N/A N/A
Grace-period latency 10s of milliseconds 10s of nanoseconds in absence of readers
Non-PREEMPT_RT implementation SRCU N/A
PREEMPT_RT implementation SRCU N/A


The most straightforward answer to ``what is RCU'' is that RCU is an API used in the Linux kernel, as summarized by Tables [*] and [*], which shows the wait-for-RCU-readers portions of the non-sleepable and sleepable APIs, respectively, and by Table [*], which shows the publish/subscribe portions of the API.

If you are new to RCU, you might consider focusing on just one of the columns in Table [*], each of which summarizes one member of the Linux kernel's RCU API family.. For example, if you are primarily interested in understanding how RCU is used in the Linux kernel, ``RCU Classic'' would be the place to start, as it is used most frequently. On the other hand, if you want to understand RCU for its own sake, ``SRCU'' has the simplest API. You can always come back for the other columns later.

If you are already familiar with RCU, these tables can serve as a useful reference.

Quick Quiz 10.22: Why do some of the cells in Table [*] have exclamation marks (``!'')? End Quick Quiz

The ``RCU Classic'' column corresponds to the original RCU implementation, in which RCU read-side critical sections are delimited by rcu_read_lock() and rcu_read_unlock(), which may be nested. The corresponding synchronous update-side primitives, synchronize_rcu(), along with its synonym synchronize_net(), wait for any currently executing RCU read-side critical sections to complete. The length of this wait is known as a ``grace period''. The asynchronous update-side primitive, call_rcu(), invokes a specified function with a specified argument after a subsequent grace period. For example, call_rcu(p,f); will result in the ``RCU callback'' f(p) being invoked after a subsequent grace period. There are situations, such as when unloading a Linux-kernel module that uses call_rcu(), when it is necessary to wait for all outstanding RCU callbacks to complete [McK07e]. The rcu_barrier() primitive does this job. Note that the more recent hierarchical RCU [McK08a] implementation described in Sections [*] and [*] also adheres to ``RCU Classic'' semantics.

Finally, RCU may be used to provide type-safe memory [GC96], as described in Section [*]. In the context of RCU, type-safe memory guarantees that a given data element will not change type during any RCU read-side critical section that accesses it. To make use of RCU-based type-safe memory, pass SLAB_DESTROY_BY_RCU to kmem_cache_create(). It is important to note that SLAB_DESTROY_BY_RCU will in no way prevent kmem_cache_alloc() from immediately reallocating memory that was just now freed via kmem_cache_free()! In fact, the SLAB_DESTROY_BY_RCU-protected data structure just returned by rcu_dereference might be freed and reallocated an arbitrarily large number of times, even when under the protection of rcu_read_lock(). Instead, SLAB_DESTROY_BY_RCU operates by preventing kmem_cache_free() from returning a completely freed-up slab of data structures to the system until after an RCU grace period elapses. In short, although the data element might be freed and reallocated arbitrarily often, at least its type will remain the same.

Quick Quiz 10.23: How do you prevent a huge number of RCU read-side critical sections from indefinitely blocking a synchronize_rcu() invocation? End Quick Quiz

Quick Quiz 10.24: The synchronize_rcu() API waits for all pre-existing interrupt handlers to complete, right? End Quick Quiz

In the ``RCU BH'' column, rcu_read_lock_bh() and rcu_read_unlock_bh() delimit RCU read-side critical sections, and call_rcu_bh() invokes the specified function and argument after a subsequent grace period. Note that RCU BH does not have a synchronous synchronize_rcu_bh() interface, though one could easily be added if required.

Quick Quiz 10.25: What happens if you mix and match? For example, suppose you use rcu_read_lock() and rcu_read_unlock() to delimit RCU read-side critical sections, but then use call_rcu_bh() to post an RCU callback? End Quick Quiz

Quick Quiz 10.26: Hardware interrupt handlers can be thought of as being under the protection of an implicit rcu_read_lock_bh(), right? End Quick Quiz

In the ``RCU Sched'' column, anything that disables preemption acts as an RCU read-side critical section, and synchronize_sched() waits for the corresponding RCU grace period. This RCU API family was added in the 2.6.12 kernel, which split the old synchronize_kernel() API into the current synchronize_rcu() (for RCU Classic) and synchronize_sched() (for RCU Sched). Note that RCU Sched did not originally have an asynchronous call_rcu_sched() interface, but one was added in 2.6.26. In accordance with the quasi-minimalist philosophy of the Linux community, APIs are added on an as-needed basis.

Quick Quiz 10.27: What happens if you mix and match RCU Classic and RCU Sched? End Quick Quiz

Quick Quiz 10.28: In general, you cannot rely on synchronize_sched() to wait for all pre-existing interrupt handlers, right? End Quick Quiz

The ``Realtime RCU'' column has the same API as does RCU Classic, the only difference being that RCU read-side critical sections may be preempted and may block while acquiring spinlocks. The design of Realtime RCU is described elsewhere [McK07a].

Quick Quiz 10.29: Why do both SRCU and QRCU lack asynchronous call_srcu() or call_qrcu() interfaces? End Quick Quiz

The ``SRCU'' column in Table [*] displays a specialized RCU API that permits general sleeping in RCU read-side critical sections (see Appendix [*] for more details). Of course, use of synchronize_srcu() in an SRCU read-side critical section can result in self-deadlock, so should be avoided. SRCU differs from earlier RCU implementations in that the caller allocates an srcu_struct for each distinct SRCU usage. This approach prevents SRCU read-side critical sections from blocking unrelated synchronize_srcu() invocations. In addition, in this variant of RCU, srcu_read_lock() returns a value that must be passed into the corresponding srcu_read_unlock().

The ``QRCU'' column presents an RCU implementation with the same API structure as SRCU, but optimized for extremely low-latency grace periods in absence of readers, as described elsewhere [McK07f]. As with SRCU, use of synchronize_qrcu() in a QRCU read-side critical section can result in self-deadlock, so should be avoided. Although QRCU has not yet been accepted into the Linux kernel, it is worth mentioning given that it is the only kernel-level RCU implementation that can boast deep sub-microsecond grace-period latencies.

Quick Quiz 10.30: Under what conditions can synchronize_srcu() be safely used within an SRCU read-side critical section? End Quick Quiz

The Linux kernel currently has a surprising number of RCU APIs and implementations. There is some hope of reducing this number, evidenced by the fact that a given build of the Linux kernel currently has at most three implementations behind four APIs (given that RCU Classic and Realtime RCU share the same API). However, careful inspection and analysis will be required, just as would be required in order to eliminate one of the many locking APIs.

The various RCU APIs are distinguished by the forward-progress guarantees that their RCU read-side critical sections must provide, and also by their scope, as follows:

  1. RCU BH: read-side critical sections must guarantee forward progress against everything except for NMI and IRQ handlers, but not including softirq handlers. RCU BH is global in scope.
  2. RCU Sched: read-side critical sections must guarantee forward progress against everything except for NMI and IRQ handlers, including softirq handlers. RCU Sched is global in scope.
  3. RCU (both classic and real-time): read-side critical sections must guarantee forward progress against everything except for NMI handlers, IRQ handlers, softirq handlers, and (in the real-time case) higher-priority real-time tasks. RCU is global in scope.
  4. SRCU and QRCU: read-side critical sections need not guarantee forward progress unless some other task is waiting for the corresponding grace period to complete, in which case these read-side critical sections should complete in no more than a few seconds (and preferably much more quickly).10.1 SRCU's and QRCU's scope is defined by the use of the corresponding srcu_struct or qrcu_struct, respectively.

In other words, SRCU and QRCU compensate for their extremely weak forward-progress guarantees by permitting the developer to restrict their scope.

Paul E. McKenney 2011-12-16
perfbook_html/img183.png0000644000175000017500000001071611672746161015321 0ustar paulmckpaulmckPNG  IHDRbtRNSىHIDATx]nHt(~>3 D Q:H"eHt磢HL> 3@!ۿec{X,7/+?ReF+i;;Sئm"˹ߎv|(\wvrmRtJ*kaH*>̮4s821~/Tu؝[q" X*hh<CU&MJrmhD|\+2ODM/s`邗[qn<\, M$ޤfABdQ.>鮠z4N\RL SH<CU=ؚU([R\=f&663TɗV+})Kc ## /yI&hBg\xI?{+F93MNy>J$6?]9R /*$dծMK7-y>EL?0 i0 PRC-h4k=nCI2tho "_[N˘QbSJh ʘHՉG:*v.Z,1[$|JـyR}֕`zy<{<{< ٩p}})(u5,ir נK{-  &,W|ՠW J ,w~h.) bTA%.P3P^f8TfHSׄUpTA@ { \ɄtԄf}t``s0sk0x 74Aܶ0;:@Ƞ-Ҙ "`0}C#ɤ=}T:t62rW jG_::E6a:#NmnH u_|Fĩj@{i#EJ3n=}8' = x6lh;k(/mf}8}>_:WUt;s|C6^-|t1ܨ X߰` [ \Qo}h p .ӠG*ANۓlI{2.]?0 Xk h0jR|\Ư?{{#?WII %}ϟ.,HaNJY[|Pa+1D1oRpeNϟg [5BI)NdU6ɦkk_wF {"ɥ vJCW;yIR++Y}#5U@f@Ke J U*UUj=ċqU\[{j|-YFNNv@Y4WZ\.\{Th+m#QgT^CxnL3]@q^Ók6.[`%2}6&؊͛\[m ozFNNl<u4e5PtړW}JWƊ.`r*'Y 4|E0sbcIEi`w}P:WU _u$%K`_5X_K{Z3Q6JIfwx|ոpո7֞S{yt2;53nx{ oϸ\lyQsmmp6n~7\ o뷮ij!om ?#LgϸDA&QD_j~7\[im- AqM>X04~>P;v"\E\~`X뜺G 5k/o~7\ oqϸןqz>]IENDB`perfbook_html/node128.html0000644000175000017500000000734711672746162015660 0ustar paulmckpaulmck 10.3.1.3 Maintain Multiple Versions of Recently Updated Objects


10.3.1.3 Maintain Multiple Versions of Recently Updated Objects

This section demonstrates how RCU maintains multiple versions of lists to accommodate synchronization-free readers. Two examples are presented showing how an element that might be referenced by a given reader must remain intact while that reader remains in its RCU read-side critical section. The first example demonstrates deletion of a list element, and the second example demonstrates replacement of an element.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node237.html0000644000175000017500000001325511672746162015654 0ustar paulmckpaulmck 14.2.13.1 Cache Coherency

14.2.13.1 Cache Coherency

Although cache-coherence protocols guarantee that a given CPU sees its own accesses in order, and that all CPUs agree on the order of modifications to a single variable contained within a single cache line, there is no guarantee that modifications to different variables will be seen in the same order by all CPUs -- although some computer systems do make some such guarantees, portable software cannot rely on them.

Figure: Split Caches
\includegraphics{advsync/SplitCache}

To see why reordering can occur, consider the two-CPU system shown in Figure [*], in which each CPU has a split cache. This system has the following properties:

  1. An odd-numbered cache line may be in cache A, cache C, in memory, or some combination of the above.
  2. An even-numbered cache line may be in cache B, cache D, in memory, or some combination of the above.
  3. While the CPU core is interrogating one of its caches,14.9 its other cache is not necessarily quiescent. This other cache may instead be responding to an invalidation request, writing back a dirty cache line, processing elements in the CPU's memory-access queue, and so on.
  4. Each cache has queues of operations that need to be applied to that cache in order to maintain the required coherence and ordering properties.
  5. These queues are not necessarily flushed by loads from or stores to cache lines affected by entries in those queues.

In short, if cache A is busy, but cache B is idle, then CPU 1's stores to odd-numbered cache lines may be delayed compared to CPU 2's stores to even-numbered cache lines. In not-so-extreme cases, CPU 2 may see CPU 1's operations out of order.

Much more detail on memory ordering in hardware and software may be found in Appendix [*].

Paul E. McKenney 2011-12-16
perfbook_html/img76.png0000644000175000017500000002261011672746007015235 0ustar paulmckpaulmckPNG  IHDR&͔RNPLTEb``TRRMJK# hffvstmkkZWXXUV856iffKHHC@@A>>@<=wuv.*+mjktRNS@f IDATx] AֱGf?:T((hBrsI| `WcI@}eȘfeZb٭xI@7?cbyFQ+X6UweBK(gFwŨ{9{|5pOljŤ|{ fM.%442s_heK︅Ee_=玉MMgu:nb|w'5U/ o^2 ui,eVP=wo:W0RC{Bw#@ŗe%ۗ|277tzwD0-̃ܵJ ܮL@8A\vzo:ҳ?:ͅD+f~I@\k~fVUSO<`g{쯩A_0%W4.XB{(Lܞ2a5 /BEC H]Z#4;5\j@߻UM5pzۈM4*_\'?fmE;s:+@[;1'G%8 zȶuU]dQ ͒Jfҝi;͘YN C~"'5_]I8jvt=*$uZǙɹl>d8N4>D ;Ǝ)Y . .J(փbɛYKuvEױ "_ W,Bw>3Ζy+vk8v{)ՠlV\t$&ba4KE1pܘ'(`%еp}z bI ?}j^ذ wԟ|v4)D?zU$;K\W`~N=Դr3ii6iL[.6Qu 9C*TgbH>Z2OKoQfey`MOޮWHڲ?(cʔ P֪㜣ޜ:\Yn2Yv\WcdV=e|*A-8#t/Wz];cmkv7#1Ud˖xgq={gjMߺc6qڷ x<&~,=ޯ6K4 HX-[>R w 4Y3ޟFzҲ^@V&V'P+i߶2ZwʔΙ-xNHH@j`382kÔIuc9vyHw)Cv% a$' _pRE-maOVʁ9uTل^CclG׮Y.+ʅo;}L܄i;zyhKfPgP.vpmٜE17K "OgUd]aO qz%[kRT;o8{jN'P*M) ziAgUJAk$_ѦAƾo2 mYy5yMMF4bkMQ Q'o\U2ɼ5ꔪn4Qf"NkFnA&-|Q'6PA4*}ߋ9CsnuP*( qr~*louAK7ղ|r!QS ~`O 8Z<A-n6rM뺗C3c;i&Q5qedV :"-O+U'k~>?if'Oard}@]Y{᮫O3,jRQw'Н괭cV;n'^ b4n,ov܎^Ə`-0W/Z\_Wn z3Q/F,7/ҙ#xP 3AreB qL`]2 r0~Y\nhS]^UkG[%"IW-M6eCRE= H\(HsjhϓӒmcœwN"NR/u$Kl")xB*#/,uMA-*8QeX)5!6|/?_\gU\$4p``uߡ ~}-$ 8[:a^R>KVijdd0񟌚;Is}̄/*5B eه-&#F8(߯{%DcZىu[ 4d6L4R\(d/G ;Pq+OY%3|?o s fB b53sH@:z9>؜bt* ey_EhPVw=U mpWx0~\ % W@H;h(Z%yo]gFz O1i+#"~7c|G}S*Cʐ oBy'Q' Fv0q/ bQ^fer`Y]w_`*-@yx1 z ~#ȩkyV܊PCr7k(("M g.)}ze0x9##L 8g;O;,\oqCU3+yH'ݷS)5ʨMFms7/^-rҊaw&>>̷N u5D/f?ak868w5-i&/^NH9VB+D5T3"0vZzKݕ2HUi(^H_cSha6j*c+xNn d\zd2SZ%n0pB!pewPA{n,9] 4>݊_ie/"p􍂅Y+h@:.->bӾH(ᱠ3DfA3׵oH-V]&tF,(QV 128?ل?T b3PH,Q-ǗÇgh `tRIߋe/\WҰQ+*߁ΡNO5 p^ B_+c W 'b`3id68vqb`Hdw^Gv?2H)-u|"yoUbs9"3 `MamOeϫ;/.&̪+ mM*qw]RPģ$whZZ EjR>N[[y|c~o {;6:,xyTu}z4oAs_GUT8~Om[nI:4apWRn'\«HBS2H=@V^mR4  Mɫ.]=lK^O/OO7= ΉxTّ2ȀlA2B-%WQb}N8/H̼S%g j>.I>Seԓӟ\K_/3+pEU<|mk2a@ $T ˄-uX7OZ~)}XCճxbu,I96FՉU1W  u;tQtR||ЙS7К-bסY*nBOpnR֛D?268\FWPFnÿJG&ϧĦm>,lm>OG`z_6V^~NK4|QgT _3jJ^IeW|}it| Tdf<ݴ5N$/rCEi1T:bj#\*;69ֵBHIWe9SiUk.90&?R'5z\s2~IAe0LV|Nml6-R[jb>'6{e1p s+C(t#<^}Yny͵KhOjc'7nvT1?UMa}OzzPF*|﮵M (ӆ6 }Fܝ, /YӣM|N.U qLfm]@#koeMaL-VjTAiڛ|Gش BQ=0[R-d?iK@-I%aa vWi?!Tl(k)AZϥ='"(< (Z =d󈷰,F'V5J5J8WVsOXRqm~LVM7/r.\1io9!.^NJrāl[/q,з,M9|ۉ/ym OYlec.MDžoFsK?f>I,qmr$)͂SЪRàvِ˯z.0^Mcb< |*Ր]1 17G*jf;+ߊLՒ G9&/;9v=ֱCyk)Ǯ9vf4]B*(XCZBY )~s<~$ŁĈD&D&F&:HM mO^KX%b1H٨D&FOؐ"'KfLjZ`y8M> 9MR ԚO%\7\a+[7B[BC'rz= A=7}OY-m#&mb^0.yzet(ɱ@F?*x 5B[ɳWz nK.y8{ϢUTD Y=}y&M*~NB["~ ݑ+m;Hn2gAA_B(4}M;⑽%:t1B}]A!nb0_6t.ϸC&6Ly@x_7D~wӚ01}4%0C7r)'Zi0\)> |jH+1y}7O]q@J\]D[sW}gٺwNoEir}"ZD\)oW׃=?oJuאu?BY~ST_҂g5KR^c_a xXʊ|8Uuߴ{L@Y˵"qo%]+Lߒ}@_ZT&o'F2/@*}mZ(~H:ûbxi| ~A7՗O yv n>x~@sB|k߲Hwb[c'H'sc΀ƽ 7ѯF8>xQn-G˨P[1*q 4}M#<^B5371aI+lډ@cuEb<&8 i6SyKOMJQ3 !S<&8 i6y,>M{D+v2i AByLp$;y~RCx67kᘼOHd*xG2npG0tXȠf%hdy% dٮ`ܕtcU $ݔ -{ \U7{.`<Vҵ~ -{mnZ;d -KayXxqWҵYYD N@H. &h _0܎#k^+ŘnCqU.bXr?K\|z-9y c9=~Te 4P[G٥Xw5*va]qͬc>3~WQ R'PaMdp96r4p~ 5f.=f#MMٚ-I6r9Z^z "gzlc6_VDVvVkK@b .|@7tG*I:oɩ佽HJ]<ϧ1![%U[9 wK?fsgke)G 'o(icFsb,PcrZWe|ǔQf62>jS`ΊuS iFSsx71L.vNܽI1|/=iAKFo<aLeS,MyL d&71BU:BU I'% C1Ea$i.,^[[XImxzIENDB`perfbook_html/img299.png0000644000175000017500000001223711672746055015333 0ustar paulmckpaulmckPNG  IHDRhA3PLTEMJK# b``mkkXUVROP856C@@wuv.*+AvatRNS@fIDATx]* e|"#aQjk;s̴.C !$=-wPJҽh_sCסӖ];͠sb/RÒ#)j&Q%5Z* nLm9E|(:[AѦx &?jWXfY[H$1T);R!dDQ3g$| mop^*<gǑQj> Mvo͏iTݤ5l@f ~FnR5 nRBwM0Բ]+Obg,Ko[Y6.k-ނr{X'ANhZ2gɑpM߄bJlߎBW3|&ؾ|&G5 QAh;!. 7Lүy\/8# I`!n-k%&" Ɍ/ $5 5T,vi{@Ç(Y̎Nqtæ섖dB^ mdzZ%_ ]V/bY9ԌG3.\Y| U~#Ldx$zƎJh]~mr[3-J惠Qjk;rT ֲ]&vx C@6 l\3H4A}27G@df8.)DQH-ztTN\&kr ҢNbڄd 0XPkAՔ: ٔ~<]u& R `)[Txx5=5(?h[lKǪ+~fKRq#xGf-9݅3 SŖ4M$5cUla] [#L hS?g a} :Q'2&j+껴Srk6vlA/D0޼a xF>-B&qrHNU}IG{'f˝IX, ܱ.Ia o~ԛ֛J+u8bZM!r~M)67iTݠ]ouiC(c>[>hHapAGg_ :~E dqAh0LI)iZ3  3@ފ'aW$lם lRgqInM >`Z_hI6N/)@@m|u^uu;z}ǀߖ`fjd1d9N[,B m:4&s}*ڃC>BdOؗ-&yB,Pn0! wQ4PqaM \@Q+D$(pңIfr>lf *E^*;b^HO '6Eѐ[ffGbVr F4Hlh~f9keo:1R$*ҜNeON؉q ׂ [F%\ k&<>>ZV NevoQ|?=3%,_/wk;/8Z[CUݢ+]Āq>?&9>#k hottңؠ5:if$F(Hrh8;n/ӌK*SC./W4Eൃ5x [BhZ qC ݼ#V49h#/&?<x dUp80jWj! K1d )g!cedKA{:e2vpqͳھt$@uʬ3~ׇ$ԥ2yXٯd֭Z։m8(X8˕TZwDc7_oP jp7ЪPk\zZٕڬȳ'@KImeJtDaBn z=^#2އUۄn4ps޸+rkxρpqi 9sX0@K1PsL02b#dG(Jmkh.W*% 17w'Aũx#N"޻nj7 Ȇp 9֒@p{*e^1Д ,..)jnZv(6(oκb/vp"^t#V 8\eL'=$tz֥i[UNū}H)XewH&׫Wy DUbf3j G>n 7IENDB`perfbook_html/node405.html0000644000175000017500000000734711672746163015657 0ustar paulmckpaulmck D.4.2.2 Data Structures


D.4.2.2 Data Structures

This section describes preemptible RCU's major data structures, including rcu_ctrlblk, rcu_data, rcu_flipctr, rcu_try_flip_state, rcu_try_flip_flag, and rcu_mb_flag.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img289.png0000644000175000017500000001145211672746161015326 0ustar paulmckpaulmckPNG  IHDR&a@Ǫ`PLTEݧwwwgggUUUMMM333''' tttfffZZZDDD@@@444"""n0tRNS@fxIDATx] {* ŝ]wb&BTڒ9wƗBJ… UTuqֹSRTWG(ڔbQ_,Gߔ2GWb&:` 7wTf@1ֱA[}o&]iSJDpoXJSSe_'j61rV*z0T#_V)J1V6[i2[=ڗ -eLb€k.Hfr V1.?s[]5#i٫s]VM))MWyN)K>Qsn4]-f@MZ5DkB\<;L/2UWSG`[^ &Z?nг,*/j*먾MR9{+ nwJ-^ o(ucV"-ؽ 5裫K/@ZTj -"MR(V|K˕Rm|.nEa + օZ =D_-* x'vIU4 AP٫RTKF.ѯ<*ƣvRU&jR3QÝ\8"R3 vB67|g0EARep2-P\X_.ִ:!L!kިEozaNFJWdPA_ ^XTP/!AE~0ϦJ׍TU*ͷ-]ji.hMhyvcfIy&_Pj HkR koDkXѤhД!{&XL0+4hʄu5BS&2herM~Obf)X@vDY *q t|% .!f{.҄k?kR&ū5i3fMDC)r>ZP675ADIӧʘ4ie֚L1FC9uMluwD0DКNDav&M˧ ɤ 4|5Oj1Z6LC*"6VQ'}UIac5~f\54t`&JMQr}p)Sq#CJׇtف`,=IIkƱ,$h &4i~`nس5S`:Dx2׃I&ŏτə!=&'ҿ; Lهjrc,ĠuyqU90ibDkO67&Mmf7739&Ƈ02 r/ Jś+r.-Ŕ1S85&fzu򼪣G,1Q=͈iw66nx|p"LPsM0A e-^ X)`P8Uз\郇ϡ1ɨƴN/SaC ӶQ}c1%׷wvD&S`r} ~hD MΫ,i#*Pi#* & 4=q\K?s<L)0uL"}x3TG}QSs+8&_ddzNq(}20ܴpch4ZxI"N&L8 p0Y0MUġOp2?eܘz+¼,qTɆ԰Pb&>qZl(́I\n }6QS< &^J!ߋmL,EZԔ~Ʀ&GkLiZDDXGT^<TW8b+؞'*LŸ|T$LSEb~rLXz]Tk6TMZ=R<Ä 0U+yiU`Vb0崌9b_Ъ ~b05z~"uLѪcffoĆD}c1ˇ{#6& @0QhLՒf c'ˈ ,xk c*7:Dlp 1S0%.Iõy"[Ԙ֧$ASr0A=,8qaј'cOT6h>bO )jHL\ & X7L{RNm\nʣ1%9z ~":MlTy.BLM9> Cbo gEbHLD7FÄD |"c~ }樾e^L^[0Uب z,LIix/Y׫ԘN|*'G)8[8x^L BL\#xnkQۀ1`8ۀ15Oq04A '!9 ۠ô'b1qjl>+&NχyX0/Gύ yR&<W)/OM[d"064F@<fbglhL M #12`#, '%rQ &(2` )` )`z|L(0L|Tg/1Tet[L"^bL"'xqLDUz]ɓ_ !7a*3yF֘s=UVf30Wn`Yݙx6oPSl͵>X/]t9'xND+0JLD+0JLD+0JL &(Z{%Ri0M,/I&[+I(8iL G+jBb\bU,EEyĿ$M^I' *ֿ- omC~EW +"ǰXkaIq%Px68&El&Gѽ)!EH|MY$ֲ(ĉJ[E i*Oy\4r45FSAeMrpRI4iMw M%MU?o-Iz\}c5etV's@7W,˿@!i*,IXT+aU 4ДiheMpX+tI%Єߍ +D AG wK uK uP|OMͨNQ"IMlM݌蔚kjojkdԖI1XΨ-Rc:8fQ[&t cqLeRjL2Gנ)XS#4K!_.G|ɉ&XӉQ_ bPu'xJkhgY'M-Mp- [iZKzor~X박NҞ|mJMөq6l%'?-бذ:PgY2l%&Jgy)9M7ϠK;ݟ5~4i +jݟ5~4##>Q Kl [i:7GqLgYlТ"5]>iz]"ijϲؠ%MAmZY, Zt>gPjI}-h?bT-7HV S$ŏKs T0Ii"ɚ|"ĝI<MgE)lp C.7.6 POWER / Power PC


C.7.6 POWER / Power PC

The POWER and Power PC\textregistered CPU families have a wide variety of memory-barrier instructions [IBM94,LSH02]:

  1. sync causes all preceding operations to appear to have completed before any subsequent operations are started. This instruction is therefore quite expensive.
  2. lwsync (light-weight sync) orders loads with respect to subsequent loads and stores, and also orders stores. However, it does not order stores with respect to subsequent loads. Interestingly enough, the lwsync instruction enforces the same ordering as does zSeries, and coincidentally, SPARC TSO.
  3. eieio (enforce in-order execution of I/O, in case you were wondering) causes all preceding cacheable stores to appear to have completed before all subsequent stores. However, stores to cacheable memory are ordered separately from stores to non-cacheable memory, which means that eieio will not force an MMIO store to precede a spinlock release.
  4. isync forces all preceding instructions to appear to have completed before any subsequent instructions start execution. This means that the preceding instructions must have progressed far enough that any traps they might generate have either happened or are guaranteed not to happen, and that any side-effects of these instructions (for example, page-table changes) are seen by the subsequent instructions.

Unfortunately, none of these instructions line up exactly with Linux's wmb() primitive, which requires all stores to be ordered, but does not require the other high-overhead actions of the sync instruction. But there is no choice: ppc64 versions of wmb() and mb() are defined to be the heavyweight sync instruction. However, Linux's smp_wmb() instruction is never used for MMIO (since a driver must carefully order MMIOs in UP as well as SMP kernels, after all), so it is defined to be the lighter weight eieio instruction. This instruction may well be unique in having a five-vowel mnemonic. The smp_mb() instruction is also defined to be the sync instruction, but both smp_rmb() and rmb() are defined to be the lighter-weight lwsync instruction.

Power features ``cumulativity'', which can be used to obtain transitivity. When used properly, any code seeing the results of an earlier code fragment will also see the accesses that this earlier code fragment itself saw. Much more detail is available from McKenney and Silvera [MS09].

Power respects control dependencies in much the same way that ARM does, with the exception that the Power isync instruction is substituted for the ARM ISB instruction.

Many members of the POWER architecture have incoherent instruction caches, so that a store to memory will not necessarily be reflected in the instruction cache. Thankfully, few people write self-modifying code these days, but JITs and compilers do it all the time. Furthermore, recompiling a recently run program looks just like self-modifying code from the CPU's viewpoint. The icbi instruction (instruction cache block invalidate) invalidates a specified cache line from the instruction cache, and may be used in these situations.

Paul E. McKenney 2011-12-16
perfbook_html/img283.png0000644000175000017500000001242511672746013015315 0ustar paulmckpaulmckPNG  IHDRV-6PLTEb``MJK# hffmkkXUV856KHHC@@wuv.*+M'tRNS@fIDATx]EG)O S (1iM*Z+Qj ;i\J5zG\8jRFFUVRzqy]:UVU*&J?jly_hztaU¼*|_eW2K}YC7P^Qwi.q8y{^_SJ,KiM#?j뒧3 %~ٽp֭҆}P"m+mq3:Uzkҡxq Zvn&n km͞]ר(E6;p*(Ei &HOwqF| >Pj'%ny> dl񁴉$]_V6uM:$T_6gOF:>ʮb{Y)Ix*a ZͲQF"9oK[#pXyZyO$o}4q-1icq7 k$S #tMWZӨ3:5 ~Hz?P)' 4]60iAGxjܩ(X2v4~A8!&%"?T%"9a<#߂ G K6feJ PV"C,j%xFŘQ#6FiގڔiՎ&u@W>1 6]6zi2!3:[]s+r5&:hC%ӂGMa]8Kc<*&5펝nbfX,J<"n;F8C7o2w]ޯ^->b.kU_t@$;/w\F /"e qQ [' u)D}8ًA2i! rBbj6-Lv͑G9!U۞UUjBC)ZldQiī]dz%ud\\j+E *'d8a1>1t҅g/`LHFE/8 _ Vnnz'v4t/yla`)ie9Nt'tM ɏb/e͕)ɝdF[j KN*E ⨮X!@z_ki]iuMuU}ƛRg!֕2llj8-iT нG[5x mpaz %+-Z'~ve<"n||.7~dа|aҴ%p- 3ZBTz2haGK2[jLUzGf ?5[k l8]v0Nc~Gk:1zx䮝&JE-tfedTkMvFLXBb{h\ƚ_AwPh]4* Numc]s (WB  YZ v  &ۇU6DMШn`Tyf:b+7&1 ElJXVMu4,?FS cL:yJo1>,FشΙc$ӟvh{2V{tg l}XkReTdpJN_tlIDž|U<9e 3tzO&?3 RhLWJ9UY -4]V#KC:9`31Yq^ĸ,Z 64yO.Ac8Vu*|>Q"An:Wfƙra=L<-WˌU1QΉ` t,0Gi g=qw1rəQOM2UL%攚lq:iW;GI]ޒmo4tU+)**1U1[Ys{lcaX}Rs2G#K̟͆gҡ9-wYgrט5~fϔd + RR!ga*>ZU~ by6d++c wYgr75~fƳD7=y& Oi30gMƹlvYm2OȯvMzbĵ3Wc(/rd6<WRfE9.j`Ψh.-)-!{UI]ChSEr:&uE. _%bRUl}TLh4Wp/rIHLע,I;A\e٤!fZ%!F6 D}RE9$k^ph͹Éc2.~ג?92Okg!R3@\tU .f &e5l47t:@?1JLվ \[m;{SGzķYbmӺeMXtFTsW\f 5U,%37z5 LMC5 ﯡ?$ wy~pzĜB4[*1r!+vb?hwAC ޚa.}-XF#_DG5PT(γ.["W8N|=h 4 wHeTzÃTy׌ GE+:rtCa~3Sn@a  h/Anփ`*aދ7nWGd&_$:kƑ 됸p }ǵ@ Hn,M k=LU(Q,5kMKc(t"7BYkf=!o@7n8W8P?ժ̫@:x`]T\ $ ]]T-mB錙#<ؐX$nYݱG5^YKڤ#0PC8s(񃢘FHX+R{D$gެMG193I5R8;ȏ6eqFbf,#bZ<C+SX$lmJD'hQCx9JӰ5\ҹ$N`(1ˣs@13I5T~ Y]/]>TZ,{)nQRrXMZ$EGšKr,l+ Gطcr&d.ls8ORs9\^ q6㨗,d9UK:J95K+4)yHcjJ;-X#֛oG-dxTN7mi8gNDdEJuV*':%7V=y| FlkfYH2|vxk\q27;-fm^[fnV̓eǑvK ]%$.6HE?m[Y~,{P@i[/ O۱b! g]5L.2xH{sYwފC"b4˽[Ht͚[`/ z qDR"طDRM^, t߅lo>,yLmߪG⏕k3uy[V"oh,;Ip%)&1kb,b2F5][ʘ]zQyOÙlȬ۷.cM2fE^TlbR RojdԊ(cIVNvc@wZ{Dffdž}߰|XG@ͺoþ9X,aEƍ ɡfL*9TQ|DN!f#eaCHAh ?5V|6Wqk#n>[`o:ژht2ėQJ&t)UK '>fǜ΢4hy[ٶ3})xuJ2Z% =<~29=*Ag:ƚjeYc졊wc t--mr$愈ӓiZQ_'2#k+DO.p`k)Ev|J#StpX"5vFh8%vL=m-XFhSD7}DYy'zJd}]v A'h =M~5%LdG7\hJ^و#f X6Fe6ᢕ(Zit:vJjxXEe򏍨,aEI#Lr.P.c{P6*\wjZ֊hǵf27Yk3y`w_%#6%2xf, KCЛ4`+N r {/8.M)haqsH/+hϋ>+i B?=bS9#u>J*/,KhD&˚r^2)+{c-V( gܢ-mTV2URL r@Qz|Gv"J-[G'Q$DqVFc,B <{gS2 Sl=5:h+](7]+TTg&Rex^hh"|5O5j\f" |39H`D)$8cᴡ;P#,&] Y " ,Ss_h-/ j#U2+WYyBB x,|_@Dn&j܆=/hH#=#4)xzj&)u|xV468*X]|vpLe>L+7xQehٲ Z#L 5–1#Lgg`_Dg 2=s-8 y7LnW~g& (0 <_}ʠUYީsRRڿp@r4ʀ$L &eP](Հ?DW:K^0rBgXc~f[-咗vZ@4م KFX?_36|_2 P)ɞmM,y z?.w21I1>Jޱ)،GQIYtjl7C윶,[ 9D' =MdӿZy {u:'ոT{N!rÞr$׎2UB"9Z=8±Z{ނnq;drnt p,A>lFK=5IۅWm+p&WӦ3(%AXYV9[jr."6y7Jnuw/jx;gja9M3=礪mΈ?3.HVNΙ jda#MI XlVKmG%uR記[m5fr Fqr/|R^[&Ɗdef%o Zm+󃔯>ڀUOaGj/$_JtDHԷ[J{4 뷭9;z0( i$1%+..jޅ]7O2ڵmW#9:Ğ&dfٝ.Ko ^ɫ9];<_1U2$< qnMm9K/@O_:-^atO_kwT7FM%EdTT9fq `s bM(< l#sm5gNmifij!( ~%Hr7Ǩ͋%4,\^T5(׹Zl͵ٵ0C|zx^A/#Hv$ƾ4&?,!}šok@ZJb藥u ^b{iK.kO^eH~~힃[iRG2V~~U 'wcLjEÌG;x;5HLNӇ'{7!3yyV˴^&>;*x\.s(` t``IH7b\I-_N'ङQӼ^&o>GVe/GP]hkuQZ]XTzlI׸ߐ@B%Jl-j@] !m1gctG_5]P5bhQ:~ߋAs5*{EKF~1U eЬh@ݚF=[dKꥪ%|[gǿuQWgo1Rqbz>KTGPsq*'m=M CSwvI _] Wa6Dz10N+T*k[I98NVobCR)Cd̅#131o4W3*fIncOW-_laۦLUm meYN󪏜UtvdBCP]&1 # }K2xu=_` gN<{T' -iy-d8I344?'o;8.Xl`>ho!ȟZL˲nC;10T,`ߢt>_:Ŗړ҉8?<_RjdNӖ ԞEr Tq+_0jF;nT{bquzΑ\\rZ:+feE{l֯*~%Do hb&o0Qx蟃'Kv!͠-;Ę(hOU*4kHVsEdڻ_;=Y+oq,^)<殓`w{`Hav!=YڥV-]L<)CLit3[}wzLm\n[\nA̸~_R pwM &|JB |?vjsEf6rZ4]򯯽&Wawd7Y~2 UۨK"^jLw#ųOnLbPmLyKM_n#szd gG2/XH8'2؍dd LD(%B~@2L{F C;2KeBMѵg2R!ÞNPvڛ=_Ӥl"L}z+)ckaZ{& }`#͂Sѵ'}lPhts9nae^N1 ~j[#/ZXxRnqX0plE%IqHDԋ8uX 2¯8,;^EdW5J?)hW²ȟ11ÂKǍj)7)|0ڝ^,ǩ䦂fM+纑XfK@|% /]r~-2}"3~I:Nx&S_y2L$Sw|m'߁Y(tZ)S2 _mc\-X|3}QRd C4>E%/tf!/ގ|8p ܱ^R JYPI)}efSl'{{--3M K⦶t\33ҭZZ qtQ˪J*{oY FT:\TlP[/W}_aN^8.?9{ < "(1H}x"D/,=xߞrJi,Ws_ '#MEǶ[n?vv‹p{ằ3(x4tP&kJE!xj۠n!FK4/Ff>/ )Q7 Mҩk\elT&.+0sv &.ۓyU۷owaF vx6=i 8-^;Xʲ&j iGTx?* Q$w'"X mr ,//Xnܸ쌽yO!fY`.&T\۶Q>'I:-dtFޞbYD+]JAR6fsFC6+흐ž:eM'%n4׈0/xiV=C&j܂YK ,ŭKO¦a1P(qص))q~2AqA&pbOY",cJ+Fiknve؂%Y\Yt` wpXabKb^!XO/#Y9A§i~f8_~Iq}&М>M;Z 糕لC?8ݦij >Cdʆ /90g>&q[o|.PɫTĞ)_\LE_.gS=})6O]TO䅸\PLŤlJ@LʖoIW!>AdCTCLG8vޑ)wdʍSpҞ) W>_pVLie(y{ϔ=S$ئ7I9GL$}|=Sl+GLDO3g[Y3%MߞTc{tr8D!ҏof`V({%z [n7a2;0l{{v=-nof'%{ ;a䞅=mrSC|r,G+>L䭂 T!zzNkcd~XD_w׷/:nb 햅4,2qy?,D~vK3Mݲn< ljKj@l>[o<~%u_=oܸ ' )'_Qv d}^A ZUVS v^Lm dx8jq)\a>kOH:P嫢Ѣ;}T^ph߉}V闲 wv>`&4??MrX:vs9IENDB`perfbook_html/img245.png0000644000175000017500000001446011672746150015316 0ustar paulmckpaulmckPNG  IHDRT)55TPLTEb``^\\MJKZWW# hffywwommmkkXUV856iffC@@wuv.*+a_`<tRNS@fIDATx](v8q$VgZb[u]RtɒA+V.Mv/u'hiVi3뗇Q]:L joЂ~oWE/RA'YBXI9pyCymM2\~wjcZmΫWҨh& ^3iZ0Ac''}9`Ԭ#ZJ#ce=vUu$r}kyhl!aݜA)cUؠf)'h9]^ Q]-9l'Uůj8IPg @- ` |OK:ѠGóO ӰU7CLMv>HBj{}eakaTGk |`Z%cX>9} WޣTS H @5jb6DZ E1u3ub+8$* tQYH̘~{AN;|h=W pWU0NaW8Z$qGV9(0j04C44Q*K=jcaSAj(|9zr,`tB8r-\Qj6ԱqB]BQ&X,?b43@"^Aa ڡo*ޘB"PA K 3<Ve Ŵ)!M6*ɡ;jBĊ0GȒ1NJͱ?c>;*\Ofw[`Ui{~>gFG)@jen?]#XhU &3ŤF^lQW| OXEžZWZۢ"_b_-I Y@f kՇ[VWRHakTtVZ,Ƭ@#!4nѸ ߏYE1vݥ_UV}".OEmmh5]&KKKj"W4sBRBngj.U9<0%1и?f%80br~ yU%r*͌[FRx9l17Pu[CDRTt#U<{HT =Gqn/LXfdN%TUloCg{d-L/: cU֠‚x14=.^}9,aVЁV.f k3SofP q靋EOW 0sgr,{yՓrʢ XefJfw78Ihuvʁ陆R8kZUtek'1YqY q:(&r#_? 3qwYe;>qEƑb.!MqPcS&gP+G:G|1ްnϽ`nĕRPt3cCyLusASʾ?( &"IwWWl$EZ`qC봪ׯlb-:cxe rruCdYQ?ahja0*XK* *bcSÖSu"#-E4M5@yyu9[սКQoO! r8[W Xx4c] [?ZWL^" }A"]HpH!Ο"m%/`Cָ6CWb}ԢBDHt^8b%Iu1u>b&pvsGGo,M޻8◅|(fqv\o`fTH=,m^,Z?QA\:KÚFi' a7+)A~X~)d>)JI tty ӖGӬ2+߈Ϛ Uհz"UyU!  jI "'y|zvT00z'U퐐Qfh6l Diǽ']r{gzelToGL#_FDFrh6DZ d2A#9Cnzݬz7>(qL03ࡁ2%SQĠX{($WX(W4jlit5>t>'fwI^rmJWVl?/I9$;oڀӺ>V8CsOML^Qrb"W`-Se򁜾Lc`ϮzyޅHTǐ{a &jԷAp .\ F[Ԕ:)nbtE9x[mZuo%Qi3ݕ J i{gݘ`QA2(:EWbw][^i}S6ODq?Yź0ؕ wQi}٨0A[rTƑJw#U3 ór…wbE6<< s79`-~X_WVvW񀐃~ ftI"ACӾDdh@k kejqW)]]h<o0 w"a/YVAvW$ 'n rlPr˓ pRgbb늿'fHV.\<.*un=dK!pg`>Z0ٵYcg<(wcC_bo؝o+W7H7^n߅ݶHmZuRz96<\CI0XJ+O_[VSۭ[^ևMC]pGm|Yoe+L bH.}$K捴v?9qL;2ޘΈA$d{0.||}7\d-6PV#E]cdc"KLhEIX>}ˆ63#n/plD4wlzL8%()]6{ FckF,P~}a6<&WpٔGMdJ?ȩMiV{T ?5RT3֏9oa?Q$eݠW&ޠ&TO^~ nGŗ[Nf ^E],L8h[.<]\ beZԨJv|"F&R,ӎ%G7ziinT1R]E+&.1ԵL Vb MQ8n"8X"Vww됛[zr1ŧ P^D.Tjz!Pg6?3y>)`HYGؘ?JbeKx[6K/C~ꈭ]<0ҕ!䒴.L[ ◛Tlm \|U.?bDPlOR.HF0),3ml \fȠ2?u..AFIdnWC[d" .~z~-yu׭mȟڞ|i5}!D[^$*\b<6H'3]+TTZL;4X,KaqWXH'}`#K֠$*.1!? :#GE+ ~1:2M,,VIXU`.5.B*R >Bע1 o.J2;/!QEY+[t~;o 14.2.13 The Effects of the CPU Cache


14.2.13 The Effects of the CPU Cache

The perceived ordering of memory operations is affected by the caches that lie between the CPUs and memory, as well as by the cache coherence protocol that maintains memory consistency and ordering. From a software viewpoint, these caches are for all intents and purposes part of memory. Memory barriers can be thought of as acting on the vertical dotted line in Figure [*], ensuring that the CPU present its values to memory in the proper order, as well as ensuring that it see changes made by other CPUs in the proper order.

Figure: Memory Architecture
\includegraphics{advsync/MemoryArchitecture}

Although the caches can ``hide'' a given CPU's memory accesses from the rest of the system, the cache-coherence protocol ensures that all other CPUs see any effects of these hidden accesses, migrating and invalidating cachelines as required. Furthermore, the CPU core may execute instructions in any order, restricted only by the requirement that program causality and memory ordering appear to be maintained. Some of these instructions may generate memory accesses that must be queued in the CPU's memory access queue, but execution may nonetheless continue until the CPU either fills up its internal resources or until it must wait for some queued memory access to complete.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node15.html0000644000175000017500000001357511672746161015572 0ustar paulmckpaulmck 3.4.1 Work Partitioning


3.4.1 Work Partitioning

Work partitioning is absolutely required for parallel execution: if there is but one ``glob'' of work, then it can be executed by at most one CPU at a time, which is by definition sequential execution. However, partitioning the code requires great care. For example, uneven partitioning can result in sequential execution once the small partitions have completed [Amd67]. In less extreme cases, load balancing can be used to fully utilize available hardware, thus attaining more-optimal performance.

In addition, partitioning of work can complicate handling of global errors and events: a parallel program may need to carry out non-trivial synchronization in order to safely process such global events.

Each partition requires some sort of communication: after all, if a given thread did not communicate at all, it would have no effect and would thus not need to be executed. However, because communication incurs overhead, careless partitioning choices can result in severe performance degradation.

Furthermore, the number of concurrent threads must often be controlled, as each such thread occupies common resources, for example, space in CPU caches. If too many threads are permitted to execute concurrently, the CPU caches will overflow, resulting in high cache miss rate, which in turn degrades performance. On the other hand, large numbers of threads are often required to overlap computation and I/O.

Quick Quiz 3.12: What besides CPU cache capacity might require limiting the number of concurrent threads? End Quick Quiz

Finally, permitting threads to execute concurrently greatly increases the program's state space, which can make the program difficult to understand, degrading productivity. All else being equal, smaller state spaces having more regular structure are more easily understood, but this is a human-factors statement as much as it is a technical or mathematical statement. Good parallel designs might have extremely large state spaces, but nevertheless be easy to understand due to their regular structure, while poor designs can be impenetrable despite having a comparatively small state space. The best designs exploit embarrassing parallelism, or transform the problem to one having an embarrassingly parallel solution. In either case, ``embarrassingly parallel'' is in fact an embarrassment of riches. The current state of the art enumerates good designs; more work is required to make more general judgements on state-space size and structure.

Paul E. McKenney 2011-12-16
perfbook_html/node46.html0000644000175000017500000002756611672746161015603 0ustar paulmckpaulmck 5.2.3 POSIX Locking


5.2.3 POSIX Locking

The POSIX standard allows the programmer to avoid data races via ``POSIX locking''. POSIX locking features a number of primitives, the most fundamental of which are pthread_mutex_lock() and pthread_mutex_unlock(). These primitives operate on locks, which are of type pthread_mutex_t. These locks may be declared statically and initialized with PTHREAD_MUTEX_INITIALIZER, or they may be allocated dynamically and initialized using the pthread_mutex_init() primitive. The demonstration code in this section will take the former course.

The pthread_mutex_lock() primitive ``acquires'' the specified lock, and the pthread_mutex_unlock() ``releases'' the specified lock. Because these are ``exclusive'' locking primitives, only one thread at a time may ``hold'' a given lock at a given time. For example, if a pair of threads attempt to acquire the same lock concurrently, one of the pair will be ``granted'' the lock first, and the other will wait until the first thread releases the lock.

Quick Quiz 5.8: What if I want several threads to hold the same lock at the same time? End Quick Quiz

Figure: Demonstration of Exclusive Locks
\begin{figure}{ \scriptsize
\begin{verbatim}1 pthread_mutex_t lock_a = PTHREA...
...ock'');
46 exit(-1);
47 }
48 return NULL;
49 }\end{verbatim}
}\end{figure}

This exclusive-locking property is demonstrated using the code shown in Figure [*] (lock.c). Line 1 defines and initializes a POSIX lock named lock_a, while line 2 similarly defines and initializes a lock named lock_b. Line 3 defines and initializes a shared variable x.

Lines 5-28 defines a function lock_reader() which repeatedly reads the shared variable x while holding the lock specified by arg. Line 10 casts arg to a pointer to a pthread_mutex_t, as required by the pthread_mutex_lock() and pthread_mutex_unlock() primitives.

Quick Quiz 5.9: Why not simply make the argument to lock_reader() on line 5 of Figure [*] be a pointer to a pthread_mutex_t? End Quick Quiz

Lines 12-15 acquire the specified pthread_mutex_t, checking for errors and exiting the program if any occur. Lines 16-23 repeatedly check the value of x, printing the new value each time that it changes. Line 22 sleeps for one millisecond, which allows this demonstration to run nicely on a uniprocessor machine. Line 24-27 release the pthread_mutex_t, again checking for errors and exiting the program is any occur. Finally, line 28 returns NULL, again to match the function type required by pthread_create().

Quick Quiz 5.10: Writing four lines of code for each acquisition and release of a pthread_mutex_t sure seems painful! Isn't there a better way? End Quick Quiz

Lines 31-49 of Figure [*] shows lock_writer(), which periodically update the shared variable x while holding the specified pthread_mutex_t. As with lock_reader(), line 34 casts arg to a pointer to pthread_mutex_t, lines 36-39 acquires the specified lock, and lines 44-47 releases it. While holding the lock, lines 40-48 increment the shared variable x, sleeping for five milliseconds between each increment.

Figure: Demonstration of Same Exclusive Lock
\begin{figure}{ \scriptsize
\begin{verbatim}1 printf(''Creating two threads u...
...
17 perror(''pthread_join'');
18 exit(-1);
19 }\end{verbatim}
}\end{figure}

Figure [*] shows a code fragment that runs lock_reader() and lock_writer() as thread using the same lock, namely, lock_a. Lines 2-6 create a thread running lock_reader(), and then Lines 7-11 create a thread running lock_writer(). Lines 12-19 wait for both threads to complete. The output of this code fragment is as follows:



Creating two threads using same lock:
lock_reader(): x = 0


Because both threads are using the same lock, the lock_reader() thread cannot see any of the intermediate values of x produced by lock_writer() while holding the lock.

Quick Quiz 5.11: Is ``x = 0'' the only possible output from the code fragment shown in Figure [*]? If so, why? If not, what other output could appear, and why? End Quick Quiz

Figure: Demonstration of Different Exclusive Locks
\begin{figure}{ \scriptsize
\begin{verbatim}1 printf(''Creating two threads w...
...
18 perror(''pthread_join'');
19 exit(-1);
20 }\end{verbatim}
}\end{figure}

Figure [*] shows a similar code fragment, but this time using different locks: lock_a for lock_reader() and lock_b for lock_writer(). The output of this code fragment is as follows:



Creating two threads w/different locks:
lock_reader(): x = 0
lock_reader(): x = 1
lock_reader(): x = 2
lock_reader(): x = 3


Because the two threads are using different locks, they do not exclude each other, and can run concurrently. The lock_reader() function can therefore see the intermediate values of x stored by lock_writer().

Quick Quiz 5.12: Using different locks could cause quite a bit of confusion, what with threads seeing each others' intermediate states. So should well-written parallel programs restrict themselves to using a single lock in order to avoid this kind of confusion? End Quick Quiz

Quick Quiz 5.13: In the code shown in Figure [*], is lock_reader() guaranteed to see all the values produced by lock_writer()? Why or why not? End Quick Quiz

Quick Quiz 5.14: Wait a minute here!!! Figure [*] didn't initialize shared variable x, so why does it need to be initialized in Figure [*]? End Quick Quiz

Although there is quite a bit more to POSIX exclusive locking, these primitives provide a good start and are in fact sufficient in a great many situations. The next section takes a brief look at POSIX reader-writer locking.

Paul E. McKenney 2011-12-16
perfbook_html/node440.html0000644000175000017500000001154311672746163015647 0ustar paulmckpaulmck E.7.1.1 Task Interface


E.7.1.1 Task Interface

When a given CPU enters dynticks-idle mode because it has no more tasks to run, it invokes rcu_enter_nohz():

  1 static inline void rcu_enter_nohz(void)
  2 {
  3   mb();
  4   __get_cpu_var(dynticks_progress_counter)++;
  5   WARN_ON(__get_cpu_var(dynticks_progress_counter) & 0x1);
  6 }

This function simply increments dynticks_progress_counter and checks that the result is even, but first executing a memory barrier to ensure that any other CPU that sees the new value of dynticks_progress_counter will also see the completion of any prior RCU read-side critical sections.

Similarly, when a CPU that is in dynticks-idle mode prepares to start executing a newly runnable task, it invokes rcu_exit_nohz:

  1 static inline void rcu_exit_nohz(void)
  2 {
  3   __get_cpu_var(dynticks_progress_counter)++;
  4   mb();
  5   WARN_ON(!(__get_cpu_var(dynticks_progress_counter) &
  6             0x1));
  7 }

This function again increments dynticks_progress_counter, but follows it with a memory barrier to ensure that if any other CPU sees the result of any subsequent RCU read-side critical section, then that other CPU will also see the incremented value of dynticks_progress_counter. Finally, rcu_exit_nohz() checks that the result of the increment is an odd value.

The rcu_enter_nohz() and rcu_exit_nohz functions handle the case where a CPU enters and exits dynticks-idle mode due to task execution, but does not handle interrupts, which are covered in the following section.

Paul E. McKenney 2011-12-16
perfbook_html/img315.png0000644000175000017500000001667011672746061015322 0ustar paulmckpaulmckPNG  IHDRW `PLTE^GgggMMM$''' /vtttZZZVVV @@@j444S;GjtRNS@fIDATx]]:cYg#3Ƽ[wtzڝN"E[r)Xp-aElB@oAɏd?7,Axjކ@|e\䖩CꏹF!r{AO7 )(=^D6zI]K~1h8}.yZzry RڅHѿ#׮L8RPÕip~Zr/D\f}1X\ܶҫ4ꔾ|Ay1^]_69 ڳڼiK+>soe}I9%T7WCdumC]-lf&N4ӷI&D__0{?"t>) !IYgH;:25 ,d!K[ǓhS;CqC(åؒ%D3/^*gˢ޷!^0!]k]q, l fh^"7sURbg0w3)lCb햻H8r_} K_Dz0wݩ7]6Zjm)TMx #nZRu(l16͙h3&vӱgg"3F-BɮUBbtmS2vx>c+>N0խƙIJh?">a3iDŽ1УCۺ FfbhnuS5䙝檵9_bJx{Pt\-L*$J.pr D8Y!4%=_LW0j[d:F]UO~j1F6nb}~`\ۍ=NTsQF^hg5B>WthW46F+E Ν^pS>ZAgKeT}a-m̌d/ ;cJ1muc6qXIrH,^$Q&'lX:e V7 x'GG(KМt.InyW.1ߜfjts;Ms=}70ǿaf[0&:=1w!=|Y,)U%';Y1f@ )4+&_U'ȈJen-B ' 7X 3[2!CQDV^$ 2Ltz@ޙtOH! j&Iјʫ#$)QkuKEUpkM*U`OD+W 9Ys&I+alGL /z2NU*AHJtU~JNMS6;mjP^h|S"a&'2v ;Aohl'Ezc_\ȅN HiN Q.rvsWi7[`fF?V&n3mqa:f65͊yfst*=\Sܛa@7w/YQEz"kW$T8pL50Q묽xRJ+zyo`"w;ԗ`h1FK s׭:5,e;&)<+g u?vr8mờc#ӜI_:EKx5g4I +^LC&!m 6#查-^(;ruG.`iGLk1f҃ɝK/7wMk`jM'mೄ),"!B.hGK֫&XF&`0QoZ?V:R :+s0u-4_z͊ZY ȅ]r;g%yHls΄xR` K֯$XZ9 YoM.ŝL5d{ȼXE a%66V*/#jMhH?Q6u ]t ,3.P;Nz=s89.2y:YO71˪+Xy Hx!EنC7JbXKA\:9Vco /9`:9d%g#!O3,k/ h 8E.֨„%Y9Vց0qX>+BOm1nonЦ?.]$f_atOfF_a S f5z9ŧ~BoZ X/vjXzrX]bXF[geD*_n(nιZ^ qGgq#+cu]|<}- 0pg|vm k5ܗE S~0tz acY7|qŰHNiyHY'$+u r:# Buȯ . 6b:??IoLT+zE(|]Ů/ԁ*I{ӿ$p`eQa qa7b2{IkXut&" #J^f^z:ĵ,MN6b|Q/S[AsXsu+ӥXuhd bsMX?*YLj؂\+k>Y"8O* kQlM^ku 1 z&T.B qOy2oE :' NRBZy G * /)Z6|z6݃cZTxVYUh_Gqƽ0"=J1yh b:?@vU Fz, t# ɮKk×Ch\xSb/ve;"IO.AqUd]461Ly?j8NNb:=r\ bhg%Q|ev4mhp 4xD6KQ,stk#m8SEh7[)vC#{]oЖt:DbB =Dx_sR|U\|lw&Dfkl _7DqJ?%u`<1qH\U:d#84.P l_\F*>+Juե菬uױz@S9WD~8Mwۑ1g]3cqN~XV?bC̾>ÿX}ve}zrUb_~HQ1ï1?R6_ϊ3Cb%}YRp%-[8w/YhYnK+z`Q:=:j5c O^3 .V6 BYWD[N&|DmHp^'N!И$zom8YvCisڍw,AW)3yaUX Cʁ4IvԳКfLa5jwࡊcrx>rjg(v,f[U=:) 8_'y*OK1.168nH + Kksmc>u 8CbɁrx^Nz=^'~~Vw{ʃg< shuI=Xvd'6*RɲZ_`iMfA$5yTIuz0EHzTGȸ5x*#txn{L+֫)"QPUCK?z ՠ/3jҢbvdK;xyR OERvd<xEóy1zlT z.U4ӗ5W;:,X[!<&>/[Eۨ hVp>đp{bG0\=\Aׇ\hvgo?пۅlH-z'ޑMty,ĺPP>5}FQ\"OᩩC;&0#1;FӹOFKAO*? .=L#ˁ 8ȓ; kM ػO↎( ʙB1 lJzŅJI; b'4}P# GJEn}pPhh+bs'Y,NNY'ig (ղF'CDŹ.8(7wG-@INoz'W57Ib)cbIR15~z%],^и$/w.A^wj͐D/u7.GKxlSJ6.,p̮#R;S.% _;s%FM'YAkiz-P#jG'#e>yz=)!S%*k=P9H:%^DɏڧjAGx KZﭺ=T.EDBN%=?Pq~AJƅ~]JCu ,:1諣BvЖ0uD 2qRZ-U_Q^#mD3֑p_[Oݛ#)'w}ԨCZ+ D%bق 89dXT8L[URS%H_{ ZO:mu6 -s*}=~#ԹKO o[ 3aϤopwI]:Bf;vU\PE"d-Xh=mze }C IkNkw:Spk{VdnBr` Uk<"UTQJ6|^P*qA,Y@Z\`^DTZPE Zux N܋ӎ^`FGPTP l&4ψuMBV2HR_wѳAKЅl:SIkkL+AIfM?`HtPD=p_mfz6jE%&{`3|] ͕c7$dĂfKٽ~'TIz=z=] uBSGIENDB`perfbook_html/node50.html0000644000175000017500000001121111672746161015552 0ustar paulmckpaulmck 5.5 The Right Tool for the Job: How to Choose?


5.5 The Right Tool for the Job: How to Choose?

As a rough rule of thumb, use the simplest tool that will get the job done. If you can, simply program sequentially. If that is insufficient, try using a shell script to mediate parallelism. If the resulting shell-script fork()/exec() overhead (about 480 microseconds for a minimal C program on an Intel Core Duo laptop) is too large, try using the C-language fork() and wait() primitives. If the overhead of these primitives (about 80 microseconds for a minimal child process) is still too large, then you might need to use the POSIX threading primitives, choosing the appropriate locking and/or atomic-operation primitives. If the overhead of the POSIX threading primitives (typically sub-microsecond) is too great, then the primitives introduced in Chapter [*] may be required. Always remember that inter-process communication and message-passing can be good alternatives to shared-memory multithreaded execution.

Of course, the actual overheads will depend not only on your hardware, but most critically on the manner in which you use the primitives. Therefore, it is necessary to make the right design choices as well as the correct choice of individual primitives, as is discussed at length in subsequent chapters.

Paul E. McKenney 2011-12-16
perfbook_html/img161.png0000644000175000017500000001145411672746146015320 0ustar paulmckpaulmckPNG  IHDR![ÿHPLTEb``URSMJK# hffommmkkXUVVSTB?@856KHHC@@A>>wuv.*+igh!tRNS@fIDATx]":rx&,l# 1Br.AR 5A.PF9nlD(NKeAX[ֶr]ˑԁTW.ϕ?i,!y">93&,׊{b9Uw},fTy\潱ϻcB LQ,EH/UU$/[U^O"MGu#ƸM1y01b >YsG!QgnN 淢7oUw3S-ZE{~h_!ئH %zzdS`ԊkPP;*TLe.dfO&f(\ÒhqܨɷqYYl?Z4mve)HpϜ`Jr$\,U"2}gYq;{!U%?X\̌-*2Qi($K+/[/υԿ_].iΚP"4Ӫj~d+Ku&7?|tm]b"c*.}ԷP9poq~ "_>5ӢJ[-eKZ PA6UjA4 :)Rd$/%EP*D㚌JmUd!m )nwl7@rdr۳ќg #zHǎfɤ^#A9~E-X^=.g,\CY&?zhX_ D`rR'Mn'a.xI^x+]ҕ_2ٓW(I֡r/.a^P*(آX +jGچh?ڄ=ZƯt~6{Ukm;l %|JZ#2(E(,<_PGh8J8{)EikO nUgt' G#O_/Z@d'+G^в&uŢZPM;NsiZrq3J6 ȾOiUEXmg '>s[tQfGJ&T\ T=ݬEK QV^vdGUlH,R*2:~hά]9z,sӧakIk|]'=&Å5pKTFA#kud5ӓ" kY8Wͥbn45·a~ u=:v!mIBWN*ZxHyh94H9lUW5bo7,Ǻf4q @8kNp(O a6A5*%F,lfuM?ЛSؾ"|cAVτ7e HBvcaT;2vi((pJjGgӤ є7#O,&e(W "\=H搎yeZ[EҢ*pwo;Ϛ.VuZ>)heť/½;Uȓ& "lw6V\"AuM*dmh<I]0Gn֍M{e'8x[龝NyOd][7O%ԃ=]ХZڅrP,J5ź v [\e]W5kn,x3 hd؂>^h ^Z`/-rotW\.]ǝt})V D}/G4~M^ 4eqRTk Y2&AR-,R3o jYq)\+k-i9޺I BNѺ$tteU_ 2PIZ:{I}!p`]˕'{h+ʠ@:>GyZvN>ҽ"*"xb Z@)OUhut炲0uЇ*8*ab^s5h >NE$%o3E(/$.^Djnณڇf QUm^D*KnFo&Hp \ˑpQfgpQ=^xePل׹UA8.nN~_M>衇@6ԝt,;e!9^NIE [KQѐJ9PN,?9̡΃K^}u]$vP$\qQc:>1 {C$ENJXPg Pc7ݦ 81EY:# KaӜEEQR5Ǫ6C͘n'lI肐"'/}?~yvˉ_uf/#Xm nOQ zdգ xr4,[!OZz}ҧ3YZ,c*V04*ŅOjg*8B&|&%[ZJYjј|#ȊY:C3HR\h$LUp"KM7) *{4 Rw%m=>0v廴7h͞ũ'u@g7ֲ95bdZ"5?#kJñȘR!! 7^E4sXD ^?<5"E}?e~_;Ϸ"zpJ؟%"3vR" ԰Y:)\ ෹ͅ-} eЬuX;x^NOf.k1>[*K?ȢbIENDB`perfbook_html/img265.png0000644000175000017500000003353211672746006015321 0ustar paulmckpaulmckPNG  IHDRLaWPLTE^\\TRRMJK# b``mkkcaaa__XUVJGH856iffKHHC@@wuv.*+rppQ:tRNS@f IDATx]z*\ko(*8$&q:IB(AL\n/4eS/&D)[kDe?\)'3 [+qS{G)7YTsuA+]B^#1a:a%n_Zǣ$Y5.yx~=:qAU^g3f*VYTH3o)Y LJ'iaJFEϑU;,;]Jt(ȃItƂI]0J9ۙXl9A/ $n%vC=eA`?'k}W% j}mVLwOq-w@Ʂn?{(8[i )L|>k7Ģq쏽Ū::t0@:~5="BL;f}eIsB&}U.E?uͦsuϛ # |%*IQԍy/LY"ꟵR x8jǵJdJ۹F`@OlwyQt»㦢79g8ynЍcӅAf60Bp [?\6"tBX&9aB|aOKE;j?uB^57h/ Y!xǙZ':ӁI\gI63݀?|Ż R< -ٴk_tn`vs^9: bj@ ^ț]B9~_u[Ñi\Q`(*#:ݝVOY,֭H{n,8j![21[CJ?5JzٵPl6-2x~R%+ƌI<7M5_TS%A26(*( Cfӻ{Yn?!sSW]+쌵_I T‚9sQ=ah;aZJ:Z7W'9KI~20nw#8%2LWa(+"}gQ?"ZN^?3{a\!VW]^F$ESߪNp~n95*SE׿B l@[/)pm6߬YOɮ/^ }KJ7kq]ѽ1ԤdӍVn:!Ij1-?D a_=}:Ej1F>pQtk90gܤUY05FN1 -`#h*n+u^q̽6f"$n$U?+4rW1u!("Xw̆\|91:H9>}0i/R48eȒ(&W$gF(;3cQL[\R JVfcuqm_ɪ)8!h3l,IC!c'~= _]PzEg=V̅xFO~ù}**QtA/UE;_+[NEu)׵kK|_n`{$RԯF%4>3eMWE\hP[r:,(D7O_?a1MQ$}g(ڒKIGo<=۷ƤMW:/K5yJQLoj4LIX)=' gd-IP_G8կhiHC4($d 6ю$"J)Me*K%5B@m38v˻ŗPL']zvMD/9?9,K5 A:1/< |bdok-";9 'дԐL۽]CeS3$H]iN@s&(i]'lk5egߩ7ޝ?jay&Q'ox'eNctF7J j;!a5 [PJ.Av H0yxs^1S^[C׏5spYv~omv{LT.AKʎ3g$Q. $S7}_6Q+4I_ 6x@L)tbf[c_ >^I^C\ ̔,k"{R)b!!M3!go\HuB_ J木nk@2'myt%UЙoWM.!e# \ &Na< ΒZțʇ5o iSxEyg_ =F0JojvPBsvEc5tt Zp a鷠T_lO7J)D2+' G/2B3Qi.E[ aNJ`Қd飧v4$aB@ =1'=f 2B;Q|u{mt&Z: !tLYCKiKUk[BSRl˕aX*5-rMù8'  *%T/†PpYW r%vYvmqn*}&ݙM,\ZvDNyK㉔,s\Ɋ"QͿj}3^ 饳SSQT 0:ioq-P$%T";1{h2mް] -9L hD"Ad=J!}ng O]JXc)HJ$(;̢?$fRY9vYP qu=nafl2%X ^%QUK7t}v{HKW@4qR WLd!DMW`|7 [u)%89xijvmtDŽR`nFӝ&qN4@aE ѹ;qm7Z&[T87I2,h9gLH`YLBR"a33"vשC @ 0/fbL4 ir ͪ m o3#8Y\k J؆ }`#0 \$ LX&1' v{h3/:RS׶@&IwU3gZT-kŞa 䨥6j<>=:l]X.W͟G3CT AmjXAea">/|穄NkJ=(P  m( oqwl 0RtIvM zI$JWnQU~>mH4w(̈;0S|ص1wµ) ᳟v8 hcB/k5BFԀ0(4tD(&D97~ 4C 7hʘAqҶdi[-;yG-xgX!QFE8H7v`H& X@0-jlAb5p2Ж#%F6 +lqZ^KTE<"mI$vLaQys_ wP1,1ؗsALɖ)L1OrW'DY'j6:D9Fe9Jw\ /`SpA?$=7mɑ'&8$=G uFD~u8/tl`Dj# ix&$$)9hQؿ'K01dXk*@VPɻ7ec#o0IAN |~lӯXW a*_d2j!h@Vdm›%n$-e"H|\Љߤ/jYro-+FGU1ss5oO.g6ȝiTɛC$w-w!heDTsx=^A*)™&GLrr-IP<û@\Rݿ2:3_?>~/lxsIe(b@QhZDXT6dD1 ;x,x@3`8i\A@u€ԋx-oVT6zfpks$~kqd7//zWĹK`&SM HU~ B8`gX iWj?DD~UT,@$ 3s<}t;/zR{4@5_0^14GpMc>|"Q#t %E{DW P,L ;vF;P32k" S))tPK9}0hRپ_!:)lXɗ$+?p" œ@ bKEVNJ13'Q!:)Qё΋5͚D wZ/PtЈ mƚ ) 2L0˭IJ7#^nTzTLss۸0VN t5A`QsP_ yJ7/7屬Ty5 >k3a+fx7]-GF ÒڰVSd߳qzX&XRA2rtx%[hfsu%}68'HDzËMxMZ/H gD¸9Ts6]MO[^"7f^H,L/QH1\KW4ژ7IDAT- ̚gqFi)t6@@elU_O=T%τxsB(O5JQ5!ʘq X35 Ǵjif8#r3НF]]O( {Klf9HA nS=+!htgt;Y5AM'tϰ1iU Dc4a{|m #-,ftd/F:'!Rpi7ޏB6m*@6cl#;;j@.8&Lmd'@m$jbF wl/:hӭc~24`he9X78wR聆TWyP%L̞w\4zj7n w\"`6o%׶Ib20$C G6S'921JVSx DF=7PAV2p@,2FrPgH;%!Y5F@)&%R6Ꟶ@^]YK2C+yac8hgrdxǙf!by`HF\'!{؟0g f0L WgS nOȍ<̙8<N4Mƌ(kɑl! ɵ. vmتM(#6cV j!^п1Cp td 3; x'mCh;6Ѕ tsDנS2`sjbc۩q3@CǛ3x3o<l̘?ƍ7ޏ~X8Byc?V*NFͦ~auPRu0,- ckho ;/*ӺU&RHxZb9=|[s|jmoFԘo4Yb٘a95 2\|fڥ(OrN|6QVތ1dp'/əxX]&>)qW%OȆKa\j]:aw?v= [j<Q10cJYDQP8) x ƿ_!#0%r.GnHlٝAޏ'+> (&\BMfs<&)(1X'k.Gʪ~Ln> jL]qcʴmԘ^ xИߘ[|gâ]bȹ9Z'}e> hѫ\ 6@i1Y<:r1h]- KlFlh}sd3#P#QA"M; CG?3Ko QT`>\Ũ+pnV#\[>Mݢ#{fmx%,vJDை"LFb(ʹp<0:/4A𢁑m/MpXxHdaD)\$߉qF=1MUS"n81wľ 1Cqń1m0 <3" c1QQSh-g\u@Ps1x0Պ U9)k&DFE"ȮTS!"g wtYgE~6xb t[q8#GƚPr^ZlYI֧r;Ʊaz 5W0э@~b'IgqMMB>Ep͘"{w;)X\9ij;aar:&I Sb0d2&_Nh ~";18>dT>u YM"T.*qw$ @Fo0zL( "PkG{&=j6,""o!t@cN-FB{$d(-82޻01-"y:2ISh0_d`=bJ * ޻01d,"cN4oy(:DR޷IAX5t_]fhػZC)o$H(a0n ,qD7t߉PꖨP&WړZؔ?̾q0=ԞƼ{i(:ܸqIVScǼ ]vPhg8; `)5>7E7D0#@2rҌ8rid1i '@y!,dAgq81*J'kEL <FGiFYVq(CGJ /ōķCkH3z"3~. by(R,jnHNiБL# !"ZS zI uV臊!qfLl6֥)B ;(- +5 wBq5Ұ)sF::gFGc&":4b'T*KiBʸFM":)-"d͢UƤPZtX[$"r?DHyZбNQZ|d5R<#svdoKݑj8^o첉#ß3r$8(2ſ!oTG?3 9hrbʘFJN&4fdF6qPeIq0M1q" GA5;`/ e__:,ԕ. \Iu7nܸR~* Fy m{%]}N`m˂\y~T-M W8@ps ~snV+ Q/N@\7čhßٳI:O6#K]!2sG_9H1YKfq"3wD,QC'z nnzd 'Ly;)N:B{f^HEJ}X@قf ϫMd1Ii6oN)7 g %fpγɟC >F|D]Y%,U0ii)#A* Dpy+t=fUkfy8԰T5 KzsK /=Daclnz9" ʹ@0`֍T /Ĝ#Ą7֊ax<'lcqͫI{D71& @]2H&&F}91MLxd%Q7E=3aѨ̄o3zܸ4?2JJZ=xfi Bk*\+"%oUDgdlw7> {4snn0=޶lٜ9qpa߸SAn N6)Bh<$玅8)e6Gcit3= L*aK+:|j̈a"Χ`J(z`'3RTܳ{(-eͻW1`i̘aBDLi[-IFycԚ#rol#@Th1|$13dLZdȩ˵Q_^G2SAS|W8vgf&c戛 ; ߝvgٰ >77qM8 ͵MSFLpnj Ͷٰ7nw~oܸv| EE{iP|v]ʝ/,ܹR|~mM*1qpgr w.?k_ wH;8^_;?rБϼchgƍ`CGrํ,߸lX~:leH8!Jd؂ƚlJ̏bm8VLhpɄ]朎 ckP'66/,&4,(bB}GM,sRPɇIENDB`perfbook_html/node255.html0000644000175000017500000001205711672746162015653 0ustar paulmckpaulmck 17.1.6 Time Delays


17.1.6 Time Delays

An important special case of interaction with extra-transactional accesses involves explicit time delays within a transaction. Of course, the idea of a time delay within a transaction flies in the face of TM's atomicity property, but one can argue that this sort of thing is what weak atomicity is all about. Furthermore, correct interaction with memory-mapped I/O sometimes requires carefully controlled timing, and applications often use time delays for varied purposes.

So, what can TM do about time delays within transactions?

  1. Ignore time delays within transactions. This has an appearance of elegance, but like too many other ``elegant'' solutions, fails to survive first contact with legacy code. Such code, which might well have important time delays in critical sections, would fail upon being transactionalized.
  2. Abort transactions upon encountering a time-delay operation. This is attractive, but it is unfortunately not always possible to automatically detect a time-delay operation. Is that tight loop computing something important, or is it instead waiting for time to elapse?
  3. Enlist the compiler to prohibit time delays within transactions.
  4. Let the time delays execute normally. Unfortunately, some TM implementations publish modifications only at commit time, which would in many cases defeat the purpose of the time delay.

It is not clear that there is a single correct answer. TM implementations featuring weak atomicity that publish changes immediately within the transaction (rolling these changes back upon abort) might be reasonably well served by the last alternative. Even in this case, the code at the other end of the transaction may require a substantial redesign to tolerate aborted transactions.

Paul E. McKenney 2011-12-16
perfbook_html/img96.png0000644000175000017500000000063311672746130015235 0ustar paulmckpaulmckPNG  IHDR< 670PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(ՑN0OFtRG@ea HA l(G#00"XY9Ӓ:"UGNtwԥ3muhHR ݶV50sa dO,{Ph,WK/J}Q55$6 .B}|^tߕ/SOHvyvᛯfoγ?Ǡ<Ug^pl}%RAvǰA}M]<&:dيhGgކG?~EYIENDB`perfbook_html/img151.png0000644000175000017500000000513411672745763015321 0ustar paulmckpaulmckPNG  IHDR=<8Ob6PLTE^\\URSMJK# b``mkkXUV856C@@wuv.*+Ӕ4tRNS@f IDAThv먎F}Zۉ&n  h_pك5cz{3 xD &cS L`b/f$^,~ ʮ}/xՆ`odA7g l=}l&Oo ؅y ,@mG3qD.|`"#z( VT=ncʘ3#?5}V|4 )OTA&-3K~'lf_P>}XWU~X€pqxQ.IİrFa~VYI#rD`'d|M3m;f"uI",,]f LY|35։N.r?\Y><(U_ <@9%. qӫ<4&L|þQ#Ikjwyһm#YBf<,*VQ%Ah~b5_֠6gxBm"W$FS@=. JOH-OQ|Km1Z3f5 YCԼ 2&yRg~(| uЈ%,9,'x2_o,W.ܤI-$'W%Vc+ hV6TEiÚM^lʡ0)+.ږvnN]"NVMTpcfk%IYa6l̖ZX~zK1t46%V1^7- !TpK]mԆA\Ӯ&̐6?aR$KO](b%wg> o3 v.;9 W r5BB$1v*s;D̊Ýȹ*811N}HY.%d!{+ < Šrqp~XW/?NC-r䭺ںoL\\@dq:j!X#Jۋ0J׸.:jL{tJ3["m+ͩ;56p,Y6>N66QEۊqc^ [ %&\ >R}!W/7&ї+=0I-Qg@kzBoGg7j¦W퟊$KQG\UB:%˗neɗkNpWK:21^>/9cbGmߦ{_>k~G)_?XvNO-d`UjҮ2myL_xEqezh*fߛ/Np7N^ c Vl5,m}&Ό?;oFJXvuVׇ=3pLRstƞ:iq Mc~s4B<#3i;p ^Y,M8Q#Mg{k5]o:c295g9y=sxRhn0!{9'mSlI? W 8ҙ8Hѐ\s]pŔ+hlwiG^QywɦL6 SÉ-)iOpJۑtzE탠{Oeum*hwQ+a;T S.u-uL5Cix˯BV\=>}+ޟU~t k|kE"}ff~iF=^;{MN;8~Ol̡ ]ם[ۚv_aSW'y=v'd' [8}KPYisՙ3k ;"{9D0K7O}`=23]0{;U.~uCiM_SĎ5(;=gh9vYRA|ShO9q\}h ַ B4OOfIuf:7ʍ^|.#,M'n_d=jy^߱ vd-x=' |IL4sq9ɵűu")~cՁEp_͟_a5;{+whuޙ6l-:Ali2aڰLXkPs;' '>wgo*i%s. >t7}W7^)Ds ޻M!)J0?O,(ơjޥv6"uk5usKIB*̩~?,w^+{Jvfvv7q3P 7G@j!َM2}f8fA4ٕavd-yLпE7YŚxvyEwejo0G ᪹pٍޕ%tBeCwan=*+~r?mq|f?+֟eY!5k~_4R R\5pOsC58D!%Y0}D /'}lAW3}vO{ti1A#l. AqX"R^fLa˗i x国O"t[zٕB+PqEGZaJ2yr"wc7.9s4;3<8CնD4}Kl Vg=m;\.];ȹw{Ãp^c5O˾G"Ωe3b.(weI:!S Lpj|-&ϡri0^Áѵݗy\ \B#K]cզ)l)ls^/cHxdC"r_|*ƂYa LEY,!~K+Ke`Pך/ 城MlrDRNTK4YeC8q0kGʨ&pɹ9%'&saΫEZ"\d%K^Y׼:aWؼZ-̉XIޞX0@KT HmQκə9OB&=<69̼6735oBl~7Gk9WHl'⠒× dzxp bZ8mzxO|v5qRZ8f~TfNdKHح5 ̦jm2"̘_bU}%Tdx-n:u.z fG2Txȓ; ov奸JXOADMI:(TI䄛NK`> ٯ~9w.tȨzXDqF(@fy1~ƙd8rجPX8iªXYHp\!{)7_utC \TQ`*.ouzV-Z ^uFa砣fiS/v= `ɭFM1ȫ6d?ddOtu)jYoH)Q2³jidèn#ۉA44RuZNsҔ)&֠B enC Z c2oX_:o9 FHĂ?kb$B?oB~kmu7OK%L4Ւ{C8,bD"ꉁuΐI\uFmߨbN8{JN$}X&@,d!A[ˌՠ#ZVGٔv(.ʈ7ziղX GU/6 Y@*~ D %#g5N.FH6݃KǠ:3-e\aՐ}8}. I5-*'LɆ:41PͭLOx^m8 GM BPO ^:mܐ"GfaI͛RV\ye]KTS˜]Mz}q'a[vM#Mb/16jqTmQ|Fb h_ y,,_L5Ke<m F* 6A79TJ` ,| FvIp0?*d#Ȧ7G?1+Cj6oGxg0a ] mR UXE>dXM%P^38nD.FqPQ'ʜu =yʱ B%S ?-~_swuw\Q $}9lB$(avX-kHQXfHLz# kO@wyEЉۍAuqkpY>Ԣ oߩ.v3'i|˜KPZʸ;s-YZQC=˰ȳDu~Di`DLt aSI~vlq,ǠLr m thxtr;#%^-pk±:n#0{L L'lW+{|/Ő{&u5d,_||,clժz>ָ<()˗N,_۪IhlaFj4:Sh61V"}Z˫ɡEg1ꥠ,enhضlq6NhK,?`F_A?қd4 Fyvؼkqd/n@b2K7̤Ay8I.BzM-#HV64@c[C龷ieR.-=A_TVD[PO#-&&g{vV`Bzs=t:Z#L4ybiX6'*'e"BT ì㞖`RۊwB`rfs/iⳀ<{c"{̷㫰Q32,96BS(M1Wz sdziaz~ 5֊n]w kAEI=WZ,>jp;W%6Ev-Qޢm 9A/Sm>eWoWH;tK '@dh.q|4nD䍌wHqv  yxe $b%-o Eod@ B][}{5F7,5(|5 pnHgly`;2dz\0}SG~֨%@*bn 5 phtbpbTkƥ[[kԘr[kt[Oi9ӣZUՈ*Ja# JI혿~.2ܥHX6m½Z"M)^k+z]쮔_\()A(^-|#W ~-٫ UN &˹*N,O.% vj8meA R1*~~wsaH 7\ }ق` ΰfvcef 4Kd[#uLٺ5s;n ᠁W;=c:w } /͜U>&g48}.O4q}!@ظqO a _gmӲl>u}w-eՑvmP+d:eTsv칅h/[v=Qְ>g$$<z>n2axk/ ȷyju+ Oš˲y'tZœw<& 5D^t'КAṑ zqxi" hT%p0 2>bLayN*=r5iRB›\'׸} WTdEFӇs-jlkQ/+WdPQ&kPy 7jj-R x` Zd(/%:EqBcސ^mg  ZtlB3n=9p{VWׁyjEpQ󄧔6NZ*ZceC_DP8YHW4>GŁW[/1dΒ0h`Vz5`>ogҳϗ+\j*'"a}f `ْўD`~-dL`BD&PgDZdOx׼Ih!l\$BPeAٲ& F@-Hia)T>)G-r1޳}9Y-HИ,PH "@6b_l88N'8 ~hغҳO秘pXe \rO(6GV@} G6O8(kx F% ? D?3:_{BZ4`OW|5vY,I$>CF">/NHC[4!}0<.}`խi!H ;MEFuk {5>խ [tw&nMejv zrvցy$t{tUﮜkY*X4촮˪jE#j* z <-,ʹʇi'VLx.Sǿ֛_ڼ >4tBUB"l -NEEϪBguOx) ik<*fw΅}P5FjT&O'$hjg5 GKjgZfź5CB6ŠvV6M} ٔYք]nمCδź5ኩJl ђDǗ&_ 2QçokgaHy35+\^`վ&¶X "_LvJ7z35E֕Ib`k#&UJ {Vv/s^R _'eڳlM=+Q۔O|7P۔P([2E3{&ބsp lvQoyi 6l%MO+oH,smsAbd+gaѯrCtպνgSj -z6{i8HD)P҄@ۍ32 7֖>˶vͼQP;LRßR;rsHI =Ze3{34KUR *k[+^Uȫ,u$.v< YN%%>7osCsAlN}\acn5=Wk M*-©FԢ {Z樑&FFuWxzFL%lQo m73'vd?C.[8@M?0cŤL*̅E\+l!\-_0mُTȅXTQXTw\DWR.D³Nm5ۃ6N5 ЄXv;gmF>,(8 1Q;[lv;NIDAT<滏gbg.h\]3}]6@9mT6;Q ?5zW:vY 4!\N_5}^D판a-\ilu[$VYf^s!İ5%3:\_tk.xjg m>t!9W?aOdWrf.s")9$GHܘƫ]V;#ƕ1"ۍ"J aCv'e=9]V;:e wlr;#lvj#}7o);עZ19DAM #x3{gTp3C)]T;{ 9L6v! z;N-Dmt Nز\-(bvmͣo@yIGEFs`)먹=MG"cх/t bႃ z;.Me9( ,C먹fzE| a743>gtZ}%;Rۋ:j R뀁l?*՜vϮmT7xj%6{<>@Xjѧ{ME̘K5:cgP;[. 1v_:D[vc P¹ش6nf6Ddk,mB/:'͛@{v-klբj΀5voEVծ5gvSFУ0'>"W eZs_j?@ /2>qנznx>N W91{vͮe-sk8ad->R "ω.9>mhMޭ@b |Ꮤ$2.צ$Tv,U |ᏮzVC}"WbwhČRbIHUzW;U;s[czc#Tdlzx Y &' N B Ne D/TWXB̥N,p)ʥ OJ>XC6V;U~ghv 1GzMδfg3XxDH 'Zv}j#cvxXhV #8yܩU;R+)?1l8>QANO5y ) sNJàKCc]$&ө eݸk}D4qRK\X)Vh)gJ:˰OZøYV%&\PqEV(7psy0z8(UϣE֌siZ4=w׬#s1U316{!24"spfsVWm/c5n]ȐT\5"tQՂ2mf$b–5WU(?C&}Y6]Hlnw!!c5`]aWE6+Z*ćs ]Da& hDZ"'$$lRU%j~N߅8,,\ (JHHHH~\,*_1G2fB6‡_Y2$2^4.gmo~vБ6[zF͇ЛouAaO4~ݤ|6kx";#~^;$qEh33^]!-Uuٔ#sK TbuD!Qvub-ɗgmWrYGPLHHH؊La䑦D]ge6Y@L A qU~Meb佭z>iƑR?Dg6A˘ AW  i,RH36.$.??A|^-]to!wј A A%%"zמ`4wNq&g.,L?̥ 1AA?hW 1'$|!2 2>՚Bug0 \-jYq62Bw/o %¤<Ø;"e\'X(P֤  ef!RHk#|4T&IKp ϫMF`M,M-3>:']wQ| 8Z&㷂D>c 0C-+U ҉]ŧ]cÓtJVk c]dИHDp&K#>'̍TPESxE955k g|71: 퉄\d5/7N&Bf'НLkfRNv5H #;C}3&妌BC3FWnR}rE oQ&2*㤔% _1x**.BGR!uCt5!!!!!QpYW̍* 8BRmI%A Ok*z¢ ڞ,7RFQ% .0[YB^ҝOp)l@uߥO.?ĘKp= jp_UĮu,_1)gb_95ov )K!;^ăUM{놲 WRj]㍀5ƬcNR? 9X#@]y5f8|rA8 CT,^ bP]뢡?RJvU X%R)ل w0 lw2ShVgJ^G{:@W m_MՍ'4 iqU6쮡Dc]69.Ɗ̖c; Fq ưU[p f.FEӵ en j4vhڃV>my'w =ͪS_4R`6!7Д^w`nZe<]CbjSi _$4Bf ,;AݮPؔ AW>z3a~av{w r^a]#+_ @ 2&P`h಼AT=Gj]D67 ^1:FGbqWt$BK]tcouQ*5 !۞x?enf",BI>u(0+ۄ 60aZtmetBBBO"6n^BzbVZAZ dLـ,@uqqX3*[}!c\ q v®ca@v2ÖPLdî_:6!!!!!6P`V;c0ei&F 'Wm#pNlf][WyEU%osΪ&*k\+(0Z\#k̔ݨƏ =*rȁI3㣊 j&"U f=-Ul½\"T+!6͸]=R]Z˼Zmg^UX-\_\if+MA)[Cia2|U +HVz-;h6QHW*/~|`.\ESW5yP-X+n%K G DxMӺw{eJoI:$$$2|`v׹Һĵ}.]Ŀ.}eGĿΓek(I]e:OZ-uч%u-(0{@egVczE? K{ȿQiߝ0XBBBBIGGnA9 ˜]զ-+́=bmʅkW}`^*v U4cKxa^[mߜ籶nQ9:Ik=ZQb$F:-Z\M8 ~/lݸΚ1aKGE_~pYh&]vr`p4Ջ.A;fvۍtE a7l nF'1ҨQ3]௮<]e[ 6Pb+(EÝd3=&$$IP[Sq )E0ZM`J,ʹ nZ4y=? WT|񨋦J@W n4UIa3CBBE DdoÓ̤t?;v:* x]jܱ% G]!'.⣹cgz#"`sBņ5|%JHRk P`KDbcQk2fC%0\4H욑ZH9F}++78%Dʶg1+& ~~veft~J.",Ef=svG;@{ڲGk"~UA0~Wh. o(ƃxN^b={<6"8}?xh<)F^a$x^HMA-LbbDK<{+k"^%&$5Ha$x$u[GOwK;x6xƃxh<ă߭`nbg%z, ĺ:>05Fmwu$\@Vw?[h nʆKwհ :XSZ2m#1ԯ*RY >~>0{PR-/!(kZ`/H kJt$.P@VaѼPLDEh3ֶ|BXGb_UB:Q9d:5e.awGMB٦{1V=L/ ofX6Dlgt+eEZowʠvoe(T*fQ;?qA]D ^b׽.BkBXwbAtv^Ga H"إW 1@+FHAg6U[Ty|;-3.{*{/+Tz~EW밁 gfwB\`y1!֗BB P`3b}i"n B]QĘKs}!6!!!!7`vrC!+$G1>:(0;4X#v l`vPrX#&>lBBBgДWî1f뀿fßîAa!W a-bJGIENDB`perfbook_html/node473.html0000644000175000017500000001444211672746163015656 0ustar paulmckpaulmck F.13 Chapter 

F.13 Chapter [*]

Quick Quiz [*].1: 
Give an example of a parallel program that could be written without synchronization primitives.
 
Answer:
There are many examples. One of the simplest would be a parametric study using a single independent variable. If the program run_study took a single argument, then we could use the following bash script to run two instances in parallel, as might be appropriate on a two-CPU system:

run_study 1 > 1.out& run_study 2 > 2.out; wait

One could of course argue that the bash ampersand operator and the ``wait'' primitive are in fact synchronization primitives. If so, then consider that this script could be run manually in two separate command windows, so that the only synchronization would be supplied by the user himself or herself.

Quick Quiz [*].2: 
What problems could occur if the variable counter were incremented without the protection of mutex?
 
Answer:
On CPUs with load-store architectures, incrementing counter might compile into something like the following:



LOAD counter,r0
INC r0
STORE r0,counter


On such machines, two threads might simultaneously load the value of counter, each increment it, and each store the result. The new value of counter will then only be one greater than before, despite two threads each incrementing it.

Quick Quiz [*].3: 
How could you work around the lack of a per-thread-variable API on systems that do not provide it?
 
Answer:
One approach would be to create an array indexed by smp_thread_id(), and another would be to use a hash table to map from smp_thread_id() to an array index -- which is in fact what this set of APIs does in pthread environments.

Another approach would be for the parent to allocate a structure containing fields for each desired per-thread variable, then pass this to the child during thread creation. However, this approach can impose large software-engineering costs in large systems. To see this, imagine if all global variables in a large system had to be declared in a single file, regardless of whether or not they were C static variables!

Paul E. McKenney 2011-12-16
perfbook_html/img112.png0000644000175000017500000001354611672745774015326 0ustar paulmckpaulmckPNG  IHDRTٲHA6PLTEb``^\\MJK# hffmkkXUV856C@@wuv.*+A'AwtRNS@fIDATx]ŇQUIݫ\「5S2f9g]PuKՂ1mk9(ְLk=r8.n-Wo̳M#*M2X) WФB}WPuU˖aw'fŢ-\h[Mp}̘7 AM֨yse i]eWb:EO,Bwi-'9s9d[RDݣS' w4 _=l~h\HvBo+Xܩsr#!5 0i$4F*UN9!O罪hfE@eŔ_iyFNa8Y4j3MO\  * pK>0z4Ϳfp tW4ێ'f".18gڒ5I~3oz`0\N<)@^tyK(qrҿMfGKdT{!w4#ʞp6 R1]5SKC f?e~exh?RҔbzT gFtnJ.Ѡ02#RWVfPTIEפs#ho[ s<زa0ŵаZCt'qwHz硁jrup6<#Q.Vh\U])V=ı.:Ucd1z9dza8lCR4VEޙvXaj&)ǃS ,g/qo)<1]?i'F7ZboN],4%/ОdŢKhq >{w'e>G- g[=ᩌ*X$M/A1\Žǹ%-Qz._ӂzeSK̅$8{Y".: ԉ#A\3K5U#@Y#!s-Pݭ{D{Bur%Rh RC7 ~$2L>SIzr'A #CEx(Z%:U8 7oJkkw5v_Qf)1-cd\Cl`rjՒøpZz 'Q<9ijGS#Sڨ|Qewl.\ c8L+n\Pq߯5Rp7be 2 jΘ3$ yz~ˬWO+ZC92c1,)*8kIv:^tyzԺ>` qZ-m#Ⱦsvrcx@?]ٰȴ!B0͙ 3h]ϩ)! ,ho%Ǽj޾0wzFp'UL@qH=~k3Ǽ}0 Ώ;EN6hh$@3ay=z~g^FBpDRNP!)km/YFa\ʁɼ+`a#XN>X"|ՌiUe0 c%d@V7yU'm/Y5h{nQYgT 8K$'jk;c5D.0%Kc~omY1@/0 M-Y3OBZ>;V /ೝ/B) d8c㿔S0hgfK;@n +¬NB,eVF9Q^RÊ3NJ0˳P@NLiN(`_%to 9Q3T]F=:rluc -^Y#,Yj\ H7I]4͗z\ؿm օeF8MFগci(mH{фag5tJB-xg}xd#)aI?˪k;޲[tgL%e5֭Q*9p)u)k$jdF/2w+v`(Pb4d$VvI CJSBH[?>EŢEBYeu_,%och\-eZ&DŽE'`(n d : ή tG6ؙa/E_SMq BNabMNAf!mF!Xf1!`^k`ވ3(@6WKvxhg 3H͆ Q}D[ 2 CQVuڿ2Fy~U?N7v cua$1c:gX> #m8ռY4}˩!-9d qqlYNcLz%a"2 *лz6͜{/ gLj-/n+g<+ހ C!8vl B6k9S#Ьi~TyEǍR/, 1h,]!!^|Y:T_mf^>޹2`q646ɎV- 術"&8Nv̧ߙin"}+m(JdP`06,7=!V,Fĵgj:a0ybmA=gXZa8/gNjn]>v@t)91K4e@Gs($1 )Vv[9?#-TܭMxuES3 ~2HG@x^"BPh~DƯ#BAYC)CPO  7t" {vPRX$pSD|\7"DSpEmB *"e8 x!H?O GPڥx]χCV\W^]{; m kԊK:=DRn(! /v̻Q$|bqJ烨]׵~1P`H~;z+F%:hEq]t3Bq[H9Ag3o!\na`ddK86} ,\(0dqtKvYÃ#A7@2_Gu`CW b )xҥZ!D!T~1G~#[]tgRWH%}JJ~؛rX,#aH+Mb'GȃpOD0#d#/H !H[0֋z#lQ^-Er`[_a#drO8,*j▿ƿ۾򯄕2O$'¸%X*r1M1##&"A2H@oM QA. freB D 5 lSDʈp@P6X+Ɍ| D bvD\?puqMD8`=i +{IGZo'r\QI+ogr\Q-] 9B>>]QnoQ|]%wh7]Qvo!_g>9BpCt׽5$R#qnGVR$eEB\zM/rJ^|H{;ZNj* zMNKa@1.kl㞊oB?B|b+H!ngػt)q*2]|;39B5{rl MTmsA)U'rLwL5>#9kQ׺dhÏ"!_duR폭 -IENDB`perfbook_html/img276.png0000644000175000017500000000565711672746111015327 0ustar paulmckpaulmckPNG  IHDR_TPLTEqqqgggMMM///''' |||ttthhh^^^ZZZTTTLLLHHH@@@444]JtRNS@f IDATx]*nnᲬ3[&2u&(yKtZ,Cdc3xhZH&[J.|PZyW^<arglw<; B9Ja5 &sy$Ym|Lcx,fXeDtB=B(?U0ݠTz)Z+OcYza&HV8_PB,ГpE1}Jb9% gkx[dn[{*DRR?հX3t@kUfHi28`x(iC;q/m3s¿*`mL[auw0ΒՀp=}LnA `JSv]4E0KbVKఘho}tmct _:Y1q9Y1˾=(ݔL+=z_ip>|}_vQJ{ v^ .o[u3Yya7Ne~AA+觡h;8r]B+* [lcmUVھC:d?vv] ZCIz&ubnG(V-~Tx{,=@N &X3+:Wk]'i硦i-TD-ZWUJ8BlZ½jiQNwMKÑ;pM50H( M^s9ڕWeB䷫mnJNA1z ۴O2-.h*&δLٴ$U1>VzjZC ]\UK{,}ш$1EH< C)^-IڥL%?iYR*Z)?N9̈,CK*L6䁣Li`ZEdU5FeiIRCZ~ud3DI"4I̘M5I|>$YIXcI&I6$.$k{$ɿ40-2]UU혖ikIR[K J}GkX]E.ʙ^;S6yY/ z2rOAZK WƖow 6]2v:lV?tqVuJ`Z8ڪvL˴5r$-ZmKӂ߈?;ӋkPd ZZnno;fX4?"V.U~ͯibk#nw \8j؝'>kbL1N'[eeuv)WPS4\tC9@.*>Z,^&l X5Ēlcеmgi!{)6腁N4^w12c7!`nR`bK_^cj:}Ikb-zl#EHY,p& bw~D#N^*o4u4Y^.]5M7z6Q--'MoMރaݩsf줓z-v!Dw&g4$չ0 /w͐ |rn)e,6!e,sOM,Xl)R`PX)HA[UŲXy~iPb U'ږ}x.Ϥ"ɚ۴BC燳[4L/OSd5IȗTXb;h|3д A {4w͑.׿Iqr?54(u%&IbM7;`Jn>w14w!e,F",@JŖ-[ , PX)Rb|Xb#o =H nw$>ؽ G9$va; 7IY,e)eDZ"ב9~r`bKŖB=bJ,DebxB]-bYl-BA]y4=+/zG]jnl)v ktWĮfbi\1pa+ͺE#bWV M?'f++ͺE#bVp,\ؕc͒9CEHY,e)-&"5u [,Xl)RG,CMZ[aL!-Ly5G:L;.qܠe^7{&3["DX-jIlGӵaWs.z`Fe :jʒЅ6;_O ▸7G<Ϙ3N]g(6&?%;$NIENDB`perfbook_html/img209.png0000644000175000017500000000021611672746157015317 0ustar paulmckpaulmckPNG  IHDR]PLTEMJKmkkXUVC@@.*+1_itRNS@f$IDATc` 4``H <f j 3H`IENDB`perfbook_html/node61.html0000644000175000017500000003767011672746161015575 0ustar paulmckpaulmck 6.3.2 Simple Limit Counter Implementation


6.3.2 Simple Limit Counter Implementation

Figure: Simple Limit Counter Variables
\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long __thread counter ...
...ADS] = { NULL };
7 DEFINE_SPINLOCK(gblcnt_mutex);\end{verbatim}
}\end{figure}

Figure: Simple Limit Counter Variable Relationships
\resizebox{3in}{!}{\includegraphics{count/count_lim}}

Figure [*] shows both the per-thread and global variables used by this implementation. The per-thread counter and countermax variables are the corresponding thread's local counter and the upper bound on that counter, respectively. The globalcountmax variable on line 3 contains the upper bound for the aggregate counter, and the globalcount variable on line 4 is the global counter. The sum of globalcount and each thread's counter gives the aggregate value of the overall counter. The globalreserve variable on line 5 is the sum of all of the per-thread countermax variables. The relationship among these variables is shown by Figure [*]:

  1. The sum of globalcount and globalreserve must be less than or equal to globalcountmax.
  2. The sum of all threads' countermax values must be less than or equal to globalreserve.
  3. Each thread's counter must be less than or equal to that thread's countermax.

Each element of the counterp[] array references the corresponding thread's counter variable, and, finally, the gblcnt_mutex spinlock guards all of the global variables, in other words, no thread is permitted to access or modify any of the global variables unless it has acquired gblcnt_mutex.

Figure: Simple Limit Counter Add, Subtract, and Read
\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
... spin_unlock(&gblcnt_mutex);
49 return sum;
50 }\end{verbatim}
}\end{figure}

Figure [*] shows the add_count(), sub_count(), and read_count() functions (count_lim.c).

Lines 1-18 show add_count(), which adds the specified value delta to the counter. Line 3 checks to see if there is room for delta on this thread's counter, and, if so, line 4 adds it and line 6 returns success. This is the add_counter() fastpath, and it does no atomic operations, references only per-thread variables, and should not incur any cache misses.

Quick Quiz 6.25: What is with the strange form of the condition on line 3 of Figure [*]? Why not the following more intuitive form of the fastpath?



  3 if (counter + delta <= countermax){
  4   counter += delta;
  5   return 1;
  6 }


End Quick Quiz

If the test on line 3 fails, we must access global variables, and thus must acquire gblcnt_mutex on line 7, which we release on line 11 in the failure case or on line 16 in the success case. Line 8 invokes globalize_count(), shown in Figure [*], which clears the thread-local variables, adjusting the global variables as needed, thus simplifying global processing. (But don't take my word for it, try coding it yourself!) Lines 9 and 10 check to see if addition of delta can be accommodated, with the meaning of the expression preceding the less-than sign shown in Figure [*] as the difference in height of the two red bars. If the addition of delta cannot be accommodated, then line 11 (as noted earlier) releases gblcnt_mutex and line 12 returns indicating failure.

Otherwise, line 14 subtracts delta from globalcount, line 15 invokes balance_count() (shown in Figure [*]) in order to update both the global and the per-thread variables (hopefully setting this thread's countermax to re-enable the fastpath), if appropriate, to re-enable fastpath processing, line 16 release gblcnt_mutex (again, as noted earlier), and, finally, line 17 returns indicating success.

Quick Quiz 6.26: Why do globalize_count() to zero the per-thread variables, only to later call balance_count() to refill them in Figure [*]? Why not just leave the per-thread variables non-zero? End Quick Quiz

Lines 20-36 show sub_count(), which subtracts the specified delta from the counter. Line 22 checks to see if the per-thread counter can accommodate this subtraction, and, if so, line 23 does the subtraction and line 24 returns success. These lines form sub_count()'s fastpath, and, as with add_count(), this fastpath executes no costly operations.

If the fastpath cannot accommodate subtraction of delta, execution proceeds to the slowpath on lines 26-35. Because the slowpath must access global state, line 26 acquires gblcnt_mutex, which is release either by line 29 (in case of failure) or by line 34 (in case of success). Line 27 invokes globalize_count(), shown in Figure [*], which again clears the thread-local variables, adjusting the global variables as needed. Line 28 checks to see if the counter can accommodate subtracting delta, and, if not, line 29 releases gblcnt_mutex (as noted earlier) and line 30 returns failure.

Quick Quiz 6.27: Given that globalreserve counted against us in add_count(), why doesn't it count for us in sub_count() in Figure [*]? End Quick Quiz

If, on the other hand, line 28 finds that the counter can accommodate subtracting delta, then line 32 does the subtraction, line 33 invokes balance_count() (shown in Figure [*]) in order to update both global and per-thread variables (hopefully re-enabling the fastpath), line 34 releases gblcnt_mutex, and line 35 returns success.

Quick Quiz 6.28: Why have both add_count() and sub_count() in Figure [*]? Why not simply pass a negative number to add_count()? End Quick Quiz

Lines 38-50 show read_count(), which returns the aggregate value of the counter. It acquires gblcnt_mutex on line 43 and releases it on line 48, excluding global operations from add_count() and sub_count(), and, as we will see, also excluding thread creation and exit. Line 44 initializes local variable sum to the value of globalcount, and then the loop spanning lines 45-47 sums the per-thread counter variables. Line 49 then returns the sum.

Figure: Simple Limit Counter Utility Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...idx] = NULL;
37 spin_unlock(&gblcnt_mutex);
38 }\end{verbatim}
}\end{figure}

Figure [*] shows a number of utility functions that support the add_count() sub_count(), and read_count() primitives shown in Figure [*].

Lines 1-7 show globalize_count(), which zeros the current thread's per-thread counters, adjusting the global variables appropriately. It is important to note that this function does not change the aggregate value of the counter, but instead changes how the counter's current value is represented. Line 3 adds the thread's counter variable to globalcount, and line 4 zeroes counter. Similarly, line 5 subtracts the per-thread countermax from globalreserve, and line 6 zeroes countermax. It is helpful to refer to Figure [*] when reading both this function and balance_count(), which is next.

Lines 9-19 show balance_count(), which can is, roughly speaking the inverse of globalize_count(). This function sets the current thread's counter and countermax variables (with corresponding adjustments to globalcount and globalreserve) in an attempt to promote use of add_count()'s and sub_count()'s fastpaths. As with globalize_count(), balance_count() does not change the aggregate value of the counter. Lines 11-13 compute this thread's share of that portion of globalcountmax that is not already covered by either globalcount or globalreserve, and assign the computed quantity to this thread's countermax. Line 14 makes the corresponding adjustment to globalreserve. Line 15 sets this thread's counter to the middle of the range from zero to countermax. Line 16 checks to see whether globalcount can in fact accommodate this value of counter, and, if not, line 17 decreases counter accordingly. Finally, in either case, line 18 makes the corresponding adjustment to globalcount.

Lines 21-28 show count_register_thread(), which sets up state for newly created threads. This function simply installs a pointer to the newly created thread's counter variable into the corresponding entry of the counterp[] array under the protection of gblcnt_mutex.

Finally, lines 30-38 show count_unregister_thread(), which tears down state for a soon-to-be-exiting thread. Line 34 acquires gblcnt_mutex and line 37 releases it. Line 35 invokes globalize_count() to clear out this thread's counter state, and line 36 clears this thread's entry in the counterp[] array.

Paul E. McKenney 2011-12-16
perfbook_html/img247.png0000644000175000017500000002225011672746072015317 0ustar paulmckpaulmckPNG  IHDRUz/ iNPLTEgdeb``MJK# hffommmkkcaaZWXXUVJGH856KHHC@@A>>wuv.*+1ޖ4tRNS@f IDATx](,jFjZ?:A񕘨'zN& ~.[D|Ng3pƵƇqZHSsobL/ϻ^<;mKW3M_Wt_uRƮT5pa&\ÅX< q(gyH8Hˌ5\TzL{JO >{6?/85(bH$r+ӞS/W-9,un8ʁC']oHF1n«S,~$0<fj C{nF)GfY(a@˷ L{gr>R+* 6AUi\pr1LSLˊFi QB` v{|+eU0`:@m8qE|G1;u-`1VV,'HYހ*~\/ jI 2+75Rur\oM/=Ex ,Y|`9YASAR&C[u73g?3feCunq-[0(œ>:fkEZA)8n67j< 3PxF LxQ1~n<\rt n֥O}*{Vgcێ7xl{\u ;(ib^Oyޅ^gьfo Rk1+c Sr9D- JƃҼkÐ (:d+ 0&3;JΣ׋PYXZ*oyIƊ&4W!5¯Y8RkjP ;a ;TUQ[n7*ܔ:/zqb>?ģ ')Rtt/w+.->dhU]#PF)u/ *h/ #ؗ)\ 54M o&;Rt^WT]D Pgh+70^F?62B,}k(G)6ȲZ'ChO"8`|K[ NBQH(V,m@dr"`+EcAe͡ \р\d1'+7w,H`~5t[rѦc:Ӯ0h^pk5I M)Oaf(6* VS\TƀԏnK(#0rÌx"LJ<~FvoQ 4rΐښZ`Y1Av:ݐ-10c氐n\пrR Ӏ0Q GHЌPu1k]jꄏ9"@>1LHGP> ƥM%G"ytAU'O-V X=+F=oDW@m]֦ û`j <gg23  ~e4nf*8Nhw :RWc #fJ!ף|Mz%Φ㑯#`^Qa>3sfLUc]q~.ئ\g*GY sQʯuU{ N9j\Ofg*%1;2hIe M1 Tf|?& -%IP)8̚2Pxh3vQP6:S?Pr%GnJAq\ZF3` Fw.udq kFܢW ž[߰\be2BE}x/Y4$߱ivhhjްFdh%psCe ˯ง}ը8.qjmJ(߉ oCy^-:5l/ً^~J3J0&TH ^ͷa)@-4F \ k WNsSo?F95# VXeL􉰟umu e8v}X>` !2\9gp1sjBe.e%X#ůx>Ǵ}T e8v58Ra69ߨ/#f,vxMsНek߶é9/,OOiL̅bR=,#ob1;=0fEOJLz^%Vm"a~t\KpsvX*X(vAz [52b)3Ydl{h8t@Z@1&a۠䜶<K+p30K1ڸo"&]̮ [Yq-јJMʌPaa ZuxHdwD^Ft|Bk7)ɂj-7(GHw  ωª. 'Q<, T?>zy1+q^{B|ʻ^^L\|Ķ%8A}5ב`aqԕѓ D? o o7όlAAzX8yϨd_xX8?vP4*2MYSSѷBTC:7>loBxBT5xm Tg C/D>f)wayz^T"uں v$SM/l$}ɴ)bMI{ 1kd ϵv֞<;)iOd{=˻=\9.ڣ/li0tQ:YWzH;عsp pZbΪoF å=J"PA"(/A@)㕠 UǦ>jZ0nvTܻ!.S=j[:orqW7ݩvՊ\^7ձ3QXsHh7~C{rظN"1V9&oms /& IaJZ>hN1q1Di1p/5܌~ 6:3^A܋MU*qfy' 5 44w}?h;4Ƈ!ٓ[L=$S#@ yx%>#^E(nG;y ;sdt(rm C( (1嘸C,k!-"^#](D{;S; $|S ]9H=0g}oG4z8WziR&h~S#'B߅)ԥ7d_(8a inCjnCjfBjZp %>zgn ِ"SP)P-ZK)$ 5k),'UqR0xAaI[ARj*^{-EO*vlqGW9.*,hSZUL㕋ц?D2CHc9~SHXQV.޽Ӵ[VQ62-cG2C8#R.gvH(lr*pTZX~]Gt CS:51+xy𰐼zy"5rRf >U<,3=B DJERSjR@HSybaAW @oK-@FkBvh0$]w?B ي B"VL ﷌8<C?"\?HEO*|5FV#9U3UyLhFq yv "p'x;ZS鳺j3n28TVÇl .b x +׆ⱚtkjӷq)L{>k0ÆF`+@6V't ayU[ȿt%Y*{~bCu4``ķ7`\ZZ:1V9 X]~3OX*Ǖl`" DPA6{.eXOМ6GOi)&')4yNC'P|Vٶ$8b̆^ͯMC[W{tϱWr>cSP@0M (!07E߸~(3@AAAn3/I ޅ7':L 7w}!*uڮJ}[ܡg=Du=S&Rf|(k$z[[7*٥{%0-ߕkEY#ů{R)P2mAdn J?)ZR}]0U,dˊR]oūR PYJZ<Q% ,((( jQ\,rnq:6֕#Z/zZ(u!uODohBΎh-o^ zh7 tz\4c$jxɹ.(ӧy7-8 s-`F9H=0;>+krd^]&f֑|?G@N:/c3I)5U^v *xz|5% +#HuyYGtW=DN,T5o۔ߑ@a");|X=UF1x%on*1''nX>[Suҩ#TySM=zu`eUrܪ-;Ne F6u}ֳCԲ푬8xÇZԚX>&3:vG&ZWFD9zc:QG"G:gb'Beݙĵ e];UOHЕ RY;fԚX>@vts79ѻfC0nXaޏguPTPPs~O(ѷ_Y<5sfA]uԬWkUF5+Z:e5F]q.Fh + Y ]ٜµбxL)>  )U'~vfs'x^x^eR'˂Skpz!)^h⍬.2PJIL;ѤBW"yd^: =_=w{3i|ATMa8V93jXPe*{i4'sK 8Si4'ܢYW %p7к8we((((8d]ZF6+[PPPP P`aمԒr?xRPPP1eӄ90cCqi'ӂO:4Vkpa$B"*%1NINc'i'xqI_($&'P>6@ !sX0I_)7A-cL\.e~|v*ȓORn ^5K>ECb16OsX(O;G9) R ~l*UtNxȼ<ܖTA,OM0H>Ffu\iF|k+Ƕe̵=F.<> %+׶ #N ś'HH3 FJ'ˎ {UC1bMM'7d;Fq">dx{ % N nj 󯖘n1jս #k]Pk6o*&3 h'\k#e{A^q湐P WUf@WP  v=YsD~0ܫ A`$YZdYt ][lļ6!dh *)Pn@X]cYH6ڻ$@܈C{^ nUէ@2Y P9e@kY3`M*(% 9Veocp)3v!K7b !6*џWN3؏C_ rSQrXvK~ֲ{CIENDB`perfbook_html/node283.html0000644000175000017500000000450411672746162015652 0ustar paulmckpaulmck B.3.4 spin_unlock()

B.3.4 spin_unlock()

The spin_unlock() primitive releases the specified spinlock, allowing other threads to acquire it.

@@@ likely need to add reader-writer locking.



Paul E. McKenney 2011-12-16
perfbook_html/img166.png0000644000175000017500000001073011672746005015313 0ustar paulmckpaulmckPNG  IHDR3i6PLTEMJK# b``mkkiggXUVROP856C@@wuv.*+3tRNS@fPIDATx]A|?;$DҪv{zˡ0 [C b' vS‚A'gEշz-F = SV yY8;{4M[]\Smbʚ}Nk #%,~`soMر<rՃ5[ 4Tij#K)YAe9|a8(:לּ4'A$^߾ QEg?y]YwS3K,W-%q<\u78b=x 5O6 )'3uM*>6j,׫3VCK (j'([E3J@#)D+-'4K +j eAo7ac9:ZZ:),QPb(}͘%,=Za\> zCS H" x=~zz}$MP~:t w7yҦ9P{hmUz$ u* _qk/NW `iH@Ld7Fũ v`}MKY;412ffqAp~At*RNRDu T1,vnR8dle֧8PJ}rTQC[^ lNӊ>rӟ7 s\o9)VCSHQv +']B[Y6[ю[w9>DÏ(sWҐidgAgV&J:'6Yo;K[@Yell ?8Um[S~P5#-f[ ; Ðe=d>Q{*1{Uz ?Ꞌ3&bMlGOCHz:m 'hC9Ȼ)Ԓ'aFQkS~Y_R({oZ5$D')C#xvYӨ SkKT;:69K,vv>cƞF+.'l{2w-~Z}"qVQ > %Y]sV;L'G^trfG7]cN^ÃLo +wZp-:RiGE%@桯fNVVu4sNv;?cۖ(fSC\N^dTpgvA_UK3PhzV1J]^"4U7n'Llr4FQW42_h/UNSqvnW 5{䳣y< ELhw7?yj::uy6TSnb9.4wN~&n/2R> 6qE8ztmd"D!vW\P 1оcq}:?ct2=|b6.5U)vup7VNT{]i @NHN@{9-gcfT@r;')L"%bn4AmyvgҀc)%f!,-1f3ݐ53$ Z(b{HxV$  kȨ0Oiɴ K` MQ1U'r[ la!r`}q349!bE_tѡ&dBG3W'E}!%(Iݜ@-sՖ--k@|a\;:fTMQAY3P 2ŋ55R'^ޕ֍DamQ^ dQc~0v]$?tEF.s-y ,bS=B2K]s}NBdhv m͈kNa;,8maGS<ۄ-?z5)Xkșb͢MWDLqDIXdb#K,o3C뚥]KԂ4h['SɘdѓhCm/5fdgAKWx~S&Hs4 5˅Wc* `*oklOdu`ӦQ́Mr l OeF%9VF55-hJb7M:l\치Z^ӭW2! `d*m_؃ [gSM=8$XxY~F1"SxnhQM(_x}P>Ho>עU,T3m3b=im{kj{멋,ڪ:Qf X10r6-eإ3iwfsp}y…[^C1o1/[ۘbwN9QQt9`3~,-XrtS1Ts4`͡9iK.$& #CݰS 2|*FKfH?b$a9cqVQx՞ f#Ⱥl+f)'&*D&mlK*4Z/|jC{Cw)%dy]hЄc`M'Ի9w=H`sc8>A" !o3 tZ?}t_~16^m7u@SGuD+igگ뢻mtZR8i$zm jDNJSNΓdxQBiޏZoTD:np F ,_)T}Krf]鰼QDŽg]!.[/,N j){ QxvdF jD*Q^P$( ߸ۆxt*2 ūv76GEe TV =A.4̨^~bvwca ڎU? /"&iux&: }`\`5nɂeQ~ g^(wv>/?0vLx{…ƛDm>;yX?Ʉ\}puGΈdU=;`}qϿ]#'D4$YתPHu +b I?f R8;A޴c&ӏ~\ZD%Adml=~VUJQLX=9,&:|ձd3,2WecK^VnUlv-$NlQIj35jsݪ >:1x~m2 hUra!]xۧ!W8LE±6KZd3S{::"wΡ3'CZ'۬S0?4\'.ko#$ f]Okzضl2]BZ+i6ŻטvrY!v/fd%-)/LuɊBkV<֢i ={S2n@jZ+RjcEJѮg7i]$=81 uJ,eBBf6S4]a TY_wx~sZF[<z^ qPzgČcq!AU7yF76OX<ˌSQIENDB`perfbook_html/node9.html0000644000175000017500000002460011672746161015504 0ustar paulmckpaulmck 3.2.3 Generality


3.2.3 Generality

One way to justify the high cost of developing parallel software is to strive for maximal generality. All else being equal, the cost of a more-general software artifact can be spread over more users than can a less-general artifact.

Unfortunately, generality often comes at the cost of performance, productivity, or both. To see this, consider the following popular parallel programming environments:

C/C++ ``Locking Plus Threads''
: This category, which includes POSIX Threads (pthreads) [Ope97], Windows Threads, and numerous operating-system kernel environments, offers excellent performance (at least within the confines of a single SMP system) and also offers good generality. Pity about the relatively low productivity.
Java
: This programming environment, which is inherently multithreaded, is widely believed to be much more productive than C or C++, courtesy of the automatic garbage collector and the rich set of class libraries, and is reasonably general purpose. However, its performance, though greatly improved over the past ten years, is generally considered to be less than that of C and C++.
MPI
: this message-passing interface [MPI08] powers the largest scientific and technical computing clusters in the world, so offers unparalleled performance and scalability. It is in theory general purpose, but has generally been used for scientific and technical computing. Its productivity is believed by many to be even less than that of C/C++ ``locking plus threads'' environments.
OpenMP
: this set of compiler directives can be used to parallelize loops. It is thus quite specific to this task, and this specificity often limits its performance. It is, however, much easier to use than MPI or parallel C/C++.
SQL
: structured query language [Int92] is extremely specific, applying only to relational database queries. However, its performance is quite good, doing quite well in Transaction Processing Performance Council (TPC) benchmarks [Tra01]. Productivity is excellent, in fact, this parallel programming environment permits people who know almost nothing about parallel programming to make good use of a large parallel machine.

Figure: Software Layers and Performance, Productivity, and Generality
\resizebox{3in}{!}{\includegraphics{intro/PPGrelation}}

The nirvana of parallel programming environments, one that offers world-class performance, productivity, and generality, simply does not yet exist. Until such a nirvana appears, it will be necessary to make engineering tradeoffs among performance, productivity, and generality. One such tradeoff is shown in Figure [*], which shows how productivity becomes increasingly important at the upper layers of the system stack, while performance and generality become increasingly important at the lower layers of the system stack. The huge development costs incurred near the bottom of the stack must be spread over equally huge numbers of users on the one hand (hence the importance of generality), and performance lost near the bottom of the stack cannot easily be recovered further up the stack. Near the top of the stack, there might be very few users for a given specific application, in which case productivity concerns are paramount. This explains the tendency towards ``bloatware'' further up the stack: extra hardware is often cheaper than would be the extra developers. This book is intended primarily for developers working near the bottom of the stack, where performance and generality are paramount concerns.

Figure: Tradeoff Between Productivity and Generality
\resizebox{3in}{!}{\includegraphics{intro/Generality}}

It is important to note that a tradeoff between productivity and generality has existed for centuries in many fields. For but one example, a nailgun is far more productive than is a hammer, but in contrast to the nailgun, a hammer can be used for many things besides driving nails. It should therefore be absolutely no surprise to see similar tradeoffs appear in the field of parallel computing. This tradeoff is shown schematically in Figure [*]. Here, Users 1, 2, 3, and 4 have specific jobs that they need the computer to help them with. The most productive possible language or environment for a given user is one that simply does that user's job, without requiring any programming, configuration, or other setup.

Quick Quiz 3.10: This is a ridiculously unachievable ideal! Why not focus on something that is achievable in practice? End Quick Quiz

Unfortunately, a system that does the job required by user 1 is unlikely to do user 2's job. In other words, the most productive languages and environments are domain-specific, and thus by definition lacking generality.

Another option is to tailor a given programming language or environment to the hardware system (for example, low-level languages such as assembly, C, C++, or Java) or to some abstraction (for example, Haskell, Prolog, or Snobol), as is shown by the circular region near the center of Figure [*]. These languages can be considered to be general in the sense that they are equally ill-suited to the jobs required by users 1, 2, 3, and 4. In other words, their generality is purchased at the expense of decreased productivity when compared to domain-specific languages and environments.

With the three often-conflicting parallel-programming goals of performance, productivity, and generality in mind, it is now time to look into avoiding these conflicts by considering alternatives to parallel programming.

Paul E. McKenney 2011-12-16
perfbook_html/node328.html0000644000175000017500000000645511672746163015662 0ustar paulmckpaulmck D.1.1 SRCU Implementation Strategy


D.1.1 SRCU Implementation Strategy

The primary challenge in designing an SRCU is to prevent any given task sleeping in an RCU read-side critical section from blocking an unbounded number of RCU callbacks. SRCU uses two strategies to achieve this goal:

  1. refusing to provide asynchronous grace-period interfaces, such as the Classic RCU's call_rcu() API, and
  2. isolating grace-period detection within each subsystem using SRCU.
The rationale for these strategies are discussed in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node182.html0000644000175000017500000000451211672746162015647 0ustar paulmckpaulmck 13.2 Computational Complexity and Performance


13.2 Computational Complexity and Performance

Complexity, performance, O(N).



Paul E. McKenney 2011-12-16
perfbook_html/node300.html0000644000175000017500000001042111672746163015634 0ustar paulmckpaulmck C.3 Stores Result in Unnecessary Stalls


C.3 Stores Result in Unnecessary Stalls

Although the cache structure shown in Figure [*] provides good performance for repeated reads and writes from a given CPU to a given item of data, its performance for the first write to a given cache line is quite poor. To see this, consider Figure [*], which shows a timeline of a write by CPU 0 to a cacheline held in CPU 1's cache. Since CPU 0 must wait for the cache line to arrive before it can write to it, CPU 0 must stall for an extended period of time.C.3

Figure: Writes See Unnecessary Stalls
\includegraphics{appendix/whymb/cacheSCwrite}

But there is no real reason to force CPU 0 to stall for so long -- after all, regardless of what data happens to be in the cache line that CPU 1 sends it, CPU 0 is going to unconditionally overwrite it.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node467.html0000644000175000017500000022007211672746163015657 0ustar paulmckpaulmck F.7 Chapter 

F.7 Chapter [*]

Quick Quiz [*].1: 
Why not implement reference-acquisition using a simple compare-and-swap operation that only acquires a reference if the reference counter is non-zero?
 
Answer:
Although this can resolve the race between the release of the last reference and acquisition of a new reference, it does absolutely nothing to prevent the data structure from being freed and reallocated, possibly as some completely different type of structure. It is quite likely that the ``simple compare-and-swap operation'' would give undefined results if applied to the differently typed structure.

In short, use of atomic operations such as compare-and-swap absolutely requires either type-safety or existence guarantees.

Quick Quiz [*].2: 
Why isn't it necessary to guard against cases where one CPU acquires a reference just after another CPU releases the last reference?
 
Answer:
Because a CPU must already hold a reference in order to legally acquire another reference. Therefore, if one CPU releases the last reference, there cannot possibly be any CPU that is permitted to acquire a new reference. This same fact allows the non-atomic check in line 22 of Figure [*].

Quick Quiz [*].3: 
If the check on line 22 of Figure [*] fails, how could the check on line 23 possibly succeed?
 
Answer:
Suppose that kref_put() is protected by RCU, so that two CPUs might be executing line 22 concurrently. Both might see the value ``2'', causing both to then execute line 23. One of the two instances of atomic_dec_and_test() will decrement the value to zero and thus return 1.

Quick Quiz [*].4: 
How can it possibly be safe to non-atomically check for equality with ``1'' on line 22 of Figure [*]?
 
Answer:
Remember that it is not legal to call either kref_get() or kref_put() unless you hold a reference. If the reference count is equal to ``1'', then there can't possibly be another CPU authorized to change the value of the reference count.

Quick Quiz [*].5: 
Why can't the check for a zero reference count be made in a simple ``if'' statement with an atomic increment in its ``then'' clause?
 
Answer:
Suppose that the ``if'' condition completed, finding the reference counter value equal to one. Suppose that a release operation executes, decrementing the reference counter to zero and therefore starting cleanup operations. But now the ``then'' clause can increment the counter back to a value of one, allowing the object to be used after it has been cleaned up.

Quick Quiz [*].6: 
But doesn't seqlock also permit readers and updaters to get work done concurrently?
 
Answer:
Yes and no. Although seqlock readers can run concurrently with seqlock writers, whenever this happens, the read_seqretry() primitive will force the reader to retry. This means that any work done by a seqlock reader running concurrently with a seqlock updater will be discarded and redone. So seqlock readers can run concurrently with updaters, but they cannot actually get any work done in this case.

In contrast, RCU readers can perform useful work even in presence of concurrent RCU updaters.

Quick Quiz [*].7: 
What prevents the list_for_each_entry_rcu() from getting a segfault if it happens to execute at exactly the same time as the list_add_rcu()?
 
Answer:
On all systems running Linux, loads from and stores to pointers are atomic, that is, if a store to a pointer occurs at the same time as a load from that same pointer, the load will return either the initial value or the value stored, never some bitwise mashup of the two. In addition, the list_for_each_entry_rcu() always proceeds forward through the list, never looking back. Therefore, the list_for_each_entry_rcu() will either see the element being added by list_add_rcu() or it will not, but either way, it will see a valid well-formed list.

Quick Quiz [*].8: 
Why do we need to pass two pointers into hlist_for_each_entry_rcu() when only one is needed for list_for_each_entry_rcu()?
 
Answer:
Because in an hlist it is necessary to check for NULL rather than for encountering the head. (Try coding up a single-pointer hlist_for_each_entry_rcu() If you come up with a nice solution, it would be a very good thing!)

Quick Quiz [*].9: 
How would you modify the deletion example to permit more than two versions of the list to be active?
 
Answer:
One way of accomplishing this is as shown in Figure [*].

Figure: Concurrent RCU Deletion
\begin{figure}{ \centering
\begin{verbatim}1 spin_lock(&mylock);
2 p = searc...
...&mylock);
8 synchronize_rcu();
9 kfree(p);
10 }\end{verbatim}
}\end{figure}

Note that this means that multiple concurrent deletions might be waiting in synchronize_rcu().

Quick Quiz [*].10: 
How many RCU versions of a given list can be active at any given time?
 
Answer:
That depends on the synchronization design. If a semaphore protecting the update is held across the grace period, then there can be at most two versions, the old and the new.

However, if only the search, the update, and the list_replace_rcu() were protected by a lock, then there could be an arbitrary number of versions active, limited only by memory and by how many updates could be completed within a grace period. But please note that data structures that are updated so frequently probably are not good candidates for RCU. That said, RCU can handle high update rates when necessary.

Quick Quiz [*].11: 
How can RCU updaters possibly delay RCU readers, given that the rcu_read_lock() and rcu_read_unlock() primitives neither spin nor block?
 
Answer:
The modifications undertaken by a given RCU updater will cause the corresponding CPU to invalidate cache lines containing the data, forcing the CPUs running concurrent RCU readers to incur expensive cache misses. (Can you design an algorithm that changes a data structure without inflicting expensive cache misses on concurrent readers? On subsequent readers?)

Quick Quiz [*].12: 
WTF? How the heck do you expect me to believe that RCU has a 100-femtosecond overhead when the clock period at 3GHz is more than 300 picoseconds?
 
Answer:
First, consider that the inner loop used to take this measurement is as follows:



  1 for (i = 0; i < CSCOUNT_SCALE; i++) {
  2   rcu_read_lock();
  3   rcu_read_unlock();
  4 }


Next, consider the effective definitions of rcu_read_lock() and rcu_read_unlock():



  1 #define rcu_read_lock()   do { } while (0)
  2 #define rcu_read_unlock() do { } while (0)


Consider also that the compiler does simple optimizations, allowing it to replace the loop with:



i = CSCOUNT_SCALE;


So the "measurement" of 100 femtoseconds is simply the fixed overhead of the timing measurements divided by the number of passes through the inner loop containing the calls to rcu_read_lock() and rcu_read_unlock(). And therefore, this measurement really is in error, in fact, in error by an arbitrary number of orders of magnitude. As you can see by the definition of rcu_read_lock() and rcu_read_unlock() above, the actual overhead is precisely zero.

It certainly is not every day that a timing measurement of 100 femtoseconds turns out to be an overestimate!

Quick Quiz [*].13: 
Why does both the variability and overhead of rwlock decrease as the critical-section overhead increases?
 
Answer:
Because the contention on the underlying rwlock_t decreases as the critical-section overhead increases. However, the rwlock overhead will not quite drop to that on a single CPU because of cache-thrashing overhead.

Quick Quiz [*].14: 
Is there an exception to this deadlock immunity, and if so, what sequence of events could lead to deadlock?
 
Answer:
One way to cause a deadlock cycle involving RCU read-side primitives is via the following (illegal) sequence of statements:



idx = srcu_read_lock(&srcucb);
synchronize_srcu(&srcucb);
srcu_read_unlock(&srcucb, idx);


The synchronize_rcu() cannot return until all pre-existing SRCU read-side critical sections complete, but is enclosed in an SRCU read-side critical section that cannot complete until the synchronize_srcu() returns. The result is a classic self-deadlock-you get the same effect when attempting to write-acquire a reader-writer lock while read-holding it.

Note that this self-deadlock scenario does not apply to RCU Classic, because the context switch performed by the synchronize_rcu() would act as a quiescent state for this CPU, allowing a grace period to complete. However, this is if anything even worse, because data used by the RCU read-side critical section might be freed as a result of the grace period completing.

In short, do not invoke synchronous RCU update-side primitives from within an RCU read-side critical section.

Quick Quiz [*].15: 
But wait! This is exactly the same code that might be used when thinking of RCU as a replacement for reader-writer locking! What gives?
 
Answer:
This is an effect of the Law of Toy Examples: beyond a certain point, the code fragments look the same. The only difference is in how we think about the code. However, this difference can be extremely important. For but one example of the importance, consider that if we think of RCU as a restricted reference counting scheme, we would never be fooled into thinking that the updates would exclude the RCU read-side critical sections.

It nevertheless is often useful to think of RCU as a replacement for reader-writer locking, for example, when you are replacing reader-writer locking with RCU.

Quick Quiz [*].16: 
Why the dip in refcnt overhead near 6 CPUs?
 
Answer:
Most likely NUMA effects. However, there is substantial variance in the values measured for the refcnt line, as can be seen by the error bars. In fact, standard deviations range in excess of 10values in some cases. The dip in overhead therefore might well be a statistical aberration.

Quick Quiz [*].17: 
What if the element we need to delete is not the first element of the list on line 9 of Figure [*]?
 
Answer:
As with Figure [*], this is a very simple hash table with no chaining, so the only element in a given bucket is the first element. The reader is again invited to adapt this example to a hash table with full chaining.

Quick Quiz [*].18: 
Why is it OK to exit the RCU read-side critical section on line 15 of Figure [*] before releasing the lock on line 17?
 
Answer:
First, please note that the second check on line 14 is necessary because some other CPU might have removed this element while we were waiting to acquire the lock. However, the fact that we were in an RCU read-side critical section while acquiring the lock guarantees that this element could not possibly have been re-allocated and re-inserted into this hash table. Furthermore, once we acquire the lock, the lock itself guarantees the element's existence, so we no longer need to be in an RCU read-side critical section.

The question as to whether it is necessary to re-check the element's key is left as an exercise to the reader.

Quick Quiz [*].19: 
Why not exit the RCU read-side critical section on line 23 of Figure [*] before releasing the lock on line 22?
 
Answer:
Suppose we reverse the order of these two lines. Then this code is vulnerable to the following sequence of events:

  1. CPU 0 invokes delete(), and finds the element to be deleted, executing through line 15. It has not yet actually deleted the element, but is about to do so.
  2. CPU 1 concurrently invokes delete(), attempting to delete this same element. However, CPU 0 still holds the lock, so CPU 1 waits for it at line 13.
  3. CPU 0 executes lines 16 and 17, and blocks at line 18 waiting for CPU 1 to exit its RCU read-side critical section.
  4. CPU 1 now acquires the lock, but the test on line 14 fails because CPU 0 has already removed the element. CPU 1 now executes line 22 (which we switched with line 23 for the purposes of this Quick Quiz) and exits its RCU read-side critical section.
  5. CPU 0 can now return from synchronize_rcu(), and thus executes line 19, sending the element to the freelist.
  6. CPU 1 now attempts to release a lock for an element that has been freed, and, worse yet, possibly reallocated as some other type of data structure. This is a fatal memory-corruption error.

Quick Quiz [*].20: 
But what if there is an arbitrarily long series of RCU read-side critical sections in multiple threads, so that at any point in time there is at least one thread in the system executing in an RCU read-side critical section? Wouldn't that prevent any data from a SLAB_DESTROY_BY_RCU slab ever being returned to the system, possibly resulting in OOM events?
 
Answer:
There could certainly be an arbitrarily long period of time during which at least one thread is always in an RCU read-side critical section. However, the key words in the description in Section [*] are ``in-use'' and ``pre-existing''. Keep in mind that a given RCU read-side critical section is conceptually only permitted to gain references to data elements that were in use at the beginning of that critical section. Furthermore, remember that a slab cannot be returned to the system until all of its data elements have been freed, in fact, the RCU grace period cannot start until after they have all been freed.

Therefore, the slab cache need only wait for those RCU read-side critical sections that started before the freeing of the last element of the slab. This in turn means that any RCU grace period that begins after the freeing of the last element will do--the slab may be returned to the system after that grace period ends.

Quick Quiz [*].21: 
Suppose that the nmi_profile() function was preemptible. What would need to change to make this example work correctly?
 
Answer:
One approach would be to use rcu_read_lock() and rcu_read_unlock() in nmi_profile(), and to replace the synchronize_sched() with synchronize_rcu(), perhaps as shown in Figure [*].

Figure: Using RCU to Wait for Mythical Preemptible NMIs to Finish
\begin{figure}{ \tt\scriptsize
\begin{verbatim}1 struct profile_buffer {
2 l...
... NULL);
32 synchronize_rcu();
33 kfree(p);
34 }\end{verbatim}
}\end{figure}

Quick Quiz [*].22: 
Why do some of the cells in Table [*] have exclamation marks (``!'')?
 
Answer:
The API members with exclamation marks (rcu_read_lock(), rcu_read_unlock(), and call_rcu()) were the only members of the Linux RCU API that Paul E. McKenney was aware of back in the mid-90s. During this timeframe, he was under the mistaken impression that he knew all that there is to know about RCU.

Quick Quiz [*].23: 
How do you prevent a huge number of RCU read-side critical sections from indefinitely blocking a synchronize_rcu() invocation?
 
Answer:
There is no need to do anything to prevent RCU read-side critical sections from indefinitely blocking a synchronize_rcu() invocation, because the synchronize_rcu() invocation need wait only for pre-existing RCU read-side critical sections. So as long as each RCU read-side critical section is of finite duration, there should be no problem.

Quick Quiz [*].24: 
The synchronize_rcu() API waits for all pre-existing interrupt handlers to complete, right?
 
Answer:
Absolutely not! And especially not when using preemptible RCU! You instead want synchronize_irq(). Alternatively, you can place calls to rcu_read_lock() and rcu_read_unlock() in the specific interrupt handlers that you want synchronize_rcu() to wait for.

Quick Quiz [*].25: 
What happens if you mix and match? For example, suppose you use rcu_read_lock() and rcu_read_unlock() to delimit RCU read-side critical sections, but then use call_rcu_bh() to post an RCU callback?
 
Answer:
If there happened to be no RCU read-side critical sections delimited by rcu_read_lock_bh() and rcu_read_unlock_bh() at the time call_rcu_bh() was invoked, RCU would be within its rights to invoke the callback immediately, possibly freeing a data structure still being used by the RCU read-side critical section! This is not merely a theoretical possibility: a long-running RCU read-side critical section delimited by rcu_read_lock() and rcu_read_unlock() is vulnerable to this failure mode.

This vulnerability disappears in -rt kernels, where RCU Classic and RCU BH both map onto a common implementation.

Quick Quiz [*].26: 
Hardware interrupt handlers can be thought of as being under the protection of an implicit rcu_read_lock_bh(), right?
 
Answer:
Absolutely not! And especially not when using preemptible RCU! If you need to access ``rcu_bh''-protected data structures in an interrupt handler, you need to provide explicit calls to rcu_read_lock_bh() and rcu_read_unlock_bh().

Quick Quiz [*].27: 
What happens if you mix and match RCU Classic and RCU Sched?
 
Answer:
In a non-PREEMPT or a PREEMPT kernel, mixing these two works "by accident" because in those kernel builds, RCU Classic and RCU Sched map to the same implementation. However, this mixture is fatal in PREEMPT_RT builds using the -rt patchset, due to the fact that Realtime RCU's read-side critical sections can be preempted, which would permit synchronize_sched() to return before the RCU read-side critical section reached its rcu_read_unlock() call. This could in turn result in a data structure being freed before the read-side critical section was finished with it, which could in turn greatly increase the actuarial risk experienced by your kernel.

In fact, the split between RCU Classic and RCU Sched was inspired by the need for preemptible RCU read-side critical sections.

Quick Quiz [*].28: 
In general, you cannot rely on synchronize_sched() to wait for all pre-existing interrupt handlers, right?
 
Answer:
That is correct! Because -rt Linux uses threaded interrupt handlers, there can be context switches in the middle of an interrupt handler. Because synchronize_sched() waits only until each CPU has passed through a context switch, it can return before a given interrupt handler completes.

If you need to wait for a given interrupt handler to complete, you should instead use synchronize_irq() or place explicit RCU read-side critical sections in the interrupt handlers that you wish to wait on.

Quick Quiz [*].29: 
Why do both SRCU and QRCU lack asynchronous call_srcu() or call_qrcu() interfaces?
 
Answer:
Given an asynchronous interface, a single task could register an arbitrarily large number of SRCU or QRCU callbacks, thereby consuming an arbitrarily large quantity of memory. In contrast, given the current synchronous synchronize_srcu() and synchronize_qrcu() interfaces, a given task must finish waiting for a given grace period before it can start waiting for the next one.

Quick Quiz [*].30: 
Under what conditions can synchronize_srcu() be safely used within an SRCU read-side critical section?
 
Answer:
In principle, you can use synchronize_srcu() with a given srcu_struct within an SRCU read-side critical section that uses some other srcu_struct. In practice, however, doing this is almost certainly a bad idea. In particular, the code shown in Figure [*] could still result in deadlock.

Figure: Multistage SRCU Deadlocks
\begin{figure}{ \centering
\begin{verbatim}1 idx = srcu_read_lock(&ssa);
2 s...
...ronize_srcu(&ssa);
9 srcu_read_unlock(&ssb, idx);\end{verbatim}
}\end{figure}

Quick Quiz [*].31: 
Why doesn't list_del_rcu() poison both the next and prev pointers?
 
Answer:
Poisoning the next pointer would interfere with concurrent RCU readers, who must use this pointer. However, RCU readers are forbidden from using the prev pointer, so it may safely be poisoned.

Quick Quiz [*].32: 
Normally, any pointer subject to rcu_dereference() must always be updated using rcu_assign_pointer(). What is an exception to this rule?
 
Answer:
One such exception is when a multi-element linked data structure is initialized as a unit while inaccessible to other CPUs, and then a single rcu_assign_pointer() is used to plant a global pointer to this data structure. The initialization-time pointer assignments need not use rcu_assign_pointer(), though any such assignments that happen after the structure is globally visible must use rcu_assign_pointer().

However, unless this initialization code is on an impressively hot code-path, it is probably wise to use rcu_assign_pointer() anyway, even though it is in theory unnecessary. It is all too easy for a "minor" change to invalidate your cherished assumptions about the initialization happening privately.

Quick Quiz [*].33: 
Are there any downsides to the fact that these traversal and update primitives can be used with any of the RCU API family members?
 
Answer:
It can sometimes be difficult for automated code checkers such as ``sparse'' (or indeed for human beings) to work out which type of RCU read-side critical section a given RCU traversal primitive corresponds to. For example, consider the code shown in Figure [*].

Figure: Diverse RCU Read-Side Nesting
\begin{figure}{ \centering
\begin{verbatim}1 rcu_read_lock();
2 preempt_disa...
.... */
6
7 preempt_enable();
8 rcu_read_unlock();\end{verbatim}
}\end{figure}

Is the rcu_dereference() primitive in an RCU Classic or an RCU Sched critical section? What would you have to do to figure this out?

Quick Quiz [*].34: 
Why wouldn't any deadlock in the RCU implementation in Figure [*] also be a deadlock in any other RCU implementation?
 
Answer:

Figure: Deadlock in Lock-Based RCU Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 void foo(void)
2 {
3 spin_loc...
...);
17 do_whatever();
18 rcu_read_unlock();
19 }\end{verbatim}
}\end{figure}

Suppose the functions foo() and bar() in Figure [*] are invoked concurrently from different CPUs. Then foo() will acquire my_lock() on line 3, while bar() will acquire rcu_gp_lock on line 13. When foo() advances to line 4, it will attempt to acquire rcu_gp_lock, which is held by bar(). Then when bar() advances to line 14, it will attempt to acquire my_lock, which is held by foo().

Each function is then waiting for a lock that the other holds, a classic deadlock.

Other RCU implementations neither spin nor block in rcu_read_lock(), hence avoiding deadlocks.

Quick Quiz [*].35: 
Why not simply use reader-writer locks in the RCU implementation in Figure [*] in order to allow RCU readers to proceed in parallel?
 
Answer:
One could in fact use reader-writer locks in this manner. However, textbook reader-writer locks suffer from memory contention, so that the RCU read-side critical sections would need to be quite long to actually permit parallel execution [McK03].

On the other hand, use of a reader-writer lock that is read-acquired in rcu_read_lock() would avoid the deadlock condition noted above.

Quick Quiz [*].36: 
Wouldn't it be cleaner to acquire all the locks, and then release them all in the loop from lines 15-18 of Figure [*]? After all, with this change, there would be a point in time when there were no readers, simplifying things greatly.
 
Answer:
Making this change would re-introduce the deadlock, so no, it would not be cleaner.

Quick Quiz [*].37: 
Is the implementation shown in Figure [*] free from deadlocks? Why or why not?
 
Answer:
One deadlock is where a lock is held across synchronize_rcu(), and that same lock is acquired within an RCU read-side critical section. However, this situation will deadlock any correctly designed RCU implementation. After all, the synchronize_rcu() primitive must wait for all pre-existing RCU read-side critical sections to complete, but if one of those critical sections is spinning on a lock held by the thread executing the synchronize_rcu(), we have a deadlock inherent in the definition of RCU.

Another deadlock happens when attempting to nest RCU read-side critical sections. This deadlock is peculiar to this implementation, and might be avoided by using recursive locks, or by using reader-writer locks that are read-acquired by rcu_read_lock() and write-acquired by synchronize_rcu().

However, if we exclude the above two cases, this implementation of RCU does not introduce any deadlock situations. This is because only time some other thread's lock is acquired is when executing synchronize_rcu(), and in that case, the lock is immediately released, prohibiting a deadlock cycle that does not involve a lock held across the synchronize_rcu() which is the first case above.

Quick Quiz [*].38: 
Isn't one advantage of the RCU algorithm shown in Figure [*] that it uses only primitives that are widely available, for example, in POSIX pthreads?
 
Answer:
This is indeed an advantage, but do not forget that rcu_dereference() and rcu_assign_pointer() are still required, which means volatile manipulation for rcu_dereference() and memory barriers for rcu_assign_pointer(). Of course, many Alpha CPUs require memory barriers for both primitives.

Quick Quiz [*].39: 
But what if you hold a lock across a call to synchronize_rcu(), and then acquire that same lock within an RCU read-side critical section?
 
Answer:
Indeed, this would deadlock any legal RCU implementation. But is rcu_read_lock() really participating in the deadlock cycle? If you believe that it is, then please ask yourself this same question when looking at the RCU implementation in Section [*].

Quick Quiz [*].40: 
How can the grace period possibly elapse in 40 nanoseconds when synchronize_rcu() contains a 10-millisecond delay?
 
Answer:
The update-side test was run in absence of readers, so the poll() system call was never invoked. In addition, the actual code has this poll() system call commented out, the better to evaluate the true overhead of the update-side code. Any production uses of this code would be better served by using the poll() system call, but then again, production uses would be even better served by other implementations shown later in this section.

Quick Quiz [*].41: 
Why not simply make rcu_read_lock() wait when a concurrent synchronize_rcu() has been waiting too long in the RCU implementation in Figure [*]? Wouldn't that prevent synchronize_rcu() from starving?
 
Answer:
Although this would in fact eliminate the starvation, it would also mean that rcu_read_lock() would spin or block waiting for the writer, which is in turn waiting on readers. If one of these readers is attempting to acquire a lock that the spinning/blocking rcu_read_lock() holds, we again have deadlock.

In short, the cure is worse than the disease. See Section [*] for a proper cure.

Quick Quiz [*].42: 
Why the memory barrier on line 5 of synchronize_rcu() in Figure [*] given that there is a spin-lock acquisition immediately after?
 
Answer:
The spin-lock acquisition only guarantees that the spin-lock's critical section will not ``bleed out'' to precede the acquisition. It in no way guarantees that code preceding the spin-lock acquisition won't be reordered into the critical section. Such reordering could cause a removal from an RCU-protected list to be reordered to follow the complementing of rcu_idx, which could allow a newly starting RCU read-side critical section to see the recently removed data element.

Exercise for the reader: use a tool such as Promela/spin to determine which (if any) of the memory barriers in Figure [*] are really needed. See Section [*] for information on using these tools. The first correct and complete response will be credited.

Quick Quiz [*].43: 
Why is the counter flipped twice in Figure [*]? Shouldn't a single flip-and-wait cycle be sufficient?
 
Answer:
Both flips are absolutely required. To see this, consider the following sequence of events:

  1. Line 8 of rcu_read_lock() in Figure [*] picks up rcu_idx, finding its value to be zero.
  2. Line 8 of synchronize_rcu() in Figure [*] complements the value of rcu_idx, setting its value to one.
  3. Lines 10-13 of synchronize_rcu() find that the value of rcu_refcnt[0] is zero, and thus returns. (Recall that the question is asking what happens if lines 14-20 are omitted.)
  4. Lines 9 and 10 of rcu_read_lock() store the value zero to this thread's instance of rcu_read_idx and increments rcu_refcnt[0], respectively. Execution then proceeds into the RCU read-side critical section.
  5. Another instance of synchronize_rcu() again complements rcu_idx, this time setting its value to zero. Because rcu_refcnt[1] is zero, synchronize_rcu() returns immediately. (Recall that rcu_read_lock() incremented rcu_refcnt[0], not rcu_refcnt[1]!)
  6. The grace period that started in step [*] has been allowed to end, despite the fact that the RCU read-side critical section that started beforehand in step [*] has not completed. This violates RCU semantics, and could allow the update to free a data element that the RCU read-side critical section was still referencing.

Exercise for the reader: What happens if rcu_read_lock() is preempted for a very long time (hours!) just after line 8? Does this implementation operate correctly in that case? Why or why not? The first correct and complete response will be credited.

Quick Quiz [*].44: 
Given that atomic increment and decrement are so expensive, why not just use non-atomic increment on line 10 and a non-atomic decrement on line 25 of Figure [*]?
 
Answer:
Using non-atomic operations would cause increments and decrements to be lost, in turn causing the implementation to fail. See Section [*] for a safe way to use non-atomic operations in rcu_read_lock() and rcu_read_unlock().

Quick Quiz [*].45: 
Come off it! We can see the atomic_read() primitive in rcu_read_lock()!!! So why are you trying to pretend that rcu_read_lock() contains no atomic operations???
 
Answer:
The atomic_read() primitives does not actually execute atomic machine instructions, but rather does a normal load from an atomic_t. Its sole purpose is to keep the compiler's type-checking happy. If the Linux kernel ran on 8-bit CPUs, it would also need to prevent ``store tearing'', which could happen due to the need to store a 16-bit pointer with two eight-bit accesses on some 8-bit systems. But thankfully, it seems that no one runs Linux on 8-bit systems.

Quick Quiz [*].46: 
Great, if we have $N$ threads, we can have $2N$ ten-millisecond waits (one set per flip_counter_and_wait() invocation, and even that assumes that we wait only once for each thread. Don't we need the grace period to complete much more quickly?
 
Answer:
Keep in mind that we only wait for a given thread if that thread is still in a pre-existing RCU read-side critical section, and that waiting for one hold-out thread gives all the other threads a chance to complete any pre-existing RCU read-side critical sections that they might still be executing. So the only way that we would wait for $2N$ intervals would be if the last thread still remained in a pre-existing RCU read-side critical section despite all the waiting for all the prior threads. In short, this implementation will not wait unnecessarily.

However, if you are stress-testing code that uses RCU, you might want to comment out the poll() statement in order to better catch bugs that incorrectly retain a reference to an RCU-protected data element outside of an RCU read-side critical section.

Quick Quiz [*].47: 
All of these toy RCU implementations have either atomic operations in rcu_read_lock() and rcu_read_unlock(), or synchronize_rcu() overhead that increases linearly with the number of threads. Under what circumstances could an RCU implementation enjoy light-weight implementations for all three of these primitives, all having deterministic ( $O\left(1\right)$) overheads and latencies?
 
Answer:
Special-purpose uniprocessor implementations of RCU can attain this ideal [McK09a].

Quick Quiz [*].48: 
If any even value is sufficient to tell synchronize_rcu() to ignore a given task, why doesn't line 10 of Figure [*] simply assign zero to rcu_reader_gp?
 
Answer:
Assigning zero (or any other even-numbered constant) would in fact work, but assigning the value of rcu_gp_ctr can provide a valuable debugging aid, as it gives the developer an idea of when the corresponding thread last exited an RCU read-side critical section.

Quick Quiz [*].49: 
Why are the memory barriers on lines 17 and 29 of Figure [*] needed? Aren't the memory barriers inherent in the locking primitives on lines 18 and 28 sufficient?
 
Answer:
These memory barriers are required because the locking primitives are only guaranteed to confine the critical section. The locking primitives are under absolutely no obligation to keep other code from bleeding in to the critical section. The pair of memory barriers are therefore requires to prevent this sort of code motion, whether performed by the compiler or by the CPU.

Quick Quiz [*].50: 
Couldn't the update-side optimization described in Section [*] be applied to the implementation shown in Figure [*]?
 
Answer:
Indeed it could, with a few modifications. This work is left as an exercise for the reader.

Quick Quiz [*].51: 
Is the possibility o readers being preempted in line 3 of Figure [*] a real problem, in other words, is there a real sequence of events that could lead to failure? If not, why not? If so, what is the sequence of events, and how can the failure be addressed?
 
Answer:
It is a real problem, there is a sequence of events leading to failure, and there are a number of possible ways of addressing it. For more details, see the Quick Quizzes near the end of Section [*]. The reason for locating the discussion there is to (1) give you more time to think about it, and (2) because the nesting support added in that section greatly reduces the time required to overflow the counter.

Quick Quiz [*].52: 
Why not simply maintain a separate per-thread nesting-level variable, as was done in previous section, rather than having all this complicated bit manipulation?
 
Answer:
The apparent simplicity of the separate per-thread variable is a red herring. This approach incurs much greater complexity in the guise of careful ordering of operations, especially if signal handlers are to be permitted to contain RCU read-side critical sections. But don't take my word for it, code it up and see what you end up with!

Quick Quiz [*].53: 
Given the algorithm shown in Figure [*], how could you double the time required to overflow the global rcu_gp_ctr?
 
Answer:
One way would be to replace the magnitude comparison on lines 33 and 34 with an inequality check of the per-thread rcu_reader_gp variable against rcu_gp_ctr+RCU_GP_CTR_BOTTOM_BIT.

Quick Quiz [*].54: 
Again, given the algorithm shown in Figure [*], is counter overflow fatal? Why or why not? If it is fatal, what can be done to fix it?
 
Answer:
It can indeed be fatal. To see this, consider the following sequence of events:

  1. Thread 0 enters rcu_read_lock(), determines that it is not nested, and therefore fetches the value of the global rcu_gp_ctr. Thread 0 is then preempted for an extremely long time (before storing to its per-thread rcu_reader_gp variable).
  2. Other threads repeatedly invoke synchronize_rcu(), so that the new value of the global rcu_gp_ctr is now RCU_GP_CTR_BOTTOM_BIT less than it was when thread 0 fetched it.
  3. Thread 0 now starts running again, and stores into its per-thread rcu_reader_gp variable. The value it stores is RCU_GP_CTR_BOTTOM_BIT+1 greater than that of the global rcu_gp_ctr.
  4. Thread 0 acquires a reference to RCU-protected data element A.
  5. Thread 1 now removes the data element A that thread 0 just acquired a reference to.
  6. Thread 1 invokes synchronize_rcu(), which increments the global rcu_gp_ctr by RCU_GP_CTR_BOTTOM_BIT. It then checks all of the per-thread rcu_reader_gp variables, but thread 0's value (incorrectly) indicates that it started after thread 1's call to synchronize_rcu(), so thread 1 does not wait for thread 0 to complete its RCU read-side critical section.
  7. Thread 1 then frees up data element A, which thread 0 is still referencing.

Note that scenario can also occur in the implementation presented in Section [*].

One strategy for fixing this problem is to use 64-bit counters so that the time required to overflow them would exceed the useful lifetime of the computer system. Note that non-antique members of the 32-bit x86 CPU family allow atomic manipulation of 64-bit counters via the cmpxchg64b instruction.

Another strategy is to limit the rate at which grace periods are permitted to occur in order to achieve a similar effect. For example, synchronize_rcu() could record the last time that it was invoked, and any subsequent invocation would then check this time and block as needed to force the desired spacing. For example, if the low-order four bits of the counter were reserved for nesting, and if grace periods were permitted to occur at most ten times per second, then it would take more than 300 days for the counter to overflow. However, this approach is not helpful if there is any possibility that the system will be fully loaded with CPU-bound high-priority real-time threads for the full 300 days. (A remote possibility, perhaps, but best to consider it ahead of time.)

A third approach is to administratively abolish real-time threads from the system in question. In this case, the preempted process will age up in priority, thus getting to run long before the counter had a chance to overflow. Of course, this approach is less than helpful for real-time applications.

A final approach would be for rcu_read_lock() to recheck the value of the global rcu_gp_ctr after storing to its per-thread rcu_reader_gp counter, retrying if the new value of the global rcu_gp_ctr is inappropriate. This works, but introduces non-deterministic execution time into rcu_read_lock(). On the other hand, if your application is being preempted long enough for the counter to overflow, you have no hope of deterministic execution time in any case!

Quick Quiz [*].55: 
Doesn't the additional memory barrier shown on line 14 of Figure [*], greatly increase the overhead of rcu_quiescent_state?
 
Answer:
Indeed it does! An application using this implementation of RCU should therefore invoke rcu_quiescent_state sparingly, instead using rcu_read_lock() and rcu_read_unlock() most of the time.

However, this memory barrier is absolutely required so that other threads will see the store on lines 12-13 before any subsequent RCU read-side critical sections executed by the caller.

Quick Quiz [*].56: 
Why are the two memory barriers on lines 19 and 22 of Figure [*] needed?
 
Answer:
The memory barrier on line 19 prevents any RCU read-side critical sections that might precede the call to rcu_thread_offline() won't be reordered by either the compiler or the CPU to follow the assignment on lines 20-21. The memory barrier on line 22 is, strictly speaking, unnecessary, as it is illegal to have any RCU read-side critical sections following the call to rcu_thread_offline().

Quick Quiz [*].57: 
To be sure, the clock frequencies of ca-2008 Power systems were quite high, but even a 5GHz clock frequency is insufficient to allow loops to be executed in 50 picoseconds! What is going on here?
 
Answer:
Since the measurement loop contains a pair of empty functions, the compiler optimizes it away. The measurement loop takes 1,000 passes between each call to rcu_quiescent_state(), so this measurement is roughly one thousandth of the overhead of a single call to rcu_quiescent_state().

Quick Quiz [*].58: 
Why would the fact that the code is in a library make any difference for how easy it is to use the RCU implementation shown in Figures [*] and [*]?
 
Answer:
A library function has absolutely no control over the caller, and thus cannot force the caller to invoke rcu_quiescent_state() periodically. On the other hand, a library function that made many references to a given RCU-protected data structure might be able to invoke rcu_thread_online() upon entry, rcu_quiescent_state() periodically, and rcu_thread_offline() upon exit.

Quick Quiz [*].59: 
But what if you hold a lock across a call to synchronize_rcu(), and then acquire that same lock within an RCU read-side critical section? This should be a deadlock, but how can a primitive that generates absolutely no code possibly participate in a deadlock cycle?
 
Answer:
Please note that the RCU read-side critical section is in effect extended beyond the enclosing rcu_read_lock() and rcu_read_unlock(), out to the previous and next call to rcu_quiescent_state(). This rcu_quiescent_state can be thought of as a rcu_read_unlock() immediately followed by an rcu_read_lock().

Even so, the actual deadlock itself will involve the lock acquisition in the RCU read-side critical section and the synchronize_rcu(), never the rcu_quiescent_state().

Quick Quiz [*].60: 
Given that grace periods are prohibited within RCU read-side critical sections, how can an RCU data structure possibly be updated while in an RCU read-side critical section?
 
Answer:
This situation is one reason for the existence of asynchronous grace-period primitives such as call_rcu(). This primitive may be invoked within an RCU read-side critical section, and the specified RCU callback will in turn be invoked at a later time, after a grace period has elapsed.

The ability to perform an RCU update while within an RCU read-side critical section can be extremely convenient, and is analogous to a (mythical) unconditional read-to-write upgrade for reader-writer locking.

Quick Quiz [*].61: 
The statistical-counter implementation shown in Figure [*] (count_end.c) used a global lock to guard the summation in read_count(), which resulted in poor performance and negative scalability. How could you use RCU to provide read_count() with excellent performance and good scalability. (Keep in mind that read_count()'s scalability will necessarily be limited by its need to scan all threads' counters.)
 
Answer:
Hint: place the global variable finalcount and the array counterp[] into a single RCU-protected struct. At initialization time, this structure would be allocated and set to all zero and NULL.

The inc_count() function would be unchanged.

The read_count() function would use rcu_read_lock() instead of acquiring final_mutex, and would need to use rcu_dereference() to acquire a reference to the current structure.

The count_register_thread() function would set the array element corresponding to the newly created thread to reference that thread's per-thread counter variable.

The count_unregister_thread() function would need to allocate a new structure, acquire final_mutex, copy the old structure to the new one, add the outgoing thread's counter variable to the total, NULL the pointer to this same counter variable, use rcu_assign_pointer() to install the new structure in place of the old one, release final_mutex, wait for a grace period, and finally free the old structure.

Does this really work? Why or why not?

Quick Quiz [*].62: 
Section [*] showed a fanciful pair of code fragments that dealt with counting I/O accesses to removable devices. These code fragments suffered from high overhead on the fastpath (starting an I/O) due to the need to acquire a reader-writer lock. How would you use RCU to provide excellent performance and scalability? (Keep in mind that the performance of the common-case first code fragment that does I/O accesses is much more important than that of the device-removal code fragment.)
 
Answer:
Hint: replace the read-acquisitions of the reader-writer lock with RCU read-side critical sections, then adjust the device-removal code fragment to suit.

See Section [*] on Page [*] for one solution to this problem.

Paul E. McKenney 2011-12-16
perfbook_html/img296.png0000644000175000017500000001650011672745755015333 0ustar paulmckpaulmckPNG  IHDRIC%NPLTE^\\\ZZMJK# b``vstmkka__XUVNKL856C@@wuv.*+6tRNS@fIDATx] v-:?uC1e A/Ei ]5J9xT\KZ56<-5szkT١Kj!“NօZF>)I)g;U`:,NX|Ǟ lgS]eA+8m@`PBhj pm LM=3WS o\P.UQN cp5vĺpqvLڸ~3MhFWnD;|vZ\gu]۪jtmw}c8 Ehpwvu`ྣm+qFOGGW.Q MT!X9^]e4ޤUDkpֶ7d^ ^ZU 4[(k$|oxA/_Dc?YGx|@"V<"x$@"l.=>PԚV FW=7u֐]ނ,R23L$aUе!_?$H49y Ӟ4^D{[V֑xk?˴#|ٷ`Mn,rؤMmԮz;ALˊk!P뢑@vѵ~Q@%cC g(YUEDKj~qX̤~3*0x⯤pb'ר*X Z=jjE:|S7[qNI-ׯha}gZ:6c8{/ur! %կR^nW3{ ri-xx?@e6Y ^M~i#ִ_y*ǖ(TeA: UXP2rK&_)"g`P<[i?k@ehQ7B6Q;I[?K ! FQ^[t6 |'9'0>]ς[Ϯu.k]5ZiyFVv k=1!V<tyrggJqN><ݢ|jG=Jk{e}"!Olr.JBif%-6 ׼ěwzϭ1_dc$u+@"e䁧5<=xӱo~ktAGB;ZZD]yZ"v}3֫p*Waj۱RS u |u,;;oOm?3~%nHуl92=x2=2 g(jjaHF$m%B@U iub|pMz dF=GE:WзCF8Ρv#Ǭ9jJlbCN*73i4(+I{rt?:W1f2| 36)Lx z?!A^}Jr$WmP=3_YB o-T<5ݨT`cX<`ms0 NsiL o,HPc{Z\*IP'5" -Hz"u 7H ieBA 4/ 5/wطslouŮ5 RJ U+z dF\% a·k*yΠ߅<܋wWCYJPHď/ŧ[FkGj~q֭9ӫU/Rc%oG{ c'q}9.\euJ(0#S{](J9WE^`X!Ϋ; ֜rsPb 1.-Nt(QUEZv won݀NR5>R~JJs&$3Z Z3[`("(9*5:줍!HyӗƲ=S'yUո,ޔnّ_m~\'I^_dI|\rl-G݋qdScKvrt囉d{4Vb)qf{`"`y6섔o6`nwX/ɬdcsPj Ӄ7V NXĝ-6Y͢nVSK2)ޓɲx}w6Y"ɗ ޤ`㽑F^?(+ㄾ@ VpNNTyf%DVn;ƲqZ1OA,5h 6w9/I KWtso֝ǁmah{!8`82⬽@T{;qЧL {1,ul6ً>'%_@jie`[`E;g}^cdbs#GP93)Ѳ鹥C$ v2`hNO0Ƶ-ї2`jm}ZlJ tҔ{t?CD8Qd-dpC0?plu-jZ:b[Cߑ/ N{l_"!jmy+zYrRn:IQʹG5;ŹLQb5*.4MN&Ee3S )ֿ_z9ˎl.((( p:Kw<n`Jb ,wxEIpDŤDd@]7#[S{b] !J 2p'<ϞnSع "V4vaq1`0d c# 08}"$.QP"J` $ @Jz1bFð)D+ߧܓ|%8\P;'Α VxF 0,+-K4œED>Tt@E?yGOTP;:;~R*ՕqHbWf$ՕI>{㔕W>Ƣ7.lXՓUw蔰<{BWf>¢*A:DNZf0G#CY vDDIҿ#^dhqEeq5ӓW"Ua<ε|1$ (vrHQFLI&orGx(7uLt(׹~<{fBU'2_T5x5qQ+7_s "wi"]-J|eJTw|Nw YN{#Ƨ'y*fN}O_b<k%5*z &GV݆D«0 H6 d5ƳlOni.¯cjpXThNhmj sR!rŴ\PM5ثcI=ju_ݩ&ba7|?Sz$#ޛ_y!TU{#[^ 1嗩d6-yβG?IG:\TUg4_&ʹӸVA;k}1|D׉fVʗ#U0Fz\V'5LXe Wċ&"#T.ujwmPPPPPPPPPPPPXqfJFn92s#JoC+Ӊ@L&+hXSBiSR:b=) z]Sì`-F2#V Q=U2U4թ.Lr-ǧaEzR;񳕁4-*,*kjUT1W@DQb"4r*F]T׸r E9a:m~ty_)502c;{U]h; !eM&ߌPic{?,)+W >J1wU tFǖ1.xhUcmz1.%8a䑜1yt7+!зHHH$TǸ{mhb-C&/fWN< bD_g;3$D3*^ۈ(~ZebDpzi$OOwH}~Q}Չ`ɂ? kbA3^m^&%HYtuS\c?_\ԝ d}g.gsEiU1 V 5HrE]#Džp<[j?1Ӱѓ1=[<$";Kf2caSWSE%}ȰJ\c*1q54D$L.,p1Ut_MrbX%X.s̻*-?a/ąp<j\M-c5l p~*({*y8k j$$Qi\=+Nz Loj-r|#$J"LJ{|$I/AZ\Z(9X4nحC9сloxɁj8lQej&j@r.M V NUѯO2!2,Sd# O y^NYd.2ѭg ytt07$d*p%Ʉ# 0OydD<"7q Y^Nl런 ɹ7d TGa 7ǜKg O<Rp,2BP̂'VY^VYi2 .E\d?=wfK)oUPPa~wnT IYgNA^]|#ra=0{uH1cʬFҨ# va%!iWGY IlC\Pf3Jbq>C<$Omn~ u?xH 2e>@ TeAzXsP;lXdJ.C3>b%(sJΌ=O59;:5uXafg }Iv?]< ^favR{^@ߤ ?sVL̉O5/?8?ɳsRsR'l${~+s~I ݙIENDB`perfbook_html/img233.png0000644000175000017500000003070711672746146015322 0ustar paulmckpaulmckPNG  IHDRU0v8PLTE""$8D 6SfDDXBBff"l̙̈3''gggݦMMM*3-EUQ}wc'''D33UqUU3U@@ fMM"33wZZHoUUZww~tttZZZ ff@@@ϛ?awss444fuݪD"tRNS@f IDATx} cHD^n1֍jK q]6Gshy 03 3BD&W"~/pA Yxpsk9y=p~p?7?( ST"Gޝ) ;/Avs}t)YyӲ&d})o9N*(1Ә|j)^oN q^^؛.. COtm֘E ,Ϯ9a^x8ݍyFdÛc>"B7k=ԠY0ZA<8чH^ҽme~KFGd?ߪ]2p\M,2ϭ1ؖҵE/sٲNu9Xj+@+ւ4l].q1Kzy,E8lXNyaz7or<1!bu굛; ˙J-ozs7#7Q]T$\mJ^݇Zvwi>Pw'@}qrru+&E7rP=*P=Z H[VެA'm+y<)y}vXᐑ9RJ390F2_֮ҼIW9Njyf ky'^]{wZ<7ոn7i|` r\W1 SCZNV>w;ia<Bp0q(Lkgs R05)%tT R M39~`g֋]n)kvgFqOj5>bݝήkd{Hw uk[Q[G)w+f3s6nN5橰62n2[zd>lX$+_ӵ*̞!@ٌ^.qgK/<lm`fgI)aYaqJMʛ%T.[%̦UZZ*s\7PGAZ;y9eYjz"i5mZ.i5OOgU@錌tvx;;XN_U.5*{ى_V.^=mʹՒYҭ}2f5)V<49Fy|V{ȶjV]˟dX-UUz brWf,'.Ogi<\OfpD_g[-@ E~P*po_rw|jQ pcvOSiVYT@[5|o|f;0K:a^ڣ|u_EuMzko5?sh0,pz6@r,5_VqQn,DT)ɦ^O*|:ynD,Fq$9$+5z#W O|ѯu @1xO\"sc#"G{ozеV ޒçn#eU:77\ՊvAcKժMV#kU0VʛW)AHvRdchs#zTan&ճtZ`<,!j!@N#dx+ MKX dup@ Axñk-EC 7Dkǡ_zCvGuxWGr$R؎<&I nW{H }󱅉j-`p7ѥ%a@`s}h`dHk"\;gQ`+lmHI5 8{ ߹y/x'݃-p}pW&u3\o lgΐGxw8uD#k.5ۻc\7af]\p8%`ɖ{-\/'r= j{}.Q?̴*~GG))u 09,wONw0evLY3r!σOF,IFF kֺԶe\J"DW"l5GMe\k75 xH e.rm.4pBHຒ&[^՞_זJwX"q骄(.SL˷^L^]%OůpB}Sj@86rY{}uzWS!>O|R8D{-Е;^$zcFNn|N|e6 Hzpq+ ٦^/Jfsq"SRD)k-Zn+D>[AV{!Ň9Oxua ߧ?^\zEs tnv G\2Mioŵu;%K&MVk1)?2ce[c{ˀ-[Aމ2Iqkе1*#b$e0z&q//< zA٦k$G#TID?|~~.LbM8&nɕh\"y\035G|[@>+x O*a#W4Jm/nymaqŞe;k61%W9 ezWXCWFw&}xTjs-~,f56/'<++[cG@3i\š1=PkfЂQdן;`\ L|~WO`f*^CnO:[:G"myOU:4)SUᣒ@#mC R}:nS]=F9'YQL ޝ4:һǸۉd;2A"]T\驋̣IUD΢)sSU4*htU;NOuxKR]yLn4'C4:74ũ.ȧGLav3JFa ;<97Оj4C,Ueנryꁤ:U6*;?<zX)tuYq$O/5TuT_[-RMtn.0+@gt xοĬB*$PO,0}_$Tpag{ 0>Y]34Rb-IU z6c7zBhH7J '/ͨURs_w"nBlttvS@+NݒfPvQ%z;A$V3&%4j @mj2j*6Q=dyZ^Q-?k)Tۈ #j*4*e=L*sM[*٠2UVMIZ^[UkjbHţyT6GBPUS ,2#@wA53[C}T#Bue}LjXۘ)nraU*Z?;Y)Ai&w ʥK=9E3fT4UO[ Ҭ!:lGKqB0#k^&jɮy^lfIYsaF6Uy(U~ 7I/mz Y?x{-Ꝣz?ZGF\I'\0o՛7\AIioo<[\ ^vիO Q=6̧Aˀ D$շr*ݱhk݀2\6#ozKDKԫ=RPRm-[tYZ,z`7Bg2P@mvla+ũnk[d˔QKAys-_Z6L.\Vͣ2 Auq^ZCYm]jEQ-4 P崚Z MT??ټVj\~F?F'00|Tk@' F?F0g#*ȧb3 9ΐ\KkN6THj7'xm3!6%&U#dIK0 (1۪%4>Di%\ !`*8 Lwi7,KfS͉U8~RKZ1үm0.`?<bTT嫊e0Ŵt{G2A!U{H IrFE7q %~_p=$p R E#@\i;RʵbA>&jXaUxvDt>KW~'S XV/7T ~TH9ኋ7:&ϔR\T%Ub8bK}xGT/7ea7K0\OH6'^@0aZf^Ȣf]<:r`d4 V~T˞:.8CRK kQC3sQw῵i59m1\n.-K5s\wk>E[%]kƌRrU +4J7V TH<3>FTuO5`)0S*J-sڲebF1)Uؔ:/a0mުTPΐE:&%-+ipm]NQ6Qѣ;҅!]%&УmD.R^-BACGcjZ *|F^>EбJqv ]9l`[Ra,\zQ*s]Gbaȧ IuLOyx`ywPNwXU{zCmi\Krn-<)X݈:t Ur|J<U WkZ""簒L4vhN. pp5z$"GˇFr%G݄ȱ$XTzjbU;lHJٟRsSX-8˻gtUVNa9$UUL]YKGT`i"Hs3F ,PpIa؅?a/Wx\oo {KG}Шc7W萾J!tԋFd=/ܑ>FdeMwuA+[C(d ܅lUn^6of`*/ml5sh6Sh@XX Mc9DT EmI ;d]dcԜà lB0Ղ` q}.#Z{,[pB [/t 3ey8֨+BTt2ѣGGKw %WUR-@ _UU=ztU!yJ褪 K?n4-wJ߿?Si|o;?ьI?쾒1tn~{=wy+{p&I[qyIDATO>3&Z{ x_hWrUak/+(,NXg@ *oTY{\?_ރ۪?{z%?PV~Ar<*­@z+u=-ä_IprE~r1^p_W/Ya%qkJb6:_m=zUUv`jUU^UUU8r}U WW9[֫åfr9=AKSFqpq]8Y:;w@mwt3W5 `}zG2Pu'2W_Vʱ-*!vN=yݫ ]s(\ɡ֫ej=UUA u)w{W(56>^K"g^acd{ߧ<ߩ'rإ^vUݣvi{Xľ+LA?Q)_2 f3.;Nf^dUQ o+MR)CʳKy`zЫ@LW"Rå?ӫ {'2nNѫu0UUWU^U zUU0,TѣYތ6YIضxOФWNXQخhGjTm*ϳS}tޠ[S&nIhؑ4mͫ]IдmДGESJ. &I%1jLiJPĪ!U۩)A &TmSj5%Q]ДP/OvER*T[jcLiJU)DUeM ׯj5%T=U JT:BvdL -3UUTi/7y^d3UkjN|fRޫ~r[)51M#:NU}]."Lӈ^7;m6G^iD[5w A|ՏmYՀi Lm+zR}ޫ~Yi|iD3{V*v@յ{섻jJ܉ïf'ʴTR_FcۃZj&Jќ\n0]'4:U)ܵX.!B ;1}؟z'N]]u:5Ͳr0M gETa؉DUa'A܉װ{rn3L(i L DTiX.5*CpE|]kV]gITs$\B|8V'YD`c 9f4_D}=tGkV2.@usM0ԫZk^r\+^^4~uUmk-*j,qKF5UoSUݨj64*ڸ`JU*TU隵VQ4^vAʪ݀}UU. ˪괪5Yռxъ[uUѣ*{HF @TXRWuN7UUz Ț*7&HB9z$ V)c-?_UV]nvگjѫ*!U;puH)UEWz]St6ltO.`ZC@cmŒ3v߀HfG5.U [s C!͹a2u`[`Pf)S~~k1t!(:֜@I-PXDT] CcI^{-X.ނgYw3ܻ nG-j+8.źP!PG 0Ƹ`-A$3r) UiOwa<ޥ^U% qUo_ͻjwc=}@(ZZW-ZdR۫M;baUmYȵ,3Zx\Yӝ ۥ Yw̶y,6] Yއj(T\XUUX:/368Z#f$FikduFU#{UӁ|J9+7zܦP"Yc^y=ߟ')7')ST&`Sk zKr)W5:^U(}87TQU*ƫ6rz|f5M֬XQ7oWxp>]]}1!XYUn S ]WK'L9EXqYWbe"ꍼkyxoۨi7@ z+α֎a]U6e'O~+,zZ(vVKaV5Ul5z'Em.WUC5}r[Cޙqk+wB~J$bۧjkj/BE_ֻ"U6PQ ]G(hVq'XI]PU=aQr5B 4ꝨaPV@ӵn^UQ*uUoe uUoeӵ}U-kBUqmQPTmR5淺eD[hUG5j;tͫ3" (38矘ܶmUۀN3<|4O ÏV6 oY,GCfMUJ끫ۊ x=-Wޜ>W{/HOW%%*jP P%E$'0hd2ɓ04KmUT] ]_`mT [>.a.h6m 7vKM)/σY9h1 ֢jHU5% #*DT .9\8ᦸc?{'Tu*9XDc vHU/IJ@6 dv +VT$/i0GUjTD!%tFk3%WCי18ښ mN064a 3LIU/rK t ݪ] }@˪u'#5d!U(nN+kY2&#^f%U^6pF7I-;o+HIGpܯ2涩A1U^|6ɍ{'8.?x5#s=y[&27`KQ]q!<5U?ZwH_a .}?g*NG|7%}?+XVRBѯ `MՑM} i!3S^K7BG&T] @pi'~=0s&f)$URKJywGr|`MՇTh~8hj9%ajFDzӕ]%b^ ( (jŶ<ӂs:X=R8#ѨՑHqu)kUY澋Q0|E0rEQ]=p֌K, OJ[y 6yaUAjkLjDNPg=5J;jnz5@s:XmaÇѨUUGu('aa,Z@]R;UU^U'Q >w }SBV^V%s{I*>T(B/k=zK*A/*Aj=z*A/ XJڣG#"mh;½Æ &wV :RUu2t55317yD0tæXbqYlБ abn9W5$W)}LW"m-Gw!BGzY{sԑ9(@D\Up8A4ZjT#9BG<@GPV1sDU]0*'9Prh/(_E46D#fӎ24Z Xߖ3Gx2r OH6d5䖿}%Fb!Fr! a`px!3 [6N]{ah6sq9(t%9|PoJvu`| -ۂ]DhQ1V<A,#F9B1:%s0qT>x)"lp܋+l~ vkSCtR:JV#3`;nycުUIENDB`perfbook_html/node386.html0000644000175000017500000001504611672746163015662 0ustar paulmckpaulmck D.3.6.2 Noting End of Old Grace Periods


D.3.6.2 Noting End of Old Grace Periods

Figure: Noting End of Old Grace Periods
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_process_gp_e...
...ed_snap;
18 }
19 local_irq_restore(flags);
20 }\end{verbatim}
}\end{figure}

Figure: RCU Callback List
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/AdvanceRCUCallbacks}}

Figure [*] shows rcu_process_gp_end(), which is invoked when a CPU suspects that a grace period might have ended (possibly because the CPU in question in fact ended the grace period). If a grace period really has ended, then this function advances the current CPU's RCU callbacks, which are managed as a singly linked list with multiple tail pointers, as shown in Figure [*]. This multiple tail pointer layout, spearheaded by Lai Jiangshan, simplifies list handling [Jia08]. In this figure, the blue box represents one CPU's rcu_data structure, with the six white boxes at the bottom of the diagram representing a list of six RCU callbacks (rcu_head structures). In this list, the first three callbacks have passed through their grace period and are thus waiting to be invoked, the fourth callback (the first on the second line) is waiting for the current grace period to complete, and the last two are waiting for the next grace period. The last two tail pointers reference the last element, so that the final sublist, which would comprise callbacks that had not yet been associated with a specific grace period, is empty.

Lines 8 and 19 of Figure [*] suppress and re-enable interrupts, respectively. Line 9 picks up a snapshot of the rcu_state structure's ->completed field, storing it in the local variable completed_snap. Line 10 checks to see if the current CPU is not yet aware of the end of a grace period, and if it is not aware, lines 11-16 advance this CPU's RCU callbacks by manipulating the tail pointers. Line 17 then records the most recently completed grace period number in this CPU's rcu_data structure in the ->completed field.

Paul E. McKenney 2011-12-16
perfbook_html/node115.html0000644000175000017500000000432411672746162015644 0ustar paulmckpaulmck 10.1 Barriers


10.1 Barriers

HPC-style barriers.



Paul E. McKenney 2011-12-16
perfbook_html/node37.html0000644000175000017500000001301211672746161015560 0ustar paulmckpaulmck 4.3.2 Novel Materials and Processes


4.3.2 Novel Materials and Processes

Stephen Hawking is said to have claimed that semiconductor manufacturers have but two fundamental problems: (1) the finite speed of light and (2) the atomic nature of matter [Gar07]. It is possible that semiconductor manufacturers are approaching these limits, but there are nevertheless a few avenues of research and development focused on working around these fundamental limits.

One workaround for the atomic nature of matter are so-called ``high-K dielectric'' materials, which allow larger devices to mimic the electrical properties of infeasibly small devices. These materials pose some severe fabrication challenges, but nevertheless may help push the frontiers out a bit farther. Another more-exotic workaround stores multiple bits in a single electron, relying on the fact that a given electron can exist at a number of energy levels. It remains to be seen if this particular approach can be made to work reliably in production semiconductor devices.

Another proposed workaround is the ``quantum dot'' approach that allows much smaller device sizes, but which is still in the research stage.

Although the speed of light would be a hard limit, the fact is that semiconductor devices are limited by the speed of electrons rather than that of light, given that electrons in semiconductor materials move at between 3% and 30% of the speed of light in a vacuum. The use of copper connections on silicon devices is one way to increase the speed of electrons, and it is quite possible that additional advances will push closer still to the actual speed of light. In addition, there have been some experiments with tiny optical fibers as interconnects within and between chips, based on the fact that the speed of light in glass is more than 60% of the speed of light in a vacuum. One obstacle to such optical fibers is the inefficiency conversion between electricity and light and vice versa, resulting in both power-consumption and heat-dissipation problems.

That said, absent some fundamental advances in the field of physics, any exponential increases in the speed of data flow will be sharply limited by the actual speed of light in a vacuum.

Paul E. McKenney 2011-12-16
perfbook_html/node387.html0000644000175000017500000002342011672746163015656 0ustar paulmckpaulmck D.3.6.3 Starting a Grace Period


D.3.6.3 Starting a Grace Period

Figure: Starting a Grace Period
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_start_gp(str...
...n_unlock_irqrestore(&rsp->onofflock, flags);
47 }\end{verbatim}
}\end{figure}

Figure [*] shows rcu_start_gp(), which starts a new grace period, also releasing the root rcu_node structure's lock, which must be acquired by the caller.

Line 4 is annotation for the sparse utility, indicating that rcu_start_gp() releases the root rcu_node structure's lock. Local variable rdp references the running CPU's rcu_data structure, rnp references the root rcu_node structure, and rnp_cur and rnp_end are used as cursors in traversing the rcu_node hierarchy.

Line 10 invokes cpu_needs_another_gp() to see if this CPU really needs another grace period to be started, and if not, line 11 releases the root rcu_node structure's lock and line 12 returns. This code path can be executed due to multiple CPUs concurrently attempting to start a grace period. In this case, the winner will start the grace period, and the losers will exit out via this code path.

Otherwise, line 14 increments the specified rcu_state structure's ->gpnum field, officially marking the start of a new grace period.

Quick Quiz D.43: But there has been no initialization yet at line 15 of Figure [*]! What happens if a CPU notices the new grace period and immediately attempts to report a quiescent state? Won't it get confused? End Quick Quiz

Line 15 sets the ->signaled field to RCU_GP_INIT in order to prevent any other CPU from attempting to force an end to the new grace period before its initialization completes. Lines 16-18 schedule the next attempt to force an end to the new grace period, first in terms of jiffies and second in terms of the number of calls to rcu_pending. Of course, if the grace period ends naturally before that time, there will be no need to attempt to force it. Line 20 invokes record_gp_stall_check_time() to schedule a longer-term progress check--if the grace period extends beyond this time, it should be considered to be an error. Line 22 invokes note_new_gpnum() in order to initialize this CPU's rcu_data structure to account for the new grace period.

Lines 23-26 advance all of this CPU's callbacks so that they will be eligible to be invoked at the end of this new grace period. This represents an acceleration of callbacks, as other CPUs would only be able to move the RCU_NEXT_READY_TAIL batch to be serviced by the current grace period; the RCU_NEXT_TAIL would instead need to be advanced to the RCU_NEXT_READY_TAIL batch. The reason that this CPU can accelerate the RCU_NEXT_TAIL batch is that it knows exactly when this new grace period started. In contrast, other CPUs would be unable to correctly resolve the race between the start of a new grace period and the arrival of a new RCU callback.

Line 27 checks to see if there is but one rcu_node structure in the hierarchy, and if so, line 28 sets the ->qsmask bits corresponding to all online CPUs, in other words, corresponding to those CPUs that must pass through a quiescent state for the new grace period to end. Line 29 releases the root rcu_node structure's lock and line 30 returns. In this case, gcc's dead-code elimination is expected to dispense with lines 32-46.

Otherwise, the rcu_node hierarchy has multiple structures, requiring a more involved initialization scheme. Line 32 releases the root rcu_node structure's lock, but keeps interrupts disabled, and then line 33 acquires the specified rcu_state structure's ->onofflock, preventing any concurrent CPU-hotplug operations from manipulating RCU-specific state.

Line 34 sets the rnp_end local variable to reference the first leaf rcu_node structure, which also happens to be the rcu_node structure immediately following the last non-leaf rcu_node structure in the ->node array. Line 35 sets the rnp_cur local variable to reference the root rcu_node structure, which also happens to be first such structure in the ->node array. Lines 36 and 37 then traverse all of the non-leaf rcu_node structures, setting the bits corresponding to lower-level rcu_node structures that have CPUs that must pass through quiescent states in order for the new grace period to end.

Quick Quiz D.44: Hey! Shouldn't we hold the non-leaf rcu_node structures' locks when munging their state in line 37 of Figure [*]??? End Quick Quiz

Line 38 sets local variable rnp_end to one past the last leaf rcu_node structure, and line 39 sets local variable rnp_cur to the first leaf rcu_node structure, so that the loop spanning lines 40-44 traverses all leaves of the rcu_node hierarchy. During each pass through this loop, line 41 acquires the current leaf rcu_node structure's lock, line 42 sets the bits corresponding to online CPUs (each of which must pass through a quiescent state before the new grace period can end), and line 43 releases the lock.

Quick Quiz D.45: Why can't we merge the loop spanning lines 36-37 with the loop spanning lines 40-44 in Figure [*]? End Quick Quiz

Line 45 then sets the specified rcu_state structure's ->signaled field to permit forcing of quiescent states, and line 46 releases the ->onofflock to permit CPU-hotplug operations to manipulate RCU state.

Paul E. McKenney 2011-12-16
perfbook_html/img130.png0000644000175000017500000001116411672746015015305 0ustar paulmckpaulmckPNG  IHDRCj30PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fIDATx]m$Y~oc{{"PNC l@9"XI{grlp0֡rxHـ%%(H8f@%Vs($}tUWWuWNLwO=oUxYD!b:ID0Fl)c CP1I_F-@`)&)Ė-bg%}F LcM6>C#w$2 TZY3H;i&エaW1ScXnb 6LQ0-Qdp̬JrF4rvu]-XfEŋ9;K ,kX"Ћ>@1saHYM76, .ׇ?|& <*<ˑdjYGfq`ձ0QL#Hʭ9Cw[Xs a8[y]ͨ^$&:D+T\$07s2[[[Uy(mz,N VO @Ŗ~΄̚L}y*cW #rVJ:1$c):erǙZ./_XjMoYnTYĦTڹ+Y6yc%o~teUe?þh9 :ް2WRYwV,ĝlZULɹHɊcU*)[>'-y:&8Ǝ2K4oٷyXnJBR9eKWݲP^~GiohҰ@yr&&-^ӿ\NWMi:^33q~a:z]i{9/E;5yq#eEs3J m]6Oj "c쉊RhQИlXg6D$cp,fsNa5O;(kjx.wOnk$mgf1i$Maa{g,ref0X9t@rʹ,qO[1"H) ҚX{⢛ 2+A0Y?q=sXQfpլl cUi0cg'fracN&.j?Uqp:mw7ӵwwo@sFe -e#O|jݔɢ&LU]aJI' Jq c=2/q#[(˅5)Ӆ{M]YŢizRsgukV:k3xvuR7.L=%QcEQ=w33 E9r zq5ُJicn"a<ϮHg4e<GЧ~D/N[⌏n[Fkxp q# zU&7t\_-cu&|7-:)f7}֛˅<, b,JԞ+M kJ"cSh*?1 sj6 ;y3W hGɻLAy.c\a3,Tr `6(VXÄvMq:{p39;O6{S91>_G=>3+ƿmww7iZuj8Դ11]kh݂NܫG~zx#Thd('FeHc|qp4>r,3L~:BA[ԞR= O,}7z] a,K˭(D-<=RS`yYq !wDnCc᝭`ŚѶ QdL$X=Zu[6 _J]MeDbE pA?qi>ŌDc;D$ C)cEջߐNLܪurt}D_/B2kHr&L2ut?*q`I.%/< %BCD^axs Kw,$+OxYWt,h pK&K0-1(O* JY2U7IR֨bv^]t#f508|)V4}c ?4P~|b쮁@Qyqb:7[("Q8>7WC̙ܵ eS G/L¼ Kty ;)h !sFSo_؃lX[ɔ)6_/r$+1KrWc (b%tbkQBgCEG4 M12eUl7!ßW@\{M)2?6Hԗo9]l#7 p;:_yblolՖSS "hTcOXut~*ӯYfi?/p?9,o@V ԥI }Ū؆440JT)ӃPCëx[+T>iM$ #` ϏO}oX{nszX2*!Z*٢ƀY \Bc;"/6k.$g1vD:6YݶޒukF۾DLbÏv(%q/*x9C'n5n7ƶ:e5cq[8 7CדƷ zbwn[.l-vt`m1[Ǜ⽓%/[]-ݥSͩ' w1[\ؖi;gCuNiK5\Ko<.oc3; _m-t݄%IxI\ѱs{:A3:u*8gchwAsíTAWdis7-^-~Ks MK#6BkBՁ'sf-9_MLI/8=p=;3^*3%/1$v\qx6#XkJ Dx]xϋ\'k;bOk;$ot1?<|>IENDB`perfbook_html/node472.html0000644000175000017500000000713611672746163015657 0ustar paulmckpaulmck F.12 Chapter 

F.12 Chapter [*]

Quick Quiz [*].1: 
What SMP coding errors can you see in these examples? See time.c for full code.
 
Answer:
  1. Missing barrier() or volatile on tight loops.
  2. Missing Memory barriers on update side.
  3. Lack of synchronization between producer and consumer.

Quick Quiz [*].2: 
How could there be such a large gap between successive consumer reads? See timelocked.c for full code.
 
Answer:

  1. The consumer might be preempted for long time periods.
  2. A long-running interrupt might delay the consumer.
  3. The producer might also be running on a faster CPU than is the consumer (for example, one of the CPUs might have had to decrease its clock frequency due to heat-dissipation or power-consumption constraints).



Paul E. McKenney 2011-12-16
perfbook_html/node216.html0000644000175000017500000000622411672746162015647 0ustar paulmckpaulmck 14.2.10.1.1 Write Memory Barriers

14.2.10.1.1 Write Memory Barriers

A write memory barrier gives a guarantee that all the STORE operations specified before the barrier will appear to happen before all the STORE operations specified after the barrier with respect to the other components of the system.

A write barrier is a partial ordering on stores only; it is not required to have any effect on loads.

A CPU can be viewed as committing a sequence of store operations to the memory system as time progresses. All stores before a write barrier will occur in the sequence before all the stores after the write barrier.

$\dagger$ Note that write barriers should normally be paired with read or data dependency barriers; see the "SMP barrier pairing" subsection.



Paul E. McKenney 2011-12-16
perfbook_html/images.bbl0000644000175000017500000011642411672745743015541 0ustar paulmckpaulmck\newcommand{\etalchar}[1]{$^{#1}$} \begin{thebibliography}{SATG{\etalchar{+}}09} \bibitem[aCB08]{SETIatHOME2008} University at~California~Berkeley. \newblock {SETI}@{HOME}. \newblock Available: \url{http://setiathome.berkeley.edu/} [Viewed January 31, 2008], December 2008. \bibitem[ACMS03]{Arcangeli03} Andrea Arcangeli, Mingming Cao, Paul~E. McKenney, and Dipankar Sarma. \newblock Using read-copy update techniques for {System V IPC} in the {Linux} 2.5 kernel. \newblock In {\em Proceedings of the 2003 USENIX Annual Technical Conference (FREENIX Track)}, pages 297--310. USENIX Association, June 2003. \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf} [Viewed November 21, 2007]. \bibitem[Adv02]{AMDOpteron02} Advanced Micro Devices. \newblock {\em AMD x86-64 Architecture Programmer's Manual Volumes 1-5}, 2002. \bibitem[Adv07]{AMDOpteron:2:2007} Advanced Micro Devices. \newblock {\em AMD x86-64 Architecture Programmer's Manual Volume 2: System Programming}, 2007. \bibitem[Ale79]{Alexander79} Christopher Alexander. \newblock {\em The Timeless Way of Building}. \newblock Oxford University Press, New York, 1979. \bibitem[Amd67]{GeneAmdahl1967AmdahlsLaw} Gene Amdahl. \newblock Validity of the single processor approach to achieving large-scale computing capabilities. \newblock In {\em AFIPS Conference Proceedings}, pages 483--485, Washington, DC, USA, 1967. IEEE Computer Society. \bibitem[ARM10]{ARMv7A:2010} ARM Limited. \newblock {\em ARM Architecture Reference Manual: ARMv7-A and ARMv7-R Edition}, 2010. \bibitem[ATS09]{Ali-Reza-Adl-Tabatabai2009CppTM} Ali-Reza Adl-Tabatabai and Tatiana Shpeisman. \newblock Draft specification of transactional language constructs for c++. \newblock http://research.sun.com/scalable/pubs/C++-transactional-constructs-1.0.pdf, August 2009. \bibitem[BA01]{Bonwick01slab} Jeff Bonwick and Jonathan Adams. \newblock Magazines and vmem: Extending the slab allocator to many {CPUs} and arbitrary resources. \newblock In {\em {USENIX} Annual Technical Conference, General Track 2001}, pages 15--33, 2001. \bibitem[BC05]{BovetCesati2005} Daniel Bovet and Marco Cesati. \newblock {\em Understanding the Linux Kernel}. \newblock O'Reilly Media, Inc., third edition, 2005. \bibitem[BHS07]{BuschmannHenneySchmidt2007v4Textbook} Frank Buschmann, Kevlin Henney, and Douglas~C. Schmidt. \newblock {\em Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing}. \newblock Wiley, Chichester, West Sussex, England, 2007. \bibitem[BK85]{Beck85} Bob Beck and Bob Kasten. \newblock {VLSI} assist in building a multiprocessor {UNIX} system. \newblock In {\em USENIX Conference Proceedings}, pages 255--275, Portland, OR, June 1985. USENIX Association. \bibitem[BLM05]{Blundell2005DebunkTM} C.~Blundell, E.~C. Lewis, and M.~Martin. \newblock Deconstructing transactional semantics: The subtleties of atomicity. \newblock In {\em Annual Workshop on Duplicating, Deconstructing, and Debunking (WDDD)}, June 2005. \newblock Available: \url{http://www.cis.upenn.edu/acg/papers/wddd05_atomic_semantics.pdf} [Viewed June 4, 2009]. \bibitem[BLM06]{Blundell2006TMdeadlock} C.~Blundell, E.~C. Lewis, and M.~Martin. \newblock Subtleties of transactional memory and atomicity semantics. \newblock {\em Computer Architecture Letters}, 5(2), 2006. \newblock Available: \url{http://www.cis.upenn.edu/acg/papers/cal06_atomic_semantics.pdf} [Viewed June 4, 2009]. \bibitem[Boe09]{HansJBoehm2009HOTPAR} Hans-J. Boehm. \newblock Transactional memory should be an implementation technique, not a programming interface. \newblock In {\em HOTPAR 2009}, page~6, Berkeley, CA, USA, March 2009. \newblock Available: \url{http://www.usenix.org/event/hotpar09/tech/full_papers/boehm/boehm.pdf} [Viewed May 24, 2009]. \bibitem[But97]{Butenhof1997pthreads} David Butenhof. \newblock {\em Programming with {POSIX} Threads}. \newblock Addison-Wesley, Boston, MA, USA, 1997. \bibitem[Cor06]{JonathanCorbet2006lockdep} Jonathan Corbet. \newblock The kernel lock validator. \newblock Available: \url{http://lwn.net/Articles/185666/} [Viewed: March 26, 2010], May 2006. \bibitem[Cor08]{CorbetLWN} Jonathan Corbet. \newblock Linux weekly news. \newblock Available: \url{http://lwn.net/} [Viewed November 26, 2008], November 2008. \bibitem[CRKH05]{CorbetRubiniKroahHartman} Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman. \newblock {\em Linux Device Drivers}. \newblock O'Reilly Media, Inc., third edition, 2005. \bibitem[CSG99]{DavidECuller1999} David~E. Culler, Jaswinder~Pal Singh, and Anoop Gupta. \newblock {\em Parallel Computer Architecture: a Hardware/Software Approach}. \newblock Morgan Kaufman, 1999. \bibitem[DCW{\etalchar{+}}11]{LukeDalessandro:2011:ASPLOS:HybridNOrecSTM:deque} Luke Dalessandro, Francois Carouge, Sean White, Yossi Lev, Mark Moir, Michael~L. Scott, and Michael~F. Spear. \newblock Hybrid norec: A case study in the effectiveness of best effort hardware transactional memory. \newblock In {\em Proceedings of the 16th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS)}, ASPLOS '11, pages ???--???, New York, NY, USA, 2011. ACM. \bibitem[Des09]{MathieuDesnoyers2009URCU} Mathieu Desnoyers. \newblock [{RFC} git tree] userspace {RCU} (urcu) for {Linux}. \newblock Available: \url{http://lkml.org/lkml/2009/2/5/572} \url{http://lttng.org/urcu} [Viewed February 20, 2009], February 2009. \bibitem[Dij71]{Dijkstra1971HOoSP} Edsger~W. Dijkstra. \newblock Hierarchical ordering of sequential processes. \newblock {\em Acta Informatica}, 1(2):115--138, 1971. \newblock Available: \url{http://www.cs.utexas.edu/users/EWD/ewd03xx/EWD310.PDF} [Viewed January 13, 2008]. \bibitem[DLM{\etalchar{+}}10]{DavidDice:2010:SCA:HTM:deque} Dave Dice, Yossi Lev, Virendra~J. Marathe, Mark Moir, Dan Nussbaum, and Marek Oleszewski. \newblock Simplifying concurrent algorithms by exploiting hardware transactional memory. \newblock In {\em Proceedings of the 22nd ACM symposium on Parallelism in algorithms and architectures}, SPAA '10, pages 325--334, New York, NY, USA, 2010. ACM. \bibitem[DLMN09]{DaveDice2009ASPLOSRockHTM} Dave Dice, Yossi Lev, Mark Moir, and Dan Nussbaum. \newblock Early experience with a commericial hardware transactional memory implementation. \newblock In {\em Fourteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '09)}, pages 157--168, Washington, DC, USA, March 2009. \newblock Available: \url{http://research.sun.com/scalable/pubs/ASPLOS2009-RockHTM.pdf} [Viewed February 4, 2009]. \bibitem[Dov90]{Dove90} Ken~F. Dove. \newblock A high capacity {TCP/IP} in parallel {STREAMS}. \newblock In {\em UKUUG Conference Proceedings}, London, June 1990. \bibitem[DSS06]{DaveDice2006DISC} Dave Dice, Ori Shalev, and Nir Shavit. \newblock Transactional locking {II}. \newblock In {\em Proc. International Symposium on Distributed Computing}. Springer Verlag, 2006. \newblock Available: \url{http://www.springerlink.com/content/5688h5q0w72r54x0/} [Viewed March 10, 2008]. \bibitem[EGCD03]{ElGhazawi2003UPC} T.~A. El-Ghazawi, W.~W. Carlson, and J.~M. Draper. \newblock {UPC} language specifications v1.1. \newblock Available: \url{http://upc.gwu.edu} [Viewed September 19, 2008], May 2003. \bibitem[Eng68]{DouglasEngelbart1968} Douglas Engelbart. \newblock The demo. \newblock Available: \url{http://video.google.com/videoplay?docid=-8734787622017763097} [Viewed November 28, 2008], December 1968. \bibitem[ENS05]{RyanEccles2005HPCSNovice} Ryan Eccles, Blair Nonneck, and Deborah~A. Stacey. \newblock Exploring parallel programming knowledge in the novice. \newblock In {\em HPCS '05: Proceedings of the 19th International Symposium on High Performance Computing Systems and Applications}, pages 97--102, Washington, DC, USA, 2005. IEEE Computer Society. \bibitem[ES05]{RyanEccles2006HPCSNoviceNeeds} Ryan Eccles and Deborah~A. Stacey. \newblock Understanding the parallel programmer. \newblock In {\em HPCS '05: Proceedings of the 19th International Symposium on High Performance Computing Systems and Applications}, pages 156--160, Washington, DC, USA, 2005. IEEE Computer Society. \bibitem[Gar90]{Garg90} Arun Garg. \newblock Parallel {STREAMS}: a multi-processor implementation. \newblock In {\em USENIX Conference Proceedings}, pages 163--176, Berkeley CA, February 1990. USENIX Association. \bibitem[Gar07]{BryanGardiner2007} Bryan Gardiner. \newblock Idf: Gordon moore predicts end of moore's law (again). \newblock Available: \url{http://blog.wired.com/business/2007/09/idf-gordon-mo-1.html} [Viewed: November 28, 2008], September 2007. \bibitem[GC96]{Cheriton96a} Michael Greenwald and David~R. Cheriton. \newblock The synergy between non-blocking synchronization and operating system structure. \newblock In {\em Proceedings of the Second Symposium on Operating Systems Design and Implementation}, pages 123--136, Seattle, WA, October 1996. USENIX Association. \bibitem[Gha95]{Gharachorloo95} Kourosh Gharachorloo. \newblock Memory consistency models for shared-memory multiprocessors. \newblock Technical Report CSL-TR-95-685, Computer Systems Laboratory, Departments of Electrical Engineering and Computer Science, Stanford University, Stanford, CA, December 1995. \newblock Available: \url{http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-9.pdf} [Viewed: October 11, 2004]. \bibitem[GHJV95]{GOF95} Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. \newblock {\em Design Patterns: Elements of Reusable Object-Oriented Software}. \newblock Addison-Wesley, 1995. \bibitem[GKAS99]{Gamsa99} Ben Gamsa, Orran Krieger, Jonathan Appavoo, and Michael Stumm. \newblock Tornado: Maximizing locality and concurrency in a shared memory multiprocessor operating system. \newblock In {\em {Proceedings of the 3\textsuperscript{rd} Symposium on Operating System Design and Implementation}}, pages 87--100, New Orleans, LA, February 1999. \newblock Available: \url{http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf} [Viewed August 30, 2006]. \bibitem[GMTW08]{DinakarGuniguntala2008IBMSysJ} D.~Guniguntala, P.~E. McKenney, J.~Triplett, and J.~Walpole. \newblock The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with {Linux}. \newblock {\em IBM Systems Journal}, 47(2):221--236, May 2008. \newblock Available: \url{http://www.research.ibm.com/journal/sj/472/guniguntala.pdf} [Viewed April 24, 2008]. \bibitem[GPB{\etalchar{+}}07]{Goetz2007Textbook} Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea. \newblock {\em Java: Concurrency in Practice}. \newblock Addison Wesley, Upper Saddle River, NJ, USA, 2007. \bibitem[Gra02]{JimGray2002SmokingHairyGolfBalls} Jim Gray. \newblock Super-servers: Commodity computer clusters pose a software challenge. \newblock Available: \url{http://research.microsoft.com/en-us/um/people/gray/papers/superservers(% 4t_computers).doc} [Viewed: June 23, 2004], April 2002. \bibitem[Gri00]{ScottGriffen2000} Scott Griffen. \newblock Internet pioneers: Doug englebart. \newblock Available: \url{http://www.ibiblio.org/pioneers/englebart.html} [Viewed November 28, 2008], May 2000. \bibitem[Gro01]{TheOpenGroup1997SUS} The~Open Group. \newblock Single {UNIX} specification. \newblock \url{http://www.opengroup.org/onlinepubs/007908799/index.html}, July 2001. \bibitem[Gro07]{DanGrossman2007TMGCAnalogy} Dan Grossman. \newblock The transactional memory / garbage collection analogy. \newblock In {\em {OOPSLA '07: Proceedings of the 22nd annual ACM SIGPLAN conference on Object oriented programming systems and applications}}, pages 695--706, New York, NY, USA, October 2007. ACM. \newblock Available: \url{http://www.cs.washington.edu/homes/djg/papers/analogy_oopsla07.pdf} [Viewed December 19, 2008]. \bibitem[HCS{\etalchar{+}}05]{LorinHochstein2005SC} Lorin Hochstein, Jeff Carver, Forrest Shull, Sima Asgari, and Victor Basili. \newblock Parallel programmer productivity: A case study of novice parallel programmers. \newblock In {\em SC '05: Proceedings of the 2005 ACM/IEEE conference on Supercomputing}, page~35, Washington, DC, USA, 2005. IEEE Computer Society. \bibitem[Her90]{MauriceHerlihy90a} Maurice~P. Herlihy. \newblock A methodology for implementing highly concurrent data structures. \newblock In {\em Proceedings of the 2nd ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming}, pages 197--206, March 1990. \bibitem[Her05]{MauriceHerlihy2005-TM-manifesto.pldi} Maurice Herlihy. \newblock The transactional manifesto: software engineering and non-blocking synchronization. \newblock In {\em PLDI '05: Proceedings of the 2005 ACM SIGPLAN conference on Programming language design and implementation}, pages 280--280, New York, NY, USA, 2005. ACM Press. \bibitem[HM93]{Herlihy93a} Maurice Herlihy and J.~Eliot~B. Moss. \newblock Transactional memory: Architectural support for lock-free data structures. \newblock {\em The 20\textsuperscript{th} Annual International Symposium on Computer Architecture}, pages 289--300, May 1993. \bibitem[HMB06]{ThomasEHart2006a} Thomas~E. Hart, Paul~E. McKenney, and Angela~Demke Brown. \newblock Making lockless synchronization fast: Performance implications of memory reclamation. \newblock In {\em 20\textsuperscript{th} {IEEE} International Parallel and Distributed Processing Symposium}, Rhodes, Greece, April 2006. \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/hart_ipdps06.pdf} [Viewed April 28, 2008]. \bibitem[Hol03]{Holzmann03a} Gerard~J. Holzmann. \newblock {\em The {Spin} Model Checker: Primer and Reference Manual}. \newblock Addison-Wesley, 2003. \bibitem[HP95]{Hennessy95a} John~L. Hennessy and David~A. Patterson. \newblock {\em Computer Architecture: A Quantitative Approach}. \newblock Morgan Kaufman, 1995. \bibitem[HS08]{HerlihyShavit2008Textbook} Maurice Herlihy and Nir Shavit. \newblock {\em The Art of Multiprocessor Programming}. \newblock Morgan Kaufmann, Burlington, MA, USA, 2008. \bibitem[HW92]{WilsonCHsieh92a} Wilson~C. Hsieh and William~E. Weihl. \newblock Scalable reader-writer locks for parallel systems. \newblock In {\em Proceedings of the 6\textsuperscript{th} International Parallel Processing Symposium}, pages 216--230, Beverly Hills, CA, USA, March 1992. \bibitem[{IBM}94]{PowerPC94} {IBM Microelectronics and Motorola}. \newblock {\em PowerPC Microprocessor Family: The Programming Environments}, 1994. \bibitem[Inm85]{Inman85} Jack Inman. \newblock Implementing loosely coupled functions on tightly coupled engines. \newblock In {\em USENIX Conference Proceedings}, pages 277--298, Portland, OR, June 1985. USENIX Association. \bibitem[{Int}92]{DIS9075SQL92} {International Standards Organization}. \newblock {\em Information Technology - Database Language {SQL}}. \newblock ISO, 1992. \newblock Available: \url{http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt} [Viewed September 19, 2008]. \bibitem[{Int}02a]{IntelItanium02v3} {Intel Corporation}. \newblock {\em Intel Itanium Architecture Software Developer's Manual Volume 3: Instruction Set Reference}, 2002. \bibitem[{Int}02b]{IntelItanium02v2} {Intel Corporation}. \newblock {\em Intel Itanium Architecture Software Developer's Manual Volume 3: System Architecture}, 2002. \bibitem[{Int}04a]{IntelXeonV2b-96a} {Intel Corporation}. \newblock {\em IA-32 Intel Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z}, 2004. \newblock Available: \url{ftp://download.intel.com/design/Pentium4/manuals/25366714.pdf} [Viewed: February 16, 2005]. \bibitem[{Int}04b]{IntelXeonV3-96a} {Intel Corporation}. \newblock {\em IA-32 Intel Architecture Software Developer's Manual Volume 3: System Programming Guide}, 2004. \newblock Available: \url{ftp://download.intel.com/design/Pentium4/manuals/25366814.pdf} [Viewed: February 16, 2005]. \bibitem[{Int}04c]{IBMzSeries04a} {International Business Machines Corporation}. \newblock {z/Architecture} principles of operation. \newblock Available: \url{http://publibz.boulder.ibm.com/epubs/pdf/dz9zr003.pdf} [Viewed: February 16, 2005], May 2004. \bibitem[{Int}07]{Intelx86MemoryOrdering2007} {Intel Corporation}. \newblock {\em Intel 64 Architecture Memory Ordering White Paper}, 2007. \newblock Available: \url{http://developer.intel.com/products/processor/manuals/318147.pdf} [Viewed: September 7, 2007]. \bibitem[{Int}09]{Intel64IA32v3A2009} {Intel Corporation}. \newblock {\em Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide, Part 1}, 2009. \newblock Available: \url{http://download.intel.com/design/processor/manuals/253668.pdf} [Viewed: November 8, 2009]. \bibitem[Jia08]{LaiJiangshan2008NewClassicAlgorithm} Lai Jiangshan. \newblock [{RFC}][{PATCH}] rcu classic: new algorithm for callbacks-processing. \newblock Available: \url{http://lkml.org/lkml/2008/6/2/539} [Viewed December 10, 2008], June 2008. \bibitem[Kan96]{GerryKane96a} Gerry Kane. \newblock {\em {PA-RISC} 2.0 Architecture}. \newblock Hewlett-Packard Professional Books, 1996. \bibitem[KL80]{Kung80} H.~T. Kung and Q.~Lehman. \newblock Concurrent maintenance of binary search trees. \newblock {\em ACM Transactions on Database Systems}, 5(3):354--382, September 1980. \newblock Available: \url{http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE,} [Viewed December 3, 2007]. \bibitem[Kni08]{JohnKnickerbocker2008:3DI} John~U. Knickerbocker. \newblock {3D} chip technology. \newblock {\em IBM Journal of Research and Development}, 52(6), November 2008. \newblock Available: \url{http://www.research.ibm.com/journal/rd52-6.html} [Viewed: January 1, 2009]. \bibitem[Knu73]{Knuth73} Donald Knuth. \newblock {\em The Art of Computer Programming}. \newblock Addison-Wesley, 1973. \bibitem[Lea97]{DougLea1997Textbook} Doug Lea. \newblock {\em Concurrent Programming in Java: Design Principles and Patterns}. \newblock Addison Wesley Longman, Reading, MA, USA, 1997. \bibitem[LLO09]{YossiLev2009SNZIrwlock} Yossi Lev, Victor Luchangco, and Marek Olszewski. \newblock Scalable reader-writer locks. \newblock In {\em SPAA '09: Proceedings of the twenty-first annual symposium on Parallelism in algorithms and architectures}, pages 101--110, New York, NY, USA, 2009. ACM. \bibitem[Lom77]{DBLomet1977SIGSOFT} D.~B. Lomet. \newblock Process structuring, synchronization, and recovery using atomic actions. \newblock {\em SIGSOFT Softw. Eng. Notes}, 2(2):128--137, 1977. \newblock Available: \url{http://portal.acm.org/citation.cfm?id=808319#} [Viewed June 27, 2008]. \bibitem[Lov05]{RobertLove2005} Robert Love. \newblock {\em Linux Kernel Development}. \newblock Novell Press, second edition, 2005. \bibitem[LS86]{LaninShasha1986TSM} Vladimir Lanin and Dennis Shasha. \newblock A symmetric concurrent b-tree algorithm. \newblock In {\em ACM '86: Proceedings of 1986 ACM Fall joint computer conference}, pages 380--389, Los Alamitos, CA, USA, 1986. IEEE Computer Society Press. \bibitem[LSH02]{MichaelLyons02a} Michael Lyons, Ed~Silha, and Bill Hay. \newblock {PowerPC} storage model and {AIX} programming. \newblock Available: \url{http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html} [Viewed: January 31, 2005], August 2002. \bibitem[Mas92]{HMassalinPhD} H.~Massalin. \newblock {\em Synthesis: An Efficient Implementation of Fundamental Operating System Services}. \newblock PhD thesis, Columbia University, New York, NY, 1992. \bibitem[McK96]{McKenney95b} Paul~E. McKenney. \newblock {\em Pattern Languages of Program Design}, volume~2, chapter 31: Selecting Locking Designs for Parallel Programs, pages 501--531. \newblock Addison-Wesley, June 1996. \newblock Available: \url{http://www.rdrop.com/users/paulmck/scalability/paper/mutexdesignpat.pdf} [Viewed February 17, 2005]. \bibitem[McK03]{McKenney03a} Paul~E. McKenney. \newblock Using {RCU} in the {Linux} 2.5 kernel. \newblock {\em Linux Journal}, 1(114):18--26, October 2003. \newblock Available: \url{http://www.linuxjournal.com/article/6993} [Viewed November 14, 2007]. \bibitem[McK04]{PaulEdwardMcKenneyPhD} Paul~E. McKenney. \newblock {\em Exploiting Deferred Destruction: An Analysis of Read-Copy-Update Techniques in Operating System Kernels}. \newblock PhD thesis, OGI School of Science and Engineering at Oregon Health and Sciences University, 2004. \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf} [Viewed October 15, 2004]. \bibitem[McK05a]{PaulMcKenney2005i} Paul~E. McKenney. \newblock Memory ordering in modern microprocessors, part {I}. \newblock {\em Linux Journal}, 1(136):52--57, August 2005. \newblock Available: \url{http://www.linuxjournal.com/article/8211} \url{http://www.rdrop.com/users/paulmck/scalability/paper/ordering.2007.09.1% 9a.pdf} [Viewed November 30, 2007]. \bibitem[McK05b]{PaulMcKenney2005j} Paul~E. McKenney. \newblock Memory ordering in modern microprocessors, part {II}. \newblock {\em Linux Journal}, 1(137):78--82, September 2005. \newblock Available: \url{http://www.linuxjournal.com/article/8212} \url{http://www.rdrop.com/users/paulmck/scalability/paper/ordering.2007.09.1% 9a.pdf} [Viewed November 30, 2007]. \bibitem[McK05c]{PaulMcKenney2005d} Paul~E. McKenney. \newblock Re: [fwd: Re: [patch] real-time preemption, -rt-2.6.13-rc4-v0.7.52-01]. \newblock Available: \url{http://lkml.org/lkml/2005/8/8/108} [Viewed March 14, 2006], August 2005. \bibitem[McK06]{PaulEMcKenney2006c} Paul~E. McKenney. \newblock Sleepable {RCU}. \newblock Available: \url{http://lwn.net/Articles/202847/} Revised: \url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf} [Viewed August 21, 2006], October 2006. \bibitem[McK07a]{PaulEMcKenney2007PreemptibleRCU} Paul~E. McKenney. \newblock The design of preemptible read-copy-update. \newblock Available: \url{http://lwn.net/Articles/253651/} [Viewed October 25, 2007], October 2007. \bibitem[McK07b]{PaulMcKenney2007QRCUpatch} Paul~E. McKenney. \newblock {[PATCH]} {QRCU} with lockless fastpath. \newblock Available: \url{http://lkml.org/lkml/2007/2/25/18} [Viewed March 27, 2008], February 2007. \bibitem[McK07c]{PaulEMcKenney2007PreemptibleRCUPatch} Paul~E. McKenney. \newblock [patch rfc 0/9] {RCU}: Preemptible {RCU}. \newblock Available: \url{http://lkml.org/lkml/2007/9/10/213} [Viewed October 25, 2007], September 2007. \bibitem[McK07d]{PaulEMcKenney2007BoostRCU} Paul~E. McKenney. \newblock Priority-boosting {RCU} read-side critical sections. \newblock Available: \url{http://lwn.net/Articles/220677/} Revised: \url{http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf} [Viewed September 7, 2007], February 2007. \bibitem[McK07e]{PaulEMcKenney2007rcubarrier} Paul~E. McKenney. \newblock {RCU} and unloadable modules. \newblock Available: \url{http://lwn.net/Articles/217484/} [Viewed November 22, 2007], January 2007. \bibitem[McK07f]{PaulEMcKenney2007QRCUspin} Paul~E. McKenney. \newblock Using {Promela} and {Spin} to verify parallel algorithms. \newblock Available: \url{http://lwn.net/Articles/243851/} [Viewed September 8, 2007], August 2007. \bibitem[McK07g]{PaulEMcKenney2007whatisRCU} Paul~E. McKenney. \newblock What is {RCU}? \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/whatisRCU.html} [Viewed July 6, 2007], 07 2007. \bibitem[McK08a]{PaulEMcKenney2008HierarchicalRCU} Paul~E. McKenney. \newblock Hierarchical {RCU}. \newblock Available: \url{http://lwn.net/Articles/305782/} [Viewed November 6, 2008], November 2008. \bibitem[McK08b]{PaulEMcKenney2008WhatIsRCUAPI} Paul~E. McKenney. \newblock {RCU} part 3: the {RCU} {API}. \newblock Available: \url{http://lwn.net/Articles/264090/} [Viewed January 10, 2008], January 2008. \bibitem[McK08c]{PaulEMcKenney2008WhatIsRCUUsage} Paul~E. McKenney. \newblock What is {RCU}? part 2: Usage. \newblock Available: \url{http://lwn.net/Articles/263130/} [Viewed January 4, 2008], January 2008. \bibitem[McK09a]{PaulEMcKenney2009BloatwatchRCU} Paul~E. McKenney. \newblock Re: [patch fyi] rcu: the bloatwatch edition. \newblock Available: \url{http://lkml.org/lkml/2009/1/14/449} [Viewed January 15, 2009], January 2009. \bibitem[McK09b]{PaulEMcKenney2009TMeverywhere} Paul~E. McKenney. \newblock Transactional memory everywhere? \newblock \url{http://paulmck.livejournal.com/tag/transactional%20memory%20everywhere}, September 2009. \bibitem[MD92]{McKenney92b} Paul~E. McKenney and Ken~F. Dove. \newblock Efficient demultiplexing of incoming tcp packets. \newblock In {\em SIGCOMM '92, Proceedings of the Conference on Communications Architecture \& Protocols}, pages 269--279, Baltimore, MD, August 1992. Association for Computing Machinery. \bibitem[{Mel}06]{CSIRACUniversityMelbourne} {Melbourne School of Engineering}. \newblock {CSIRAC}. \newblock Available: \url{http://www.csse.unimelb.edu.au/dept/about/csirac/} [Viewed: December 7, 2008], 2006. \bibitem[Met99]{PanagiotisMetaxas1999PDCS} Panagiotis~Takis Metaxas. \newblock Fast dithering on a data-parallel computer. \newblock In {\em Proceedings of the IASTED International Conference on Parallel and Distributed Computing and Systems}, pages 570--576, Cambridge, MA, USA, 1999. IASTED. \bibitem[MG92]{McKenney92a} Paul~E. McKenney and Gary Graunke. \newblock Efficient buffer allocation on shared-memory multiprocessors. \newblock In {\em IEEE Workshop on the Architecture and Implementation of High Performance Communication Subsystems}, pages 194--199, Tucson, AZ, February 1992. The Institute of Electrical and Electronics Engineers, Inc. \bibitem[MGM{\etalchar{+}}09]{PaulEMcKenney2009ProgrammingHard} Paul~E. McKenney, Manish Gupta, Maged~M. Michael, Phil Howard, Joshua Triplett, and Jonathan Walpole. \newblock Is parallel programming hard, and if so, why? \newblock Technical Report TR-09-02, Portland State University, Portland, OR, USA, February 2009. \newblock Available: \url{http://www.cs.pdx.edu/pdfs/tr0902.pdf} [Viewed February 19, 2009]. \bibitem[Mic04]{MagedMichael04a} Maged~M. Michael. \newblock Hazard pointers: Safe memory reclamation for lock-free objects. \newblock {\em IEEE Transactions on Parallel and Distributed Systems}, 15(6):491--504, June 2004. \bibitem[MK88]{McKusick88} Marshall~Kirk McKusick and Michael~J. Karels. \newblock Design of a general purpose memory allocator for the {4.3BSD} {UNIX} kernel. \newblock In {\em USENIX Conference Proceedings}, Berkeley CA, June 1988. \bibitem[MM00]{Molnar00a} Ingo Molnar and David~S. Miller. \newblock brlock. \newblock Available: \url{http://www.tm.kernel.org/pub/linux/kernel/v2.3/patch-html/patch-2.3.49/% linux_include_linux_brlock.h.html} [Viewed September 3, 2004], March 2000. \bibitem[MMW07]{McKenney2007PLOSTM} Paul~E. McKenney, Maged Michael, and Jonathan Walpole. \newblock Why the grass may not be greener on the other side: A comparison of locking vs. transactional memory. \newblock In {\em Programming Languages and Operating Systems}, pages 1--5, New York, NY, USA, October 2007. ACM SIGOPS. \bibitem[Mol05]{IngoMolnar05a} Ingo Molnar. \newblock Index of /pub/linux/kernel/projects/rt. \newblock Available: \url{http://www.kernel.org/pub/linux/kernel/projects/rt/} [Viewed February 15, 2005], February 2005. \bibitem[Moo03]{GordonMoore03a} Gordon Moore. \newblock No exponential is forever--but we can delay forever. \newblock In {\em IBM Academy of Technology 2003 Annual Meeting}, San Francisco, CA, October 2003. \bibitem[MPA{\etalchar{+}}06]{WikipediaRCU} Paul~E. McKenney, Chris Purcell, Algae, Ben Schumin, Gaius Cornelius, Qwertyus, Neil Conway, Sbw, Blainster, Canis Rufus, Zoicon5, Anome, and Hal Eisen. \newblock Read-copy update. \newblock Available: \url{http://en.wikipedia.org/wiki/Read-copy-update} [Viewed August 21, 2006], July 2006. \bibitem[{MPI}08]{MPIForum2008} {MPI Forum}. \newblock Message passing interface forum. \newblock Available: \url{http://www.mpi-forum.org/} [Viewed September 9, 2008], September 2008. \bibitem[MR08]{PaulEMcKenney2008dynticksRCU} Paul~E. McKenney and Steven Rostedt. \newblock Integrating and validating dynticks and preemptable rcu. \newblock Available: \url{http://lwn.net/Articles/279077/} [Viewed April 24, 2008], April 2008. \bibitem[MS93]{McKenney93} Paul~E. McKenney and Jack Slingwine. \newblock Efficient kernel memory allocation on shared-memory multiprocessors. \newblock In {\em USENIX Conference Proceedings}, pages 295--306, Berkeley CA, February 1993. USENIX Association. \newblock Available: \url{http://www.rdrop.com/users/paulmck/scalability/paper/mpalloc.pdf} [Viewed January 30, 2005]. \bibitem[MS98]{McKenney98} Paul~E. McKenney and John~D. Slingwine. \newblock Read-copy update: Using execution history to solve concurrency problems. \newblock In {\em {Parallel and Distributed Computing and Systems}}, pages 509--518, Las Vegas, NV, October 1998. \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf} [Viewed December 3, 2007]. \bibitem[MS05]{PaulMcKenney05b} Paul~E. McKenney and Dipankar Sarma. \newblock Towards hard realtime response from the {Linux} kernel on {SMP} hardware. \newblock In {\em linux.conf.au 2005}, Canberra, Australia, April 2005. \newblock Available: \url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf} [Viewed May 13, 2005]. \bibitem[MS08]{MySQL2008} {MySQL AB} and {Sun Microsystems}. \newblock {MySQL Downloads}. \newblock Available: \url{http://dev.mysql.com/downloads/} [Viewed November 26, 2008], November 2008. \bibitem[MS09]{PaulEMcKenneyN2745r2009} Paul~E. McKenney and Raul Silvera. \newblock Example power implementation for c/c++ memory model. \newblock Available: \url{http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2009.02.27a% .html} [Viewed: April 5, 2009], February 2009. \bibitem[MSK01]{McKenney01e} Paul~E. McKenney, Jack Slingwine, and Phil Krueger. \newblock Experience with an efficient parallel kernel memory allocator. \newblock {\em Software -- Practice and Experience}, 31(3):235--257, March 2001. \bibitem[MSM05]{Mattson2005Textbook} Timothy~G. Mattson, Beverly~A. Sanders, and Berna~L. Massingill. \newblock {\em Patterns for Parallel Programming}. \newblock Addison Wesley, Boston, MA, USA, 2005. \bibitem[MSMB06]{PaulEMcKenney2006b} Paul~E. McKenney, Dipankar Sarma, Ingo Molnar, and Suparna Bhattacharya. \newblock Extending {RCU} for realtime and embedded workloads. \newblock In {\em {Ottawa Linux Symposium}}, pages v2 123--138, July 2006. \newblock Available: \url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184} \url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf} [Viewed January 1, 2007]. \bibitem[MSS04]{McKenney04a} Paul~E. McKenney, Dipankar Sarma, and Maneesh Soni. \newblock Scaling dcache with {RCU}. \newblock {\em Linux Journal}, 1(118):38--46, January 2004. \newblock Available: \url{http://www.linuxjournal.com/node/7124} [Viewed December 26, 2010]. \bibitem[MT01]{Martinez01a} Jose~F. Martinez and Josep Torrellas. \newblock Speculative locks for concurrent execution of critical sections in shared-memory multiprocessors. \newblock In {\em Workshop on Memory Performance Issues, International Symposium on Computer Architecture}, Gothenburg, Sweden, June 2001. \newblock Available: \url{http://iacoma.cs.uiuc.edu/iacoma-papers/wmpi_locks.pdf} [Viewed June 23, 2004]. \bibitem[{Mus}04]{CSIRACMuseumVictoria} {Museum Victoria Australia}. \newblock {CSIRAC}: {Australia's} first computer. \newblock Available: \url{http://museumvictoria.com.au/CSIRAC/} [Viewed: December 7, 2008], 2004. \bibitem[MW07]{PaulEMcKenney2007WhatIsRCUFundamentally} Paul~E. McKenney and Jonathan Walpole. \newblock What is {RCU}, fundamentally? \newblock Available: \url{http://lwn.net/Articles/262464/} [Viewed December 27, 2007], December 2007. \bibitem[Nes06a]{OlegNesterov2006QRCU} Oleg Nesterov. \newblock Re: [patch] cpufreq: mark {\tt cpufreq\_tsc()} as {\tt core\_initcall\_sync}. \newblock Available: \url{http://lkml.org/lkml/2006/11/19/69} [Viewed May 28, 2007], November 2006. \bibitem[Nes06b]{OlegNesterov2006aQRCU} Oleg Nesterov. \newblock Re: [rfc, patch 1/2] qrcu: {"quick"} srcu implementation. \newblock Available: \url{http://lkml.org/lkml/2006/11/29/330} [Viewed November 26, 2008], November 2006. \bibitem[ONH{\etalchar{+}}96]{Olukotun96} Kunle Olukotun, Basem~A. Nayfeh, Lance Hammond, Ken Wilson, and Kunyung Chang. \newblock The case for a single-chip multiprocessor. \newblock In {\em ASPLOS VII}, October 1996. \bibitem[{Ope}97]{OpenGroup1997pthreads} {Open Group}. \newblock The single {UNIX} specification, version 2: Threads. \newblock Available: \url{http://www.opengroup.org/onlinepubs/007908799/xsh/threads.html} [Viewed September 19, 2008], 1997. \bibitem[{Pos}08]{PostgreSQL2008} {PostgreSQL Global Development Group}. \newblock {PostgreSQL}. \newblock Available: \url{http://www.postgresql.org/} [Viewed November 26, 2008], November 2008. \bibitem[PW07]{DonaldEPorter2007TRANSACT} Donald~E. Porter and Emmett Witchel. \newblock Lessons from large transactional systems. \newblock Personal communication <20071214220521.GA5721@olive-green.cs.utexas.edu>, December 2007. \bibitem[Rei07]{Reinders2007Textbook} James Reinders. \newblock {\em {Intel} {Threading} {Building} {Blocks}}. \newblock O'Reilly, Sebastopol, CA, USA, 2007. \bibitem[RG01]{Rajwar01a} Ravi Rajwar and James~R. Goodman. \newblock Speculative lock elision: Enabling highly concurrent multithreaded execution. \newblock In {\em Proceedings of the 34\textsuperscript{th} Annual ACM/IEEE International Symposium on Microarchitecture}, pages 294--305, Austin, TX, December 2001. The Institute of Electrical and Electronics Engineers, Inc. \bibitem[RHP{\etalchar{+}}07]{ChistopherJRossbach2007a} Chistopher~J. Rossbach, Owen~S. Hofmann, Donald~E. Porter, Hany~E. Ramadan, Aditya Bhandari, and Emmett Witchel. \newblock {TxLinux}: Using and managing hardware transactional memory in an operating system. \newblock In {\em SOSP'07: Twenty-First ACM Symposium on Operating Systems Principles}. ACM SIGOPS, October 2007. \newblock Available: \url{http://www.sosp2007.org/papers/sosp056-rossbach.pdf} [Viewed October 21, 2007]. \bibitem[SATG{\etalchar{+}}09]{TatianaShpeisman2009CppTM} Tatiana Shpeisman, Ali-Reza Adl-Tabatabai, Robert Geva, Yang Ni, and Adam Welc. \newblock Towards transactional memory semantics for c++. \newblock In {\em SPAA '09: Proceedings of the twenty-first annual symposium on Parallelism in algorithms and architectures}, pages 49--58, New York, NY, USA, 2009. ACM. \bibitem[Sco06]{MichaelScott2006Textbook} Michael Scott. \newblock {\em Programming Language Pragmatics}. \newblock Morgan Kaufmann, Burlington, MA, USA, 2006. \bibitem[Sew]{PeterSewell2010weakmemory} Peter Sewell. \newblock The semantics of multiprocessor programs. \newblock Available: \url{http://www.cl.cam.ac.uk/~pes20/weakmemory/} [Viewed: June 7, 2010]. \bibitem[SMS08]{SpearMichaelScott2008InevitableSTM} Michael Spear, Maged Michael, and Michael Scott. \newblock Inevitability mechanisms for software transactional memory. \newblock In {\em {3\textsuperscript{rd} ACM SIGPLAN Workshop on Transactional Computing}}, New York, NY, USA, February 2008. ACM. \newblock Available: \url{http://www.cs.rochester.edu/u/scott/papers/2008_TRANSACT_inevitability.% pdf} [Viewed January 10, 2009]. \bibitem[SPA94]{SPARC94} SPARC International. \newblock {\em The {SPARC} Architecture Manual}, 1994. \bibitem[Spr01]{Spraul01} Manfred Spraul. \newblock Re: {RFC:} patch to allow lock-free traversal of lists with insertion. \newblock Available: \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100264675012867&w=2} [Viewed June 23, 2004], October 2001. \bibitem[Spr08a]{ManfredSpraul2008dyntickIRQNMI} Manfred Spraul. \newblock Re: [{RFC}, {PATCH}] v4 scalable classic {RCU} implementation. \newblock Available: \url{http://lkml.org/lkml/2008/9/6/86} [Viewed December 8, 2008], September 2008. \bibitem[Spr08b]{ManfredSpraul2008StateMachineRCU} Manfred Spraul. \newblock [{RFC}, {PATCH}] state machine based rcu. \newblock Available: \url{http://lkml.org/lkml/2008/8/21/336} [Viewed December 8, 2008], August 2008. \bibitem[SS94]{DuaneSzafron1994PEMPDS} Duane Szafron and Jonathan Schaeffer. \newblock Experimentally assessing the usability of parallel programming systems. \newblock In {\em IFIP WG10.3 Programming Environments for Massively Parallel Distributed Systems}, pages 19.1--19.7, 1994. \bibitem[SSHT93]{JMStone93} Janice~S. Stone, Harold~S. Stone, Philip Heidelberger, and John Turek. \newblock Multiple reservations and the {Oklahoma} update. \newblock {\em {IEEE} Parallel and Distributed Technology Systems and Applications}, 1(4):58--71, November 1993. \bibitem[SSRB00]{SchmidtStalRohnertBuschmann2000v2Textbook} Douglas~C. Schmidt, Michael Stal, Hans Rohnert, and Frank Buschmann. \newblock {\em Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects}. \newblock Wiley, Chichester, West Sussex, England, 2000. \bibitem[ST87]{Snaman87} William~E. Snaman and David~W. Thiel. \newblock The {VAX/VMS} distributed lock manager. \newblock {\em Digital Technical Journal}, 5:29--44, September 1987. \bibitem[ST95]{Shavit95} Nir Shavit and Dan Touitou. \newblock Software transactional memory. \newblock In {\em Proceedings of the 14\textsuperscript{th} Annual {ACM} Symposium on Principles of Distributed Computing}, pages 204--213, Ottawa, Ontario, Canada, August 1995. \bibitem[Ste92]{WRichardStevens1992} W.~Richard Stevens. \newblock {\em Advanced Programming in the {UNIX} Environment}. \newblock Addison Wesley, 1992. \bibitem[Sut08]{HerbSutter2008EffectiveConcurrency} Herb Sutter. \newblock Effective concurrency. \newblock Series in Dr. Dobbs Journal, 2008. \bibitem[SW95]{ALPHA95} Richard~L. Sites and Richard~T. Witek. \newblock {\em Alpha {AXP} Architecture}. \newblock Digital Press, second edition, 1995. \bibitem[{The}08]{OpenMPI2008} {The Open MPI Project}. \newblock {MySQL Downloads}. \newblock Available: \url{http://www.open-mpi.org/software/} [Viewed November 26, 2008], November 2008. \bibitem[Tor01]{LinusTorvalds2001a} Linus Torvalds. \newblock {Re:} {[Lse-tech]} {Re:} {RFC:} patch to allow lock-free traversal of lists with insertion. \newblock Available: \url{http://lkml.org/lkml/2001/10/13/105} [Viewed August 21, 2004], October 2001. \bibitem[Tor03]{Torvalds2.6kernel} Linus Torvalds. \newblock Linux 2.6. \newblock Available: \url{ftp://kernel.org/pub/linux/kernel/v2.6} [Viewed June 23, 2004], August 2003. \bibitem[{Tra}01]{TPC} {Transaction Processing Performance Council}. \newblock {TPC}. \newblock Available: \url{http://www.tpc.org/} [Viewed December 7, 2008], 2001. \bibitem[UoC08]{BOINC2008} Berkeley University~of California. \newblock {BOINC}: compute for science. \newblock Available: \url{http://boinc.berkeley.edu/} [Viewed January 31, 2008], October 2008. \bibitem[VGS08]{Volos2008TRANSACT} Haris Volos, Neelam Goyal, and Michael~M. Swift. \newblock Pathological interaction of locks with transactional memory. \newblock In {\em 3rd ACM SIGPLAN Workshop on Transactional Computing}, New York, NY, USA, February 2008. ACM. \newblock Available: \url{http://www.cs.wisc.edu/multifacet/papers/transact08_txlock.pdf} [Viewed September 7, 2009]. \bibitem[Vog09]{WernerVogels:2009:EventuallyConsistent} Werner Vogels. \newblock Eventually consistent. \newblock {\em Commun. ACM}, 52:40--44, January 2009. \bibitem[{Wik}08]{z80Wikipedia} {Wikipedia}. \newblock {Zilog Z80}. \newblock Available: \url{http://en.wikipedia.org/wiki/Z80} [Viewed: December 7, 2008], 2008. \end{thebibliography} perfbook_html/node8.html0000644000175000017500000001551711672746161015512 0ustar paulmckpaulmck 3.2.2 Productivity


3.2.2 Productivity

Quick Quiz 3.8: Why all this prattling on about non-technical issues??? And not just any non-technical issue, but productivity of all things? Who cares? End Quick Quiz

Productivity has been becoming increasingly important through the decades. To see this, consider that early computers cost millions of dollars at a time when engineering salaries were a few thousand dollars a year. If dedicating a team of ten engineers to such a machine would improve its performance by 10%, their salaries would be repaid many times over.

One such machine was the CSIRAC, the oldest still-intact stored-program computer, put in operation in 1949 [Mus04,Mel06]. Given that the machine had but 768 words of RAM, it is safe to say that the productivity issues that arise in large-scale software projects were not an issue for this machine. Because this machine was built before the transistor era, it was constructed of 2,000 vacuum tubes, ran with a clock frequency of 1kHz, consumed 30kW of power, and weighed more than three metric tons.

It would be difficult to purchase a machine with this little compute power roughly sixty years later (2008), with the closest equivalents being 8-bit embedded microprocessors exemplified by the venerable Z80 [Wik08]. This CPU had 8,500 transistors, and can still be purchased in 2008 for less than $2 US per unit in 1,000-unit quantities. In stark contrast to the CSIRAC, software-development costs are anything but insignificant for the Z80.

Figure: MIPS per Die for Intel CPUs
\resizebox{3in}{!}{\includegraphics{SMPdesign/mipsperbuck}}

The CSIRAC and the Z80 are two points in a long-term trend, as can be seen in Figure [*]. This figure plots an approximation to computational power per die over the past three decades, showing a consistent four-order-of-magnitude increase. Note that the advent of multicore CPUs has permitted this increase to continue unabated despite the clock-frequency wall encountered in 2003.

One of the inescapable consequences of the rapid decrease in the cost of hardware is that software productivity grows increasingly important. It is no longer sufficient merely to make efficient use of the hardware, it is now also necessary to make extremely efficient use of software developers. This has long been the case for sequential hardware, but only recently has parallel hardware become a low-cost commodity. Therefore, the need for high productivity in creating parallel software has only recently become hugely important.

Quick Quiz 3.9: Given how cheap parallel hardware has become, how can anyone afford to pay people to program it? End Quick Quiz

Perhaps at one time, the sole purpose of parallel software was performance. Now, however, productivity is increasingly important.

Paul E. McKenney 2011-12-16
perfbook_html/node400.html0000644000175000017500000000613311672746163015642 0ustar paulmckpaulmck D.3.10 Possible Flaws and Changes


D.3.10 Possible Flaws and Changes

The biggest possible issue with Hierarchical RCU put forward as of this writing is the fact that force_quiescent_state() involves a potential walk through all CPUs' rcu_data structures. On a machine with thousands of CPUs, this could potentially represent an excessive impact on scheduling latency, given that this scan is conducted with interrupts disabled.

Should this become a problem in real life, one fix is to maintain separate force_quiescent_state() sequencing on a per-leaf-rcu_node basis as well as the current per-rcu_state ->signaled state variable. This would allow incremental forcing of quiescent states on a per-leaf-rcu_node basis, greatly reducing the worst-case degradation of scheduling latency.

In the meantime, those caring deeply about scheduling latency can limit the number of CPUs in the system or use the preemptible RCU implementation.



Paul E. McKenney 2011-12-16
perfbook_html/node314.html0000644000175000017500000004653511672746163015660 0ustar paulmckpaulmck C.7 Memory-Barrier Instructions For Specific CPUs


C.7 Memory-Barrier Instructions For Specific CPUs

Each CPU has its own peculiar memory-barrier instructions, which can make portability a challenge, as indicated by Table [*]. In fact, many software environments, including pthreads and Java, simply prohibit direct use of memory barriers, restricting the programmer to mutual-exclusion primitives that incorporate them to the extent that they are required. In the table, the first four columns indicate whether a given CPU allows the four possible combinations of loads and stores to be reordered. The next two columns indicate whether a given CPU allows loads and stores to be reordered with atomic instructions.

The seventh column, data-dependent reads reordered, requires some explanation, which is undertaken in the following section covering Alpha CPUs. The short version is that Alpha requires memory barriers for readers as well as updaters of linked data structures. Yes, this does mean that Alpha can in effect fetch the data pointed to before it fetches the pointer itself, strange but true. Please see: http://www.openvms.compaq.com/wizard/wiz_2637.htmlif you think that I am just making this up. The benefit of this extremely weak memory model is that Alpha can use simpler cache hardware, which in turn permitted higher clock frequency in Alpha's heyday.

The last column indicates whether a given CPU has a incoherent instruction cache and pipeline. Such CPUs require special instructions be executed for self-modifying code.

Parenthesized CPU names indicate modes that are architecturally allowed, but rarely used in practice.


Table: Summary of Memory Ordering
         
\begin{picture}(6,185)(0,0)
\rotatebox{90}{Loads Reordered After Loads?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Loads Reordered After Stores?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Stores Reordered After Stores?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Stores Reordered After Loads?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Atomic Instructions Reordered With Loads?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Atomic Instructions Reordered With Stores?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Dependent Loads Reordered?}
\end{picture}

\begin{picture}(6,185)(0,0)
\rotatebox{90}{Incoherent Instruction Cache/Pipeline?}
\end{picture}
Alpha Y Y Y Y Y Y Y Y
AMD64       Y        
ARMv7-A/R Y Y Y Y Y Y   Y
IA64 Y Y Y Y Y Y   Y
(PA-RISC) Y Y Y Y        
PA-RISC CPUs                
POWERTM Y Y Y Y Y Y   Y
(SPARC RMO) Y Y Y Y Y Y   Y
(SPARC PSO)     Y Y   Y   Y
SPARC TSO       Y       Y
x86       Y       Y
(x86 OOStore) Y Y Y Y       Y
zSeries\textregistered       Y       Y


The common "just say no" approach to memory barriers can be eminently reasonable where it applies, but there are environments, such as the Linux kernel, where direct use of memory barriers is required. Therefore, Linux provides a carefully chosen least-common-denominator set of memory-barrier primitives, which are as follows:

  • smp_mb(): ``memory barrier'' that orders both loads and stores. This means that loads and stores preceding the memory barrier will be committed to memory before any loads and stores following the memory barrier.
  • smp_rmb(): ``read memory barrier'' that orders only loads.
  • smp_wmb(): ``write memory barrier'' that orders only stores.
  • smp_read_barrier_depends() that forces subsequent operations that depend on prior operations to be ordered. This primitive is a no-op on all platforms except Alpha.
  • mmiowb() that forces ordering on MMIO writes that are guarded by global spinlocks. This primitive is a no-op on all platforms on which the memory barriers in spinlocks already enforce MMIO ordering. The platforms with a non-no-op mmiowb() definition include some (but not all) IA64, FRV, MIPS, and SH systems. This primitive is relatively new, so relatively few drivers take advantage of it.
The smp_mb(), smp_rmb(), and smp_wmb() primitives also force the compiler to eschew any optimizations that would have the effect of reordering memory optimizations across the barriers. The smp_read_barrier_depends() primitive has a similar effect, but only on Alpha CPUs. See Section [*] for more information on use of these primitives.

These primitives generate code only in SMP kernels, however, each also has a UP version (mb(), rmb(), wmb(), and read_barrier_depends(), respectively) that generate a memory barrier even in UP kernels. The smp_ versions should be used in most cases. However, these latter primitives are useful when writing drivers, because MMIO accesses must remain ordered even in UP kernels. In absence of memory-barrier instructions, both CPUs and compilers would happily rearrange these accesses, which at best would make the device act strangely, and could crash your kernel or, in some cases, even damage your hardware.

So most kernel programmers need not worry about the memory-barrier peculiarities of each and every CPU, as long as they stick to these interfaces. If you are working deep in a given CPU's architecture-specific code, of course, all bets are off.

Furthermore, all of Linux's locking primitives (spinlocks, reader-writer locks, semaphores, RCU, ...) include any needed barrier primitives. So if you are working with code that uses these primitives, you don't even need to worry about Linux's memory-ordering primitives.

That said, deep knowledge of each CPU's memory-consistency model can be very helpful when debugging, to say nothing of when writing architecture-specific code or synchronization primitives.

Besides, they say that a little knowledge is a very dangerous thing. Just imagine the damage you could do with a lot of knowledge! For those who wish to understand more about individual CPUs' memory consistency models, the next sections describes those of the most popular and prominent CPUs. Although nothing can replace actually reading a given CPU's documentation, these sections give a good overview.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node55.html0000644000175000017500000001650011672746161015565 0ustar paulmckpaulmck 6.2.2 Array-Based Implementation


6.2.2 Array-Based Implementation

One way to provide per-thread variables is to allocate an array with one element per thread (presumably cache aligned and padded to avoid false sharing).

Quick Quiz 6.12: An array??? But doesn't that limit the number of threads? End Quick Quiz

Figure: Array-Based Per-Thread Statistical Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_PER_THREAD(long, counter...
...m += per_thread(counter, t);
15 return sum;
16 }\end{verbatim}
}\end{figure}

Such an array can be wrapped into per-thread primitives, as shown in Figure [*] (count_stat.c). Line 1 defines an array containing a set of per-thread counters of type long named, creatively enough, counter.

Lines 3-6 show a function that increments the counters, using the __get_thread_var() primitive to locate the currently running thread's element of the 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, using the for_each_thread() primitive to iterate over the list of currently running threads, and using the per_thread() primitive to fetch the specified thread's counter. Because the hardware can fetch and store a properly aligned long atomically, and because gcc is kind enough to make use of this capability, normal loads suffice, and no special atomic instructions are required.

Quick Quiz 6.13: What other choice does gcc have, anyway??? End Quick Quiz

Quick Quiz 6.14: How does the per-thread counter variable in Figure [*] get initialized? End Quick Quiz

Quick Quiz 6.15: How is the code in Figure [*] supposed to permit more than one counter? End Quick Quiz

Figure: Data Flow For Per-Thread Increment
\resizebox{3in}{!}{\includegraphics{count/PerThreadInc}}

This approach scales linearly with increasing number of updater threads invoking inc_count(). As is shown by the green arrows in Figure [*], the reason for this is that each CPU can make rapid progress incrementing its thread's variable, with no expensive communication required crossing the full diameter of the computer system. However, this excellent update-side scalability comes at great read-side expense for large numbers of threads. The next section shows one way to reduce read-side expense while still retaining the update-side scalability.

Paul E. McKenney 2011-12-16
perfbook_html/img184.png0000644000175000017500000011217011672745757015331 0ustar paulmckpaulmckPNG  IHDRY>LPLTE/%>K 7 2mM q(d>|g'\8r sia`/l c":y q(&$ tj_ u 0kaXjyS y! oEeE%^+| rHBR  u-a` 7Q 3yA npcB r ph*b+]-x t,*J Y^ v 6NJK0 lCbm'V <z  f$% 8G s rF hi^ v u l k>ybba%[z x 5 .f nd|}"{ZgH9u1p#4m-j tI .j`ytRNS@f IDATx S[g.MAɁ14r8C9b2E4T n9s-N@3X]jL1mE:‘nYbUAc{kKʉD,^ﳞZ>o38ѣӶ}kӜspù52:\"{>K_=mZOg2Zrĺvo_>M^?^;m_Jԯh9>~7ceժbaVFB=~vuy# Z-н`R{s97ݖ>{էe"TrP⦵t`;fc{r:{7V<}vvFsYy_^o9ݶLDRՈ/C -C\6Q,OmM8ܡRL}QWe-msr7v/K)ח^)rG\m>:2U=.s9|VvڼqݶPÁwʭmr;i[٨nhcr3dQW:EL_&h'9K~o*bѢ$2>t+k<-H))-o{Omg|bNO^Z r˻[n7rƍl&1Ţd#&K`Dp,g"مHh29Dz/{/: L8oiX Yv1!!w O"fۆEsWj$x-`љ3s|:@;+]3xn;(yrX>J/w&>$yO -*jV:7nV WB2G/%j~wV=yt6O=&%0,N lR<- ӻi";:p3dg2\ϕ 2j6!yf3{}Y2lC8:fa$̓ܭDyt >1?<7~^FcMYyԅ)̍OX8r\n݆Nl™~=v>wcgC6Qi 6[ݯ3COrim*;,޹;$m<sYev<..=?CxjwXlmlR軁63C*5;i 3=&#ZN+n #O0?wu#H_=ЗOۺptZoS-&sw&TSA0ѲK]23i/ܩ̍2j'ңGdnO.RH/i>C*Hqg {DUouyri An}Ȯ>~ce2Ҳ7Lu(`~gݭfOI?6sD~m fDҪ߱8:ZH$cc|7qys5$֒36'\kw9w4j/n;#&oAosC!Q>I޵<`3әRAQV~|J#u WuAךw#!h+0z$Vaw-:c~22A!1?s>^uuUyteoaO8x.ʿ> ʿ<}V1lC7jϡ:jo@RQ}+.GD LQ=YomREdJrBPJ2 wrK zxԟ)dfzeL8‚=͗AM''[sD˙`NK?# f{wvd5dC gkxT%It&ؘr-B%B{JQ}gd8ִOԬv%I8.,kp:qW8v{ǞVDGb DggZ݃]&$1$$Ośj:$!Rgb1P2)绉T6WL8AHŖLƚeLOu50?0P[JzSGHtE} eª LwRMXP.<#*#pmmɟe${a1[OSO+)% xs{(ADZF}^δ~z.VR^$Ul# =vQs~CK:qm!O9lV-psoޫrkS z W9kpX\/qیyfeCE j@gsMoZz鵑1p4|'-17:t&''!@م'k>pygXW(WۈL]/l4X168ĄjcA!mKHZZ9r[xA갶GGI/A϶4 ԰ *9M]y3-jL ?n!0!A6ُ*[H/do Fzl毑Hmi.qm,vv)&`]{Lo <gjcPInO//F03qq^D${2<<ҎMp b9.w,ThJj+`_bwnL\u¹U ?1QGG>$שJ c~ TZC1zjsot[P?>O;9goߗI8_F;6`H֧EVl9$emyL$4]}!g'ޗs!Du G& 6`c"%Y(wjfP/$24(B YKȨد[\{~Pkc7^c-So .sU̒BeveP|1YůlYRTY蕙wG\U"uzuz.X9Vi$+zfziBjɫ:p,Z{`(_e'Kw~ՏLp\.~}`e㤇+kY홦` [l r!E<1wrfl_m;eqcAO%%GF<ˎJf()Ym!J:vo kip#9Ms<60]ߞ斤뎃q:Oy< šxn@?|8z!102iT8D_/9yj4"8r_>];ɳhe8kdD06.PĬ.u(IśбQa]e;;e@xWG>V`xViTN&SÆе&t$A+A= Qaۆ0=:8O*>a\"6xBvwL%=wtTkEDJMȪJh_EA_Ҳ*gIjZ<ldԀL.<%Ezd%μ<Ϋx(7Lv+Nϙ_N#VZߓȳtd&‰1 a$֫XؤH|76v)i,yOթs x67ONFuKm#ǫ'I` 3"7B%C.*׳::ji r۠7]PB#7ӸRᯍ4zr)p)w|fL{u9%EҷoAuiZ Q4$lt^A*2,PK*E";OrO/z(Q%/\DpǮ**;@ 4-Ἶ/T F ?$P53u}AVM/UoJaFi}`̳ppǧ=XJ*i%ăW^JN㱨[YGAVZs;IBDx6mY=X:KzxR`8oKK< xމ~:Rj9-37_\cc õtU U׀o?ݥUJVW'^@[-8jC&`$S={3)/45_*rگDYZ2QM5+-%ۧ: FyWm ѶyhWO6m @ړoZ쏞8[#@VSTK(ˊ^2vD2ABxI,JʜBkm]M[Ϋ-=PG_X?rv'unRa`ٷVmRS{x8N;ɑөs`! #}d܀@L$Xi~,Sj~dM%H[Tۻp%u+cL!\Ғr-#RuZ]!mqr:՜{'K\^lз@b!0}-(j$42/}Yrs*!x!DF\K9zD=ޣ/Q9R9_3skL ;x}4_9p蜃Fv-3˞RߓӏT6=Qt3ɣg8s%RW[E@/,ϸgz"#.-s"ٶ=(3عkhl>Nvh.a!.y=4 ?¹-I.G"5B2p瞊"dGec}x0nyj#ZY? ~;' "Hȑ B'MXY2O11X lqyY^VN-巐EyW ǝ_OSWkd7jj g"*i*p|Xoz?J d`6_gùHmm$9z9cz7HV05AQ;2Q7FJE؅r3eb%a3LɪWk"Ae|d0 :l qf}j. BjYSRqG6&<9V)l*A)qsln]דW9`^f#6wbrR2U 9};O9瓢5= ~L< Q#kz|m7G#*f Iː)H?2If( M-$Ԣ9G:DjdB& IHn>$&io Sr1v;]N(Uzut2dt9e2ɝ{5Gs*Rh~m[}|$0CyҞ̋P*KK8΍HM6ARDPh9jA.m:+mxB7-G{+!0=[ p&/t0r5ߞ/lTȊNl BQ#tYrI [j0ހ3<ĺMJ*fa0hܪʦ:.u H ^JM+y@ǔw|] ٥έV^bZ[^csRۧC̓p.YŲO,p}hn. QXT(*H}:iz _%@k|lyNY-G6$ФZ=yC@C*Q:Xp(iSܝO(Lpt} @O-.?g—|ɢZ\,Hƻ!π`y]{8bJw3|vId')sF.~b_dzemt^WY[7ёҸI%ă{ιU&k̻>%8rUX쭜 7wDN,FrpU-a.ޒ!ɏSs cͧ&K@ {hϡux8>6 1F?P*/wR4ze>lˇ3n Gֵ"#jޖ &t}F<Ѳp !JBqw,6} ^׊ >@lOQ, nWh+׃sql(jNHm*}= >]W8s"'B"PV"sZ6GŬeآzW'SO{jُ:* κ=+Fr9z}dLWߠ Yp#{{+Qs:t/#iĈRgQ^)I/8F#Zv8?.e9[ll#|Eu9s9b^9ˤ%#6e}b;)RbI\K)NMgs{rљF/ c<.хEH +mODN%4-rƏҿz}]XJfdʫJg3kpd˸fmcgzu)EQaGfʅbLBb@!u/S6 =L]R '|r4Q/2Z(LF Q[GzO45"vv=*N6E쵬pAvvE_yB6DZD6\Uit5>s1JLsV3Y&{ޒ^4%GQ?x[y!Sr54BabUrc{sP6}<:_~<֬[LQpB/qVgAջoC\BR "8FU_TϿ? 7zEU<_$vۺ(J5jn gNt촉لU4`oYlPqϐTd)pҔ䬒G4 X>pδl8 cAYQm5j"X3xԪWUO8H`,Sű]q|ԂS8Wo2!U@[lY>ՈF<+nU(RѮ&xߪx+ي`ɋb|hMF ;-Y!a<[QMl"bxat`vm7-2 xAдԏ1 X  HC2Y] 7`FFGEȸ޸c1ww_ky(h^zG쳚/ϣ1s*Y6LxjWSU1B{UPa2)N c17@-݅EtZW1=н\xyydܨ쓋-02q]fi{LTho̷=6]kf s ]W#[n  -|#VUƁS9aKSץ!#zS=/ -"/25>m:dE(3@ZmD%2YDz37U[D_H[a/ڮ_4'ha'*݂dkSՉ EۢgBD%w[H6ЭXE5:dxa `&<_ ,:pX|jNi,J~[Ĥ3nL AR< g31'9x.ۖ aѦي uڌrI|7#wRԿ**_fWloF.;0zfޫaMKDo' #w$`XAcM~ka4`]اՆ"FAFX) Ck(À\M8]|@lq Ux`l(5VddK@e{kHNqy~M‹⾤2zƋVBf( 1qF.nof Kj[>> &s%[#, mo=jES}j82уCۉ^9@bb垆\0E}7uI@^JQ'2m"k/&7 yMg7ʳWk m̈@~ *4DS\ 706Kl>[k9^5]85qu I+=nq:}+&*7Ĝʱ]yziׅ ZEӍܴঋYAd%mI^ljv9%v=qIaW@WN͜lBV#^+7 CiWNޙ&v,nOSĢ"T֟kw͐sd48E^mȄ>[ r($ 1!1<{Ԍoc<@V#V]J-!形(4G"oW8isROnfXYœN卵(O|b%d"Ȋf~%J~M&7JgNߨ':fZtB>Ǿwthb$ 1Kt)+KWT ' ]F=JGBN?Ά6@T՚ nLJTE> S#CقB2+Rs|~f{193Nj!OH0 ]]0zI>B덞1uxKeQQOy$X&?f(_3aѳ/M'r@6 LJ3$O YϦ(,=W!{M0pEdL;2}~1E!!,flJnkkl3Ǥ2>\ʿa$%'>р^b%iU :Xmw\Kұ@ԕ^v4L%FikY{G]oYR{|Nۊ1 GEE,W[n<=b@ =lLO.< /(!; KD*t4v]^ ][+U,ɬ$ V0,*/ I4[ׂ=Cdᰪƣ[4zzˢOSLYK8R B<oe0QM$!#ĥ;&}rEmq,VA8')"!u˷߂VKzd~ j:>5H赞s+yD"JRAw )6BJf+`OI؆]tfJ'^q zGt`td5KOE@\V͂l.%)a yb&Q2@"}q7gZxI җwhQa `H|{X>"YoCd XpH"aO'5wsdoGD8"2`Z1͗*f}Q5Y̕ߢP\Cgy|)Wz}),( sڎc. `uYթk(:pq25ء,UyWr16??"W-0]9R/Ae?}=\|gɈwN#0{1ϣJQt3LbO 'OxKv'ҬtQ&?Qn V,yv:˵"x9oQr˓4:>h?G==H^5ck人x0k XvSeE OS2@8=AV0kW N}_MLxy bwb7V>_iqց, 0k/P6 alqK͐kP yO-w`1Ar!J s0ռT⎾!,@ sj++ WSK)TJˋ~rO!Z ]pS+Bw^jaRVKZX05y3|E3%O1/w55I Bx%ԉ{ IDATEa=UaHߧ&䗳 f:'4!ԳfQ1_^ %Ů9+[׭K'\T쒤 '^kvvvR;&&s:p? %p @0I}_/]xV0|ț–TVXVԐT~Cr1W xGX}`YX[;jѤyw}==~߫,0id+d 4pClIꄃ6KN7D؄'`U?af?āۊnknˬDr~V̚H [. r3{+ۇq ]N3tu[pv >f҇r&!=~uvaTl/fw% yX^"徼)vA߅7Jt>Z=L37)uj{0%֋xZH[ʷ "x:aP"wzV@==<40k-S]O>3PWmC oz"+U3fi{lp\H˃rp0"\?߿ذfB[l! ^$'wFd(a僌džn`",1z(21r=nL-s%xwcEz? 'O|Jm7.{ /y@{{+Œ&538eKrL aȒʭk} k ྾՜[(WxH֒7 )&ÝUIn \KsC[Z(>7EIi("ڶl zMhF->)>:ȧx)_-t)1׋u8?[B)>R +QTԛH 9;=1(N̽\W J#= LhЇRKJU%yWV}!@Eh$ K_#T۶#[9Ǩ;Rtex[5Ւ:F?I^d.u+u%x3ݸߌ\Y0I "J}SQKjgaPđs@G &zU]z9NhD۞݌I”}P7?5L ~;o?;D~~ɉDB(GO5 iƒ!:ϓB<[7JK&aYV/ڵʯD:CR{h{AjYpx4E;NTptdZO5o2/,˲p0a6/e} ʡ{Mkt}g [u ncҜ @HtcڷbaEg_Lgyd-n;1kd|zB,Yl})V틫)z7YP;eT1U[9In$y_AT4Nj{?ςvLF%aw[$)ݖԶTr=F͌+ʖhA7j<m'Ub5N+G?L Htwy1+ knٸٷa+KĈ7jj2,Li}e/޼GQӟf,SrLF-/ay3bWyx7gT 4͗; 1ΎT͕7S &D0qg٪ 9,?~$?i*P=^{A /˦}T*Hv|?+^y',9̄`ʥj!i%<|ʼ@lq=z?:~+e?yb\ LPRixH@Qy.R_ S'F}y N1qJcՎE0'@^6c;}ٚsf<(;fAPK8PKׁƴ‰)z"Kө蕬z͛/+bZ?KM"Yb\q * >gC@eA&0w,z<RJkS> +*$86D reLA&>0vVpd5렠_e\|σ | V#}x}%aa69̝v9VKr466sm-{s\0?iWxY>h}_V|G#+/66 }WhU/D ph&?T*?_/^۵_0i'o;x@}|͸Sti,L+/&/KtJ z]򆆷1ʚ[l#DZT>$|SއX8~au92n>̒p-oP_ a lTjC1qoSR"$}A\xOx5vQc`Wn"7b|/NS.YD_߼ZJB+'TW ]Ǎ|kNW߀וW8ZGU~٬n|#qlGTZjf9~}@W47^Ay)orQ11,rw}Dp'^*\,cPs\LpS*6 e dbX~sC쑺vd1\0m1trR\iDZS>Y:!!WcSa O\u Ls\a1šI.q,_9iݑtj n*yĹ0FEm蕸Lgq=g٪U!\ r_ rjvOS}ɾ>/9-Zz3jQ7!k=DZvwY#,rC]q1ߴ_E ]zc'd͟7RbC =ްYuI_'hZdW2L 5`E:o\_7TW®\Guzŝi.wB%MquB,h0}QӱyQYpuXLmцm6]Yalr,4ꬦrhGpkWyL_*ʸ[&}n-*DGu=*k>jzBbW- (yQMN)^>zέ:V{\tg?oF]9*.ca.WIêWװ'MyhkB<nu٥ɸG_$.'R!,ě jh"TMe;ۥuZ<ijnzn8{/0OH+qh9VB¢M6G6aeš#ِJ<_V +53:uM:`>j~SӧM~<8]: ̧9V 1w8ykpX>P/5_XQCR{LdJMkY'j[Łyo87d}uR^TUjvW7WW W޿/u6bH"M'' d6ݪ?}*B,\Ch*6)a;LkʭƖ1AgmYwYChVhfuaʯUCA:fGnk+oj#r2rƛyꚮ\{eluf36ۼьk&s5A\?U=3Uey{ -H~m$W(Q5`b) Ocs!*WWV .B۝<䮭ڼۼbo P9N`9J(5jM+<5#+qYY?~En \[+%wᆮ#;(vZhV zUM/>2/FG6,@vyT;30AwgB5$T[h糮ehV . h 2CtooBVn6[[i9xU< xځ":7~s\<0}ηc2Smj:oBB[iZur&dQP^f>bg߯"O/ fB\`,ӹ5GԍF`(cBsh@EH~c]֦U7*@K(,/x-ȉVM5K4]Z'$()p!!I0*t[]}Lw0l?/@5;8Xs?޷Q d]'ŞV\*tnŤN%e*7rΞÃqѭYY֊lڛ `p*ϊLWf~`E"~B$lRyV gϧgy,O ̇@KEP1YpkؕGU*J^_;EC-Gݎ\ Lr}qIfw"|x)ƈ0[shd20lDpNf94Y%c}Y!a2H~*Irogn7|V5\<,'n8n| cV܇.ْj+e+HfLDu۵(33 |kYhCl )@u! cBVl)8ir|8+GHՊ弸 Rܷa|=8n;QVD^cH$"7b[,ktWK80E\VY٫s0ά_g 2wX&Tr54Ks˷PBy֋B-܇u>ttV%Ό z-@VmZAV +a=a| i2Q^3v-' %f\B4!²kp[9l#39$O LA [[u˳֣Sqń^C7c)xV0Y=X@k@VaVZu ROyG'AyDS|*nXKSSiU5 Z܈疍 n}Eo#0im36m-E*gs=lf%HV ƪ_Z)-qXhU% vKˆ ˍo؟b印W. jJ{Y9 =GnP{yݥxy edD`v8Ych9n(EV"U*U1 @ 8j!}b>*Okn.C+֜s `%"[)xބBw=Xo6L8ϗFI%JmOSH7d{zc35觽6@anz6Zaw5Yz켜;S@0FKfw4L U\Vdܨ+ 3X˚}8eե46|Y,lR -iR0򡿡s2wdq!t<$UCDaUeO`kvftYѬB2gX\s ɢMrɓoFvdq 0]f-"meLV!HnRyy,[Y3 <|?)wu_6KjeVLJ[9#o%(!UXU^<%.6`.,,Ó wWbdS)xBX#2ͅOýU|hr8rh9 ),u`R<^܊i!#WzZ9 ąX0aڈUʫڀV+V!>DrYڅ*{J(h ~ & CnK gZ~n@>0Ywf 5[D`WQvgdY3Ԫ =kKrVY9-+Ldoh#|'zx@ 8^މKj=ysF|JUyM$reC ^G%ؾ٦m\A|hbGQ6XlMx 41F>_/ aMbE K{{6(X6y@=@@TRӫz ]iuJsJe,}j7o IDAT̊ k&\"֮!z .t[=]Ohm[ y[yYU4a%Y ;V,DԪq[):daT^mGk+QdVt:x=3~ F2ْ@g)Jȑd t:`r E0&yWh|G$d]^Q[$O#*hu=M$\/{@V!!Xp%V{=oAB4*jD>sJSE"B)S"!her~7ou0(WP9c%+\ci#`'Éϊkş|RY)֥J2`8ܷTG#ÏqjÔ$wL.9 YYdV5_ܽX5ym|:rvEt7v^nVyTlT:R~\fvc5M$Bф?%ᩰkԪ86dZsE@2ȤR!44*x-A+D`+W_=qf0|ZpCJwhup^!{6p&r+EIpt˚n2qkop;K:ͬb,-/f%E #dzLcy ?$cxtڋ6MO!뙦"5Z1XdbK4' 0 ;2 Hhռvlk LjtV޵Xڵ@C\jS~E`_N_嫘hx Tb},Y$MbLXiƒV*3h؆CX{KꎎQUr\?8J7mIヘWGQ7Rd\%"^ڭwSD=47w1EQU( m/pv]}эVIZ-#Rch+H]έ bS܆D%BzT*/s$LcAL0i1}MTP̊ %-|/wђntb>a5tyuQLV -wӠPu0࠰w@ʾqNtI*ztPp+njKX8Dm-Q vaD8Qkڋa$A֎?̛H-' xݎ4PMH>Je̜Dر_uqƵQʜ8+_[b 2Oف.^<[O Db1"JWղ` (e6˛cPFD]UAcDE#~7K 26Qlݶ 1XBvٲAl;4a!LxRuC*WUߎ֋t{'ɖ.)|˧ 2M{cd:pTKT,F/Ӧђnoeρ} PYX\ԅGuO{<Ӂf "M Ik`1y.6+&T6z/pr[hqdav!]'ȈVubxcFA)OR! 2(n6P4 @`M|G; q=z;?;8ֿpd738Q2n%Z0 XSCbBK̬,jd ^0(nc-uQ0 @q^s0}f7rK5iB2*jUsC<[')-2 aif6 6HXC^()[(L4^pMc*Ui&^@, %E$-`6ְ~Չ-%M A+&h&zTcĢL&Z7b[y9lGϩ O\%B Ȏ HSщ\ "j`nQ+ln!q^J,P03Hȗd 1CTo4< ESP$l$y.#zDgE#%T/.% YNGK,%R4pd]sBl1Azn@'S䏗bXF2HŒVG&2Y6>KM~x2< «M2=š9N=|qXזWW;KY4*+kXo# Z˹w%G|h/n#҇ jрkBD 98@ZzOèR6y)kU"KFzhłzAkpi]JhebFxWe\:"eA)rXk?ak(CC`Q?dNf]U1M@`JadV8i5O5X+5V'XcgE 2R` I^CdO lۋ?̄6+kqj*'(R~G :ݨk˴khiCt\Oao|܌|N |L|y^Jm4}h$*Nx_8 [ \w([ T45.+#ڌ<#YwoRX&]KzYy t0P[H3^BK^k($?^H1Gfj&ĽJ7^:{u}D! B\+T˞ekdWk1ul65E6pr&=7)ʅ H\Z"($~?y/ /?HJ(&#l3R~ ӎҤ ̸šeQ9An^GeX( !{$ޫ~Yt%R#>' ׈#K` gvOG Zz8[q9RFN†u0 XHuySRgi(N @}VjG_LD`%_b]dK0+~_E2[S7qcv a X\,A4ӮْzmaU<ʑZà- Znyl$%3|#_"B'9㶾?mDx%CgǜJteGv[1uwX)/@-AHF`ߺ PwVk&E}[˘oԼ9{ "n^bybh5˰E*FI;ET kx"|[EJݲgU `ڣXXaMdR71Zv~?yVE0 Qq4WABZ!i:>Y*hMJ׆, PX%—61{7Z+rJGXLbI lYE ŷ+4MC0Z;9 y \ \h ХUqG3@X3r{f6 y&$z-=%1h D XRL?$X0fFPJ}\N*zdgX.;Y:/Fv|㲎""_]zURxfm N%]T2L O?q7 [V*s@Ѡnݢ6gl?b%ْ]ْl6+_#&h Wyz՗ 2f&#qH8uٱ+WTTj\ő&Ѡg̺VeIFl۞;kN-y bф/QNZOg6$ q_?߾ls8OwUސ`:"hwh,cd{ko;:VoԍAz IN5?#]u %Occs=ccW~{} + [Y{H+~ɍ̉StvNڛ7<5x-B.I+Q8~4O?Pnp"Zu=k[9-XCK ճl{9kdڲ^O2WXzg>L&~Oln>|ѠAWф )1rXlm ;uf[YEZP%׏",XMlF<Gѫ0˚%ͺeDȰ9t߯E'5l) yp9C<[}g$oV0o|}dB d+s9 JcK\&tk[~ (AάNhV_w4rp]"f?i#ؒ| g~D<?t2о"NT?C]JxFǢښ·)Lڭs DGkk3{c-Z̿)?+mřu02fn/*IE$"EkEڪ0n5u5*pũ}19j_t0͊hQ['B]%7v$F掳9FC><+ q&Ԉ iE/:ćn'mN*6 d}jT/^+?;Γ!K5[{>VZޥmד\d6ڄRy Av",ʗ83͗DŽ+!^nCI}EzWᚾr6XȰ CĊǗyA&hhsag8xWH>< #7/(*q2u4zO#AmZ~%XSت|-u zK[b ᅄaD(D{%.=EO>rEnjV 蹮ׂbc. iHr_Vnm) oQ (곡4! y +Et5I_d=%~|T"=cix/qfyڞj)>FYD*_yMYzF523s[>!YXLO HcI3c!8|m$AA 4g_c!E$ݼ|K4}D!zqigl# YYyuhm.cr!vAvkpL 5t^7!c@zbwϚX Hox/AµG)09ŻJb]XP{ h1zq;E*[y%;??/Mږ%0LzDasޏD2ñBh&<}Cak+=dci 8p͡SwWG͙knLr$^v3ZxaoS1X4L2ٌKP"F2?GW?![l9aMO?b(_h&Ry:\0pV\`1G<@dTLr;l-ٜ4%e)hO}tvv"1z~ҷ .A eL(qNonż7=:;y0[UsG`}l{ [}}3j(VI$, k]3f$1+&:OFGıwv탵}uOhwmݻg#R[l%$wb+{H ,Y! ?VeSJ9Ba\7ux2z`^½%'|O__S"vro.WJUM Џ Ē޷];`< ex9VgRQ]yu}=z^#[mwPX2N\@NpɾO=eY`e !h+ $-<!(ix#ZCvCUӭDiyl{nڵ+K F&Vv;ƤIqfOÕISh- w)^۹]E65J)lV\s?Zщm\NtWa,0%1aq~KJNu2SS/hh jm f?M <"!&Ռ>Rh#u[GʾߣtR{X]7md!-ON݋dNCow5)k/ ҊrXgS~UIDATK⣃ikLHΑ.VBLkW R:.BG$fiygiyKUNRXgط's~{nsLY!qA9jW{#Ll^զ%}4a7 Pc"YDF+ҹЖ< ZȢcA;6az#311(:d ERמhٝԑ>pV:j/`*ͽ\fhr+Qw)FMfxjF"vӦzz$h_@Ok"Va $_P (^RUx 4ɘiY nf*WרHКhERj$l >ww"DŽ-鷳|Ź:>Ʌ@1,YdiiIJžbIC@;MH&x-+S|$-}_fztM]^qsy> P>u[6w٥pצ)ʔU\C#(4)SԢT֤M*SjZ_$VхBE/ԦXvFE 5-2&g E׆_3P/|n~zW>= Hc-S쬘$9IتG k$3SShSP=s?.vU:[h]X {seiM ԬT^d]U>,Ž^q\=Q4(ƒeK1lQk5+^y@ܡA'O|7<&J#xL+xn tgYbr~n]Ʒv/at;6" ڕø0[}ew;I>E!2#7Z5'~B(ejAD|3A֘'W1ŕ4ܚ_(?Z?[O`ZQmˤ?;}br s=8S6Q;fnGVE;-mdgQ;M * Jܱ Qmczjsru. |.,GDq݂C}ج-/nOuvv"#̓L)+,6-sCo.=( y7 maE<0ҮFwyetwvdƬK*Mh +ѭ}-W%0v4BQNy[#'r̞2gF'͎|((%'a8?|n׆V[1=Q)hfl^m{ERwQu,;ѽ@r PZ9Q z L8Cf%=Bߔ}C}Ev{4ʷjc?O d'Ѽ-c3:WcW<\PjȵwR0aX:ed< ]dd.;95ˬ 1%xtd i d{8sBؾSkw7m(B9lٞO~0&n&--9@Tۘi-e|<YvEDxFYs ߖ9'$r46l32;ґITMUW t ML<d>xse!2Xōl>L>^OMu*8 mQDHfssx7 ?Η:+C8J՘gԕYue*1vOL6{=w'pk`ta~7;k fr p< T.];)!/wU,GڞTi;\uAܬVZeTJE`ZHA \+5r&c+)JBRV;:‚aĉ*uss;[#Or(lo;UaAD|q-N#7*.4)M']9QeA.HN z;4'L"( I_^HaAepT#*3XkM䊶q d?3{癅D!al/8."&Inen?% հ԰DԕӤU]ȣ8rGY2 99q]ZVugy#` Y7N:GJ@TX1\.]k BSup wr&ɑc#u E8ۢl֗LMV[jmd& 4?OT3 gV:#{ B ɼD@dubNpsf++Jî͎5R~΄dϜ ڻ'H0# Ur^Y&MGc@e| ogIu`[ :ѥ-hvd]]i7w\i0oIkmԢm&h]1 #}$Q E|wWw--vu="S w KڅŌڒEvmk9p"K:[ 2ElA488&81#ѼB.F3"DlRS]  ^E~PlvsFbxvWb&KK$N.Nԁ)x^ #[(*|xA>w")܆/q}Fyx+44kHwX N' !N"F6]bF0K<P\Do# LNy@$ ʞr}IE1xu F`'}v\tlyG3vsGgԭ]Jh#mO*]?} iqo5JXPZ7Sz s3ٸ2?ǮLq0d 2.gr32zT0>rI*|y.E*72')Ђj ZÝkKUw=MsK- lsu+7犰煑}ICa͇B£sdϐ[vR d}psjTZۮpj+gz8ڽֹ6ܹ$`j PʼnN8amgm*c@Ⱦ$-Yo ;ὗɽ(gQu|ducn|Yꦗمe~8KJoP=K{umYհw) lǝ͠‹Ҭ[t&%0qJIENDB`perfbook_html/img74.png0000644000175000017500000001732511672746056015246 0ustar paulmckpaulmckPNG  IHDR&KPLTEb``TRRMJK# hffvstmkkZWXXUV856KHHC@@A>>@<=wuv.*+mjk*tRNS@f8IDATx]Eʽ}'] I4b3=""P?*+뙅_ [Ec[j8Aw4{sO֗{w`{h+FQڞ&6ZyX zMϪ%{lL#+}q'*kI҆񂺛Rʈk/Rr ޞT@[*@CcRЀJ*[}/u>R^6Uô86YU7Ǽxëe%F3ܮL3hƂƤ]le;V+UBŠHkT+x x%>ZZ_K+Ah:/ҏDZoI3l+EDOÝGγ?a%~l#s(((}QmWTC<3!-rDTŭ4ν.?Jp8;,Dul8v3@mcީҽ$;SaJMհE0qr̙fYY(*UsPy+MM3N0?#>t-q*c;P [?4kt588(<=A!ڻCz:lNaX>P|.k'0w#~h~,IzAcRz?fSq3Q5oBWq~cG1.В.㔇4, BrOi] G|}uAv%u Z*ygԑ#m-z:e79 R 把eM|PxO|^Vi0$ jV?ߙরJ}B~IIBs;* |T7Q??rueUW5#ϚU]uZ|W5ʘ-_zs{Lݶnqxɟɧ7_I~XrpW3F?FfaI%,?؆õp@8jZ:U ޑ/PMPD׋/1B}ܮlPxBi$G7<(SJ?^b43 ee++[Km^3]y+f|boBSE03eldӽ+$`U26/8seUJ)^ UInJ |;j_LPPpE(O< ҇;G5Yc3III0kJB: cշEe#_pdD#6(DSlV@㻣pR4f;S%NbeX_İ4k(Q@]G | jFVV9xcWP[:^p GdQb_P>h{Tp=BKLi$co2]9X?pS5|.PMQ?IN''b r*X:J2uAH*Z o|? ĩ5p jpD6ucaÙzĪesZe$@ .ͮ+ Vatu-{pG#H>k!I92?swO =$tfyӾAZxђu@K )[(YӤJ~7Pp ^&߂S,F-|(` }p-KtAy3P Ib< t.oEx.l<ڕg݌|I 8q٩K$\兞'dp# 9\,E'OVϿv/Nq $gQ̊c)q JCH"]Ec]lcH>K`p\,:ԩ&_HWZڕ,OXۑXyhwYPXL+[Hou^qDtξPIgM0O!_|bעzM||k^SU mѣ @7@jz㋀p)(|EL׻?ެ .UIʙ1*LjTF\ͣz27k*1H)!bg7}*t'u&K  iQ}핧of&xyUz:I҃}C$ Cp[cku_UgaTUpr+rnt&U`ytSTg:%"z%rm:SZ:}|;ua˥=( lTWvN\PʯTD15c1Cͷgqvb '2c{080 ? XW?Csc@\Ӏ`T"N9(T:qҪNiu~wbSelB'Z7جSG aW : AԪVpZj"k5$ZVZ)], \2,ek A/\AƬ>׉vkfW \-Zƶ#*NTr:CSO^ ٖgZR ǽ34 #9S*`|jbN?<Ů")UlHloUO5'96d|y  _Ob=Nbe0On䨏~:#St +?њ'2;2Ni' 5Q B QLjl25OeϠ!!$"6JkdueJ_Ó 1_^f{*5 d\pki'a_nUZ4Nಡ8zVr}F9I\ΐݰ4lG vzv)gh _$&DxA&W2dObT`l56Jݍ]3LXҌ|2W_ T=0r]䢇hnS@r>mx,A&*^ -s #!1$s-G"sWp1W.{ 2[CzкiJwIqD9{[оr]*-aAO}Qjǝ ӵ{h`亥=&f \ޥm;u:8ww*H?^8![SC)Q_2ה:[~:!ZX,*;Lu#Ux@kŸDj J ;Y7eiFڟ:~s9|v#% 'luuH%~{z2xɞ;>a|Q4`TWA0sN1TA? 5`:537kؚs_'wn!m@VV@FuiqRyLV&\<<Ӱ06BgwYRŔò':ʈG*,mσ:^/Unt8G*X[-+u:Es 2:\Yݷ[-WSmae|M {IrE0/_.MGDCBt>i8R=7q)B$hÅ3SO_ v܅4iDK>(N{[F<< )`oy0N˵DwḁPT.6y}MU )`mohKۍ=odstKUh&۶MGr߷aXH%h [ gEg IIk^s)Չms\rf ]Sҡ槄~ jbsLl:] aEBƀ4 \ XLxzgQ[+ô4UD.p*[!-ʸSEӭB*PXء֊iSt=r@po/g'I8t^C02txo},ndddd\bBȕx0#$S*n SXӦUiX0H:Pi knW#X H_VhߺkdR:?&Y鶑 :t 7<}YџL]y}W oݙTem9+@gpJ>ㄢRR7#-H_wloYȘ@y5qԅ6áZõiIJ8FѽgQ]g94a d|fcP Ql&+t(]3PWbh=ǟAY˵Mn9y! ,\v'o+ Y0لɠ]߃w WW7ti}޾iN90'fZftxk vߊjxn9ꩬ~NwTYrdb+pM˙8RZxkzUD  養;I1D:}"yƛi)]ZAΌ4M )\~rX>X(wuc#N&g2'sې}@ R S$$46ZCwd%K0my$Ec+^b!÷=i^^ %[Ζ9Py@T*AxH-6+W7SY^{Lt7Rc]F4|IOjQ ;pLLO7E̜dFvݣ-r$4}_߄mJeZw ib.ld*f⻍;|9?)o"򛜗yt2!AxaGt_ܭ-NEOtqwc=73zM/>mSvpR@97ߴ'4- .T*(0z'v`݁ >T(o\{B3x`vp~u)@@tZ=SѮNzX ޮh{н+C,XC'o ~%ڕ$3t kN@PvJY\9mj g69&lSNކ?!xoڇ=dddq|X=yd iBRsYBlJ̦c IJtN$!rw>><9S͔wbx&ot51k&B+Iׯwc'4yed>eJ rzQls4kt)OZard!T#WBֲ1mX.%Ep12f\.:;9uj랕+H Rf5''z;ꀒ"xLb!v''.Rm7rӉDs90Wt]x}RtSyrF̌(pO |m{dwpsLyLCl*~m;<~ GGkM4!6i .|5}Pj(yL+eM/!"ofIENDB`perfbook_html/img50.png0000644000175000017500000002657611672746012015240 0ustar paulmckpaulmckPNG  IHDR7mQPLTE^\\\ZZMJKC@AZWWPMMFCC+'(# b``mkkXUV856iffC@@wuv.*+rppStRNS@f IDATx} 1̌ƈ4umvuO*UR;P ZizNYҟrMK)eSYƥv:XBJT?+ry'e Ӑ=US.J;|3*P)6sJ9iGuZA6J/?9;QFF!yo 'jitx94w5|?TW]NX9{7?:;ccfOp/ P: o)K~=v0.(ƅ< ӐuokexvN%E+x=mww8v 6Ic (s]T^MZ ( c9yeh4ՑAe]jC !܊JU5l&*ӽIwVoKu6iU(l;2c!OlMv>G&jekl@=Jep;/րi\eSiQ EiKUt-hbgD7T-mc,cjMJj= *h} / іf.`+tSyAx̂V0= ^-(tA4xV_l4'e4ָ 7ݒ Qx;ս]XҐ(i@h]u(ՙ;Gh0E%e@eCQ*7(΀`Cz3E.iV8wTjxYo"jDb B{@ Z~_ԼP|- 61>]5ywЪOUOzxJꢅs4UGXw +Ψo ?2L$<[).42uUٻĒfo/™|) 痭hL*#t]%̧i9ݻ|aJ| 4h^`X)``T~6讥sC%ň`r(]d/.VNJTpn[M(2\zB4ZG1B{\ ٴ&N#qdyٞY6wƆMMx݈l }UHR[hQh~%WPiޚmC= i,>^j*3iM , * G%5nplk1}vCnƆۃ?gQb|ʫdLV-=#\陏N oWX<`; ߲Lm f=Rr@!Ju\!ˇVeǷ9L%`5~2xG4xm]_-S,j ꪺAi9S&}hyW6k-pIS0ݳfZUwz5hϤM;Qu(5VNKc1Y,ΐ3 ',&\#_ Dv| z1"z辅 mN= Zߢ.T@YO@.4њ33&9[opҵmp6f  fBw탅!au}wc\ArxNsW^چiy KR6^ę"GB0၃ ?TZ8A$ǃ< +4Й?NJ;)mAZ5&B gc"52tԺkJjP=8mScTnjo3"XZ'pXĪυ륰B vI~Fzi㰢1}]zWUёifjjY')0 +U[9W2`ZVF{QT}:x{}Sy(*\8j~dt9R48BLL .t fX+ gwydX !Y!h5#QO5+x#\yc'ȈqB>B(p"T(8dj¥ Ś9Fu5:\1jtI)` thtjмo`Fb?z5[Lm`q-zraB .oD?ѴFPyXqdd9?vPke4"zF+ddJYde#eyiuK-&*yfks'W0GRyH7O(KrLqpoK.jsYus2rEHBP3XMy4WVq(ťs8Q[ .ה}+NScq'&ܡq Dd,/ך,*?S|ֆٍ Jx=/-=T/]Ou.t!6|2ZKo&n1Eޗƀ}S?9"3l*)+ue/֥A$*אcY<~/ .ꀔ1>W:l4 t֢pH*+YSG1n 1}yCֳNn}CaAfXWe=k#.E&-uNgjط+b>e^ZY MVE*='j$ɍVI'#iz^@܋x ǭt!Sg5ټht|OBQV9Ml>L@q'3ȰrWfTJQʶYo4vTxu]Lr5ƶ.Jn_G}t@3н# <4(њ,.Evޡ{e_]vu/4tFיB{'zV)c(+)z9{4Fz=7sAc*JW<6g;.8-n= k}aO }ilYh(~pzi>@35ǡ yM@!O6WЗDÑW|vjN>x}<12")J[ྜ<^p(q%S/%݅cF1|g^G:ʖLAs-mEW ̱I˳wTqD(YN 4; &+R%nYP 9xMn_  /R:~A*5(֋`5QAF(&:=؇m}h5AAH.WJ7haV~PFKM(';U`t;@O fyw#-S<hlKA)x8ɏ/dl v tzum* l[}ًy$=A8mMSQ)E;S8p0#.pxR_lP .ƉC$¹{o w] G2մi+-C[eڒ#)~lToȐbvL#)~WvaD7R?U3!Bwrń,Q#dt U!7̷(I>w|r~>=ʠk+R7d jsjR/nw 0P8өITā4b YiDN]3{JTx :EaDcQ_*>aUwv~+꾎ߊ+Fvbvz|(_cɮ(rN81pd {da3<.r腨i(A(kp*\, Tg>(YZniF9KhL2ZX>ԣĻ{e^:5ʜYoؾcğc-hb|_i'KjО/~nWwyy15Jsc?;r 6SaX:bͱ}OF7>!)d@' a"P)f*n0kܩ*rn|BmRѐk0gd~97>&+/\5#` lIvAueŕ{cpW3@Wu tb.8xJ{k⯛&sgP ўʣ=yO/g1@>[}+YNLZ'Uy'n+ܪDuK[CԦi!. %6Kd7C5q/,tx0yGU|5R;1EmSCl'6=SM)7J$ m&t 1!۶gJڴQR> . m3%EmL%r-T\RȦ=SQr r5O8˅8-#n$py1v'}A'חVo)߰[\^´7erXf>Sԑ|[WA!d7+BgAV ^B^`z͢o߲UmФY!5s58 Ƃw_Q#lj& ^>uȀr8h)e>(oPE\t?ŗr@c]R yA?Dqc'_Қٰvcss7k_a5 T"_vCY1M>79^9љM+-5l9UE ƻ#ðb+ dyemhVY yA XvT\ O%y?j*j*4l\O:}p!1J`Ry45dAc|K~*{?qk-ҘVu7MN߅ژ-Bd+r5W,8\duzcLw[ t]!t>tOc=ݏҴ29n#5:^3|\$.yTԦ8E{l/#}c}ޚ^z"-mO4;_PoCaqgs!3UVRs7( IDAT@ _Sy.T PB[7Ntr5{6NC@*}]o3zŌa<5_@ՙۍaږ ? h^-W"d(`BN ip7[^PEjEE==}}0\W,40Mb3X M4TobF k 3+eb1>>@.*`$̓?gl $DY4Eް:lC ny:LJ,I.pG 9^P{8=G Gps7QuWmNyE"l1զN척zkj?pHߺ}[.݇{nucy4xrfGSmO3b*7ɼ8#{8Kb偔u{dU\8}d4֡-sδ3lMޒ٤q\I4Gz|K p`}ّfȇ{as\ӱj#C.A msםdI,<Sng9h`7^?F@m`4>#z mXⰝ5^V i"e'~M% %zZ}ez!ٿ0Bb%۶Lz$O77Qa[;h/~QRDdEM`,#>'M2N"]hAr ]ŶMf3=$F8 m8 YjR m`|$frU.D(~}=S7}ƍÅpG7q0lлioܸdrfZm({5 [X眥3bMbs[q ox'291dc#wFM󈥞3llsUq?)3A:sc"z3ĐgxfKhd4dÔpIs5y VUJoxn6,F8uvjl7twjєm( ngqb4GٌGXu0}_H'% QQC Ԇzi֜s;5Gyw^nbʖ:(qWǍc'_IӓǏu 'C[\9A7>xy-ǿ1ox)X z߾ƍmVBM3 3#kyf݅E&Ϙ;owp { ̰څݠ";GLʘ϶>sz k7ϓ}|ʱmqn86/iRq ^taTd4']ݦzc hV=ޤ2NVǡ,> fkSP7wUf֛ u5o`c8c3@LKqҕX^},Iў\{k}*g7Nd\+Aɠ:UzoFbtuٍ7n|bOd#S=;{?IDz`+ώ8[g5Ma?qM1gΑTcR)i0L&f\̵6.MU/, ­ίy=mO"67";/m ˁS㦪}o~yFs{svOܧJOĎ+[ALV64Æalvץ[7Yo'kF'"+_^'޸ƍOBz׷^~۩S7}|yyK%ϔq.sŠ N}IyiCl<>+~9㻵Rj]̯akU[ X<U"u.v{]ƍkyrsxį ;hC~S=y:o’ ?d?ƍm4=ke]կmm~7n8!vkY#׀v9ZpʁT_' F.4 Chapter 

F.4 Chapter [*]

Quick Quiz [*].1: 
Why on earth should efficient and scalable counting be hard? After all, computers have special hardware for the sole purpose of doing counting, addition, subtraction, and lots more besides, don't they???
 
Answer:
Because the straightforward counting algorithms, for example, atomic operations on a shared counter, are slow and scale badly, as will be seen in Section [*].

Quick Quiz [*].2: 
Network-packet counting problem. Suppose that you need to collect statistics on the number of networking packets (or total number of bytes) transmitted and/or received. Packets might be transmitted or received by any CPU on the system. Suppose further that this large machine is capable of handling a million packets per second, and that there is a systems-monitoring package that reads out the count every five seconds. How would you implement this statistical counter?
 
Answer:
Hint: the act of updating the counter must be blazingly fast, but because the counter is read out only about once in five million updates, the act of reading out the counter can be quite slow. In addition, the value read out normally need not be all that accurate--after all, since the counter is updated a thousand times per millisecond, we should be able to work with a value that is within a few thousand counts of the ``true value'', whatever ``true value'' might mean in this context. However, the value read out should maintain roughly the same absolute error over time. For example, a 1% error might be just fine when the count is on the order of a million or so, but might be absolutely unacceptable once the count reaches a trillion. See Section [*].

Quick Quiz [*].3: 
Approximate structure-allocation limit problem. Suppose that you need to maintain a count of the number of structures allocated in order to fail any allocations once the number of structures in use exceeds a limit (say, 10,000). Suppose further that these structures are short-lived, that the limit is rarely exceeded, and that a ``sloppy'' approximate limit is acceptable.
 
Answer:
Hint: the act of updating the counter must be blazingly fast, but the counter is read out each time that the counter is increased. However, the value read out need not be accurate except that it absolutely must distinguish perfectly between values below the limit and values greater than or equal to the limit. See Section [*].

Quick Quiz [*].4: 
Exact structure-allocation limit problem. Suppose that you need to maintain a count of the number of structures allocated in order to fail any allocations once the number of structures in use exceeds an exact limit (say, 10,000). Suppose further that these structures are short-lived, and that the limit is rarely exceeded, that there is almost always at least one structure in use, and suppose further still that it is necessary to know exactly when this counter reaches zero, for example, in order to free up some memory that is not required unless there is at least one structure in use.
 
Answer:
Hint: the act of updating the counter must be blazingly fast, but the counter is read out each time that the counter is increased. However, the value read out need not be accurate except that it absolutely must distinguish perfectly between values between the limit and zero on the one hand, and values that either are less than or equal to zero or are greater than or equal to the limit on the other hand. See Section [*].

Quick Quiz [*].5: 
Removable I/O device access-count problem. Suppose that you need to maintain a reference count on a heavily used removable mass-storage device, so that you can tell the user when it is safe to removed the device. This device follows the usual removal procedure where the user indicates a desire to remove the device, and the system tells the user when it is safe to do so.
 
Answer:
Hint: the act of updating the counter must be blazingly fast and scalable in order to avoid slowing down I/O operations, but because the counter is read out only when the user wishes to remove the device, the counter read-out operation can be extremely slow. Furthermore, there is no need to be able to read out the counter at all unless the user has already indicated a desire to remove the device. In addition, the value read out need not be accurate except that it absolutely must distinguish perfectly between non-zero and zero values. However, once it has read out a zero value, it must act to keep the value at zero until it has taken some action to prevent subsequent threads from gaining access to the device being removed. See Section [*].

Quick Quiz [*].6: 
But doesn't the ++ operator produce an x86 add-to-memory instruction? And won't the CPU cache cause this to be atomic?
 
Answer:
Although the ++ operator could be atomic, there is no requirement that it be so. Furthermore, the ACCESS_ONCE() primitive forces most version of gcc to load the value to a register, increment the register, then store the value to memory, which is decidedly non-atomic.

Quick Quiz [*].7: 
The 8-figure accuracy on the number of failures indicates that you really did test this. Why would it be necessary to test such a trivial program, especially when the bug is easily seen by inspection?
 
Answer:
There are no trivial parallel programs, and most days I am not so sure that there are trivial sequential programs, either.

No matter how small or simple the program, if you haven't tested it, it does not work. And even if you have tested it, Murphy says there are at least a few bugs still lurking.

Furthermore, while proofs of correctness certainly do have their place, they never will replace testing, including the counttorture.h test setup used here. After all, proofs can have bugs just as easily has can programs!

Quick Quiz [*].8: 
Why doesn't the dashed line on the x axis meet the diagonal line at $y=1$?
 
Answer:
Because of the overhead of the atomic operation. The dashed line on the x axis represents the overhead of a single non-atomic increment. After all, an ideal algorithm would not only scale linearly, it would also incur no performance penalty compared to single-threaded code.

This level of idealism may seem severe, but if it is good enough for Linus Torvalds, it is good enough for you.

Quick Quiz [*].9: 
But atomic increment is still pretty fast. And incrementing a single variable in a tight loop sounds pretty unrealistic to me, after all, most of the program's execution should be devoted to actually doing work, not accounting for the work it has done! Why should I care about making this go faster?
 
Answer:
In many cases, atomic increment will in fact be fast enough for you. In those cases, you should by all means use atomic increment. That said, there are many real-world situations where more elaborate counting algorithms are required. The canonical example of such a situation is counting packets and bytes in highly optimized networking stacks, where it is all too easy to find much of the execution time going into these sorts of accounting tasks, especially on large multiprocessors.

In addition, counting provides an excellent view of the issues encountered in shared-memory parallel programs.

Quick Quiz [*].10: 
But why can't CPU designers simply ship the operation to the data, avoiding the need to circulate the cache line containing the global variable being incremented?
 
Answer:
It might well be possible to do this in some cases. However, there are a few complications:

  1. If the value of the variable is required, then the thread will be forced to wait for the operation to be shipped to the data, and then for the result to be shipped back.
  2. If the atomic increment must be ordered with respect to prior and/or subsequent operations, then the thread will be forced to wait for the operation to be shipped to the data, and for an indication that the operation completed to be shipped back.
  3. Shipping operations among CPUs will likely require more signals, which will consume more die area and more electrical power.
But what if neither of the first two conditions holds? Then you should think carefully about the algorithms discussed in Section [*], which achieve near-ideal performance on commodity hardware.

Figure: Data Flow For Global Combining-Tree Atomic Increment
\resizebox{3in}{!}{\includegraphics{count/GlobalTreeInc}}

If either or both of the first two conditions hold, there is some hope for improvement. One could imagine the hardware implementing a combining tree, so that the increment requests from multiple CPUs are combined by the hardware into a single addition when the combined request reaches the hardware. The hardware could also apply an order to the requests, thus returning to each CPU the return value corresponding to its particular atomic increment. This results in instruction latency that varies as $O(log N)$, where $N$ is the number of CPUs, as shown in Figure [*].

This is a great improvement over the $O(N)$ performance of current hardware shown in Figure [*], and it is possible that hardware latencies might decrease somewhat if innovations such as three-D fabrication prove practical. Nevertheless, we will see that in some important special cases, software can do much better.

Quick Quiz [*].11: 
But doesn't the fact that C's ``integers'' are limited in size complicate things?
 
Answer:
No, because modulo addition is still commutative and associative. At least as long as you use unsigned integer. Recall that in the C standard, overflow of signed integers results in undefined behavior (never mind the fact that machines that do anything other than wrap on overflow are quite rare these days.

That said, one potential source of additional complexity arises when attempting to gather (say) a 64-bit sum from 32-bit per-thread counters. For the moment, dealing with this added complexity is left as an exercise for the reader.

Quick Quiz [*].12: 
An array??? But doesn't that limit the number of threads?
 
Answer:
It can, and in this toy implementation, it does. But it is not that hard to come up with an alternative implementation that permits an arbitrary number of threads. However, this is left as an exercise for the reader.

Quick Quiz [*].13: 
What other choice does gcc have, anyway???
 
Answer:
According to the C standard, the effects of fetching a variable that might be concurrently modified by some other thread are undefined. It turns out that the C standard really has no other choice, given that C must support (for example) eight-bit architectures which are incapable of atomically loading a long. An upcoming version of the C standard aims to fill this gap, but until then, we depend on the kindness of the gcc developers.

Quick Quiz [*].14: 
How does the per-thread counter variable in Figure [*] get initialized?
 
Answer:
The C standard specifies that the initial value of global variables is zero, unless they are explicitly initialized. So the initial value of all the instances of counter will be zero.

That said, one often takes differences of consecutive reads from statistical counters, in which case the initial value is irrelevant.

Quick Quiz [*].15: 
How is the code in Figure [*] supposed to permit more than one counter?
 
Answer:
Indeed, this toy example does not support more than one counter. Modifying it so that it can provide multiple counters is left as an exercise to the reader.

Quick Quiz [*].16: 
Why does inc_count() in Figure [*] need to use atomic instructions?
 
Answer:
If non-atomic instructions were used, counts could be lost.

Quick Quiz [*].17: 
Won't the single global thread in the function eventual() of Figure [*] be just as severe a bottleneck as a global lock would be?
 
Answer:
In this case, no. What will happen instead is that the estimate of the counter value returned by read_count() will become more inaccurate.

Quick Quiz [*].18: 
Won't the estimate returned by read_count() in Figure [*] become increasingly inaccurate as the number of threads rises?
 
Answer:
Yes. If this proves problematic, one fix is to provide multiple eventual() threads, each covering its own subset of the other threads. In even more extreme cases, a tree-like hierarchy of eventual() threads might be required.

Quick Quiz [*].19: 
Why do we need an explicit array to find the other threads' counters? Why doesn't gcc provide a per_thread() interface, similar to the Linux kernel's per_cpu() primitive, to allow threads to more easily access each others' per-thread variables?
 
Answer:
Why indeed?

To be fair, gcc faces some challenges that the Linux kernel gets to ignore. When a user-level thread exits, its per-thread variables all disappear, which complicates the problem of per-thread-variable access, particularly before the advent of user-level RCU. In contrast, in the Linux kernel, when a CPU goes offline, that CPU's per-CPU variables remain mapped and accessible.

Similarly, when a new user-level thread is created, its per-thread variables suddenly come into existence. In contrast, in the Linux kernel, all per-CPU variables are mapped and initialized at boot time, regardless of whether the corresponding CPU exists yet, or indeed, whether the corresponding CPU will ever exist.

A key limitation that the Linux kernel imposes is a compile-time maximum limit on the number of CPUs, namely, CONFIG_NR_CPUS. In contrast, in user space, there is no hard-coded upper limit on the number of threads.

Of course, both environments must deal with dynamically loaded code (dynamic libraries in user space, kernel modules in the Linux kernel), which increases the complexity of per-thread variables in both environments.

These complications make it significantly harder for user-space environments to provide access to other threads' per-thread variables. Nevertheless, such access is highly useful, and it is hoped that it will someday appear.

Quick Quiz [*].20: 
Why on earth do we need something as heavyweight as a lock guarding the summation in the function read_count() in Figure [*]?
 
Answer:
Remember, when a thread exits, its per-thread variables disappear. Therefore, if we attempt to access a given thread's per-thread variables after that thread exits, we will get a segmentation fault. The lock coordinates summation and thread exit, preventing this scenario.

Of course, we could instead read-acquire a reader-writer lock, but Chapter [*] will introduce even lighter-weight mechanisms for implementing the required coordination.

Quick Quiz [*].21: 
Why on earth do we need to acquire the lock in count_register_thread() in Figure [*]? It is a single properly aligned machine-word store to a location that no other thread is modifying, so it should be atomic anyway, right?
 
Answer:
This lock could in fact be omitted, but better safe than sorry, especially given that this function is executed only at thread startup, and is therefore not on any critical path. Now, if we were testing on machines with thousands of CPUs, we might need to omit the lock, but on machines with ``only'' a hundred or so CPUs, no need to get fancy.

Quick Quiz [*].22: 
Fine, but the Linux kernel doesn't have to acquire a lock when reading out the aggregate value of per-CPU counters. So why should user-space code need to do this???
 
Answer:
Remember, the Linux kernel's per-CPU variables are always accessible, even if the corresponding CPU is offline -- even if the corresponding CPU never existed and never will exist.

Figure: Per-Thread Statistical Counters With Lockless Summation
\begin{figure}{ \scriptsize
\begin{verbatim}1 long __thread counter = 0;
2 l...
...nt < nthreadsexpected)
37 poll(NULL, 0, 1);
38 }\end{verbatim}
}\end{figure}

One workaround is to ensure that each thread sticks around until all threads are finished, as shown in Figure [*]. Analysis of this code is left as an exercise to the reader, however, please note that it does not fit well into the counttorture.h counter-evaluation scheme. (Why not?) Chapter [*] will introduce synchronization mechanisms that handle this situation in a much more graceful manner.

Quick Quiz [*].23: 
What fundamental difference is there between counting packets and counting the total number of bytes in the packets, given that the packets vary in size?
 
Answer:
When counting packets, the counter is only incremented by the value one. On the other hand, when counting bytes, the counter might be incremented by largish numbers.

Why does this matter? Because in the increment-by-one case, the value returned will be exact in the sense that the counter must necessarily have taken on that value at some point in time, even if it is impossible to say precisely when that point occurred. In contrast, when counting bytes, two different threads might return values that are inconsistent with any global ordering of operations.

To see this, suppose that thread 0 adds the value three to its counter, thread 1 adds the value five to its counter, and threads 2 and 3 sum the counters. If the system is ``weakly ordered'' or if the compiler uses aggressive optimizations, thread 2 might find the sum to be three and thread 3 might find the sum to be five. The only possible global orders of the sequence of values of the counter are 0,3,8 and 0,5,8, and neither order is consistent with the results obtained.

If you missed this one, you are not alone. Michael Scott used this question to stump Paul McKenney during Paul's Ph.D. defense.

Quick Quiz [*].24: 
Given that the reader must sum all the threads' counters, this could take a long time given large numbers of threads. Is there any way that the increment operation can remain fast and scalable while allowing readers to also enjoy reasonable performance and scalability?
 
Answer:
One approach would be to maintain a global approximation to the value. Readers would increment their per-thread variable, but when it reached some predefined limit, atomically add it to a global variable, then zero their per-thread variable. This would permit a tradeoff between average increment overhead and accuracy of the value read out.

The reader is encouraged to think up and try out other approaches, for example, using a combining tree.

Quick Quiz [*].25: 
What is with the strange form of the condition on line 3 of Figure [*]? Why not the following more intuitive form of the fastpath?



  3 if (counter + delta <= countermax){
  4   counter += delta;
  5   return 1;
  6 }



 
Answer:
Two words. ``Integer overflow.''

Try the above formulation with counter equal to 10 and delta equal to ULONG_MAX. Then try it again with the code shown in Figure [*].

A good understanding of integer overflow will be required for the rest of this example, so if you have never dealt with integer overflow before, please try several examples to get the hang of it. Integer overflow can sometimes be more difficult to get right than parallel algorithms!

Quick Quiz [*].26: 
Why do globalize_count() to zero the per-thread variables, only to later call balance_count() to refill them in Figure [*]? Why not just leave the per-thread variables non-zero?
 
Answer:
That is in fact what an earlier version of this code did. But addition and subtraction are extremely cheap, and handling all of the special cases that arise is quite complex. Again, feel free to try it yourself, but beware of integer overflow!

Quick Quiz [*].27: 
Given that globalreserve counted against us in add_count(), why doesn't it count for us in sub_count() in Figure [*]?
 
Answer:
The globalreserve variable tracks the sum of all threads' countermax variables. The sum of these threads' counter variables might be anywhere from zero to globalreserve. We must therefore take a conservative approach, assuming that all threads' counter variables are full in add_count() and that they are all empty in sub_count().

But remember this question, as we will come back to it later.

Quick Quiz [*].28: 
Why have both add_count() and sub_count() in Figure [*]? Why not simply pass a negative number to add_count()?
 
Answer:
Given that add_count() takes an unsigned long as its argument, it is going to be a bit tough to pass it a negative number. And unless you have some anti-matter memory, there is little point in allowing negative numbers when counting the number of structures in use!

Quick Quiz [*].29: 
In what way does line 7 of Figure [*] violate the C standard?
 
Answer:
It assumes eight bits per byte. This assumption does hold for all current commodity microprocessors that can be easily assembled into shared-memory multiprocessors, but certainly does not hold for all computer systems that have ever run C code. (What could you do instead in order to comply with the C standard? What drawbacks would it have?)

Quick Quiz [*].30: 
Given that there is only one counterandmax variable, why bother passing in a pointer to it on line 18 of Figure [*]?
 
Answer:
There is only one counterandmax variable per thread. Later, we will see code that needs to pass other threads' counterandmax variables to split_counterandmax().

Quick Quiz [*].31: 
Why does merge_counterandmax() in Figure [*] return an int rather than storing directly into an atomic_t?
 
Answer:
Later, we will see that we need the int return to pass to the atomic_cmpxchg() primitive.

Quick Quiz [*].32: 
Yecch! Why the ugly goto on line 11 of Figure [*]? Haven't you heard of the break statement???
 
Answer:
Replacing the goto with a break would require keeping a flag to determine whether or not line 15 should return, which is not the sort of thing you want on a fastpath. If you really hate the goto that much, your best bet would be to pull the fastpath into a separate function that returned success or failure, with ``failure'' indicating a need for the slowpath. This is left as an exercise for goto-hating readers.

Quick Quiz [*].33: 
Why would the atomic_cmpxchg() primitive at lines 13-14 of Figure [*] ever fail? After all, we picked up its old value on line 9 and have not changed it!
 
Answer:
Later, we will see how the flush_local_count() function in Figure [*] might update this thread's counterandmax variable concurrently with the execution of the fastpath on lines 8-14 of Figure [*].

Quick Quiz [*].34: 
What stops a thread from simply refilling its counterandmax variable immediately after flush_local_count() on line 14 of Figure [*] empties it?
 
Answer:
This other thread cannot refill its counterandmax until the caller of flush_local_count() releases the gblcnt_mutex. By that time, the caller of flush_local_count() will have finished making use of the counts, so there will be no problem with this other thread refilling -- assuming that the value of globalcount is large enough to permit a refill.

Quick Quiz [*].35: 
What prevents concurrent execution of the fastpath of either atomic_add() or atomic_sub() from interfering with the counterandmax variable while flush_local_count() is accessing it on line 27 of Figure [*] empties it?
 
Answer:
Nothing. Consider the following three cases:

  1. If flush_local_count()'s atomic_xchg() executes before the split_counterandmax() of either fastpath, then the fastpath will see a zero counter and countermax, and will thus transfer to the slowpath (unless of course delta is zero).
  2. If flush_local_count()'s atomic_xchg() executes after the split_counterandmax() of either fastpath, but before that fastpath's atomic_cmpxchg(), then the atomic_cmpxchg() will fail, causing the fastpath to restart, which reduces to case 1 above.
  3. If flush_local_count()'s atomic_xchg() executes after the atomic_cmpxchg() of either fastpath, then the fastpath will (most likely) complete successfully before flush_local_count() zeroes the thread's counterandmax variable.
Either way, the race is resolved correctly.

Quick Quiz [*].36: 
Given that the atomic_set() primitive does a simple store to the specified atomic_t, how can line 53 of balance_count() in Figure [*] work correctly in face of concurrent flush_local_count() updates to this variable?
 
Answer:
The caller of both balance_count() and flush_local_count() hold gblcnt_mutex, so only one may be executing at a given time.

Quick Quiz [*].37: 
But signal handlers can be migrated to some other CPU while running. Doesn't this possibility require that atomic instructions and memory barriers are required to reliably communicate between a thread and a signal handler that interrupts that thread?
 
Answer:
No. If the signal handler is migrated to another CPU, then the interrupted thread is also migrated along with it.

Quick Quiz [*].38: 
In Figure [*], why is the REQ theft state colored blue?
 
Answer:
To indicate that only the fastpath is permitted to change the theft state.

Quick Quiz [*].39: 
In Figure [*], what is the point of having separate REQ and ACK theft states? Why not simplify the state machine by collapsing them into a single state? Then whichever of the signal handler or the fastpath gets there first could set the state to READY.
 
Answer:
Reasons why collapsing the REQ and ACK states would be a very bad idea include:

  1. The slowpath uses the REQ and ACK states to determine whether the signal should be retransmitted. If the states were collapsed, the slowpath would have no choice but to send redundant signals, which would have the unhelpful effect of slowing down the fastpath.
  2. The following race would result:
    1. The slowpath sets a given thread's state to REQACK.
    2. That thread has just finished its fastpath, and notes the REQACK state.
    3. The thread receives the signal, which also notes the REQACK state, and, because there is no fastpath in effect, sets the state to READY.
    4. The slowpath notes the READY state, steals the count, and sets the state to IDLE, and completes.
    5. The fastpath sets the state to READY, disabling further fastpath execution for this thread.
    The basic problem here is that the combined REQACK state can be referenced by both the signal handler and the fastpath. The clear separation maintained by the four-state setup ensures orderly state transitions.
That said, you might well be able to make a three-state setup work correctly. If you do succeed, compare carefully to the four-state setup. Is the three-state solution really preferable, and why or why not?

Quick Quiz [*].40: 
In Figure [*] function flush_local_count_sig(), why are there ACCESS_ONCE() wrappers around the uses of the theft per-thread variable?
 
Answer:
The first one (on line 11) can be argued to be unnecessary. The last two (lines 14 and 16) are important. If these are removed, the compiler would be within its rights to rewrite lines 14-17 as follows:

 14   theft = THEFT_READY;
 15   if (counting) {
 16     theft = THEFT_ACK;
 17   }


This would be fatal, as the slowpath might see the transient value of THEFT_READY, and start stealing before the corresponding thread was ready.

Quick Quiz [*].41: 
In Figure [*], why is it safe for line 28 to directly access the other thread's countermax variable?
 
Answer:
Because the other thread is not permitted to change the value of its countermax variable unless it holds the gblcnt_mutex lock. But the caller has acquired this lock, so it is not possible for the other thread to hold it, and therefore the other thread is not permitted to change its countermax variable. We can therefore safely access it -- but not change it.

Quick Quiz [*].42: 
In Figure [*], why doesn't line 33 check for the current thread sending itself a signal?
 
Answer:
There is no need for an additional check. The caller of flush_local_count() has already invoked globalize_count(), so the check on line 28 will have succeeded, skipping the later pthread_kill().

Quick Quiz [*].43: 
The code in Figure [*], works with gcc and POSIX. What would be required to make it also conform to the ISO C standard?
 
Answer:
The theft variable must be of type sig_atomic_t to guarantee that it can be safely shared between the signal handler and the code interrupted by the signal.

Quick Quiz [*].44: 
In Figure [*], why does line 41 resend the signal?
 
Answer:
Because many operating systems over several decades have had the property of losing the occasional signal. Whether this is a feature or a bug is debatable, but irrelevant. The obvious symptom from the user's viewpoint will not be a kernel bug, but rather a user application hanging.

Your user application hanging!

Quick Quiz [*].45: 
What if you want an exact limit counter to be exact only for its lower limit?
 
Answer:
One simple solution is to overstate the upper limit by the desired amount. The limiting case of such overstatement results in the upper limit being set to the largest value that the counter is capable of representing.

Quick Quiz [*].46: 
What else had you better have done when using a biased counter?
 
Answer:
You had better have set the upper limit to be large enough accommodate the bias, the expected maximum number of accesses, and enough ``slop'' to allow the counter to work efficiently even when the number of accesses is at its maximum.

Quick Quiz [*].47: 
This is ridiculous! We are read-acquiring a reader-writer lock to update the counter? What are you playing at???
 
Answer:
Strange, perhaps, but true! Almost enough to make you think that the name ``reader-writer lock'' was poorly chosen, isn't it?

Quick Quiz [*].48: 
What other issues would need to be accounted for in a real system?
 
Answer:
A huge number!

Here are a few to start with:

  1. There could be any number of devices, so that the global variables are inappropriate, as are the lack of arguments to functions like do_io().
  2. Polling loops can be problematic in real systems. In many cases, it is far better to have the last completing I/O wake up the device-removal thread.
  3. The I/O might fail, and so do_io() will likely need a return value.
  4. If the device fails, the last I/O might never complete. In such cases, there might need to be some sort of timeout to allow error recovery.
  5. Both add_count() and sub_count() can fail, but their return values are not checked.
  6. Reader-writer locks do not scale well. One way of avoiding the high read-acquisition costs of reader-writer locks is presented in Chapter [*].

Quick Quiz [*].49: 
On the count_stat.c row of Table [*], we see that the update side scales linearly with the number of threads. How is that possible given that the more threads there are, the more per-thread counters must be summed up?
 
Answer:
The read-side code must scan the entire fixed-size array, regardless of the number of threads, so there is no difference in performance. In contrast, in the last two algorithms, readers must do more work when there are more threads. In addition, the last two algorithms interpose an additional level of indirection because they map from integer thread ID to the corresponding __thread variable.

Quick Quiz [*].50: 
Even on the last row of Table [*], the read-side performance of these statistical counter implementations is pretty horrible. So why bother with them?
 
Answer:
``Use the right tool for the job.''

As can be seen from Figure [*], single-variable atomic increment need not apply for any job involving heavy use of parallel updates. In contrast, the algorithms shown in Table [*] do an excellent job of handling update-heavy situations. Of course, if you have a read-mostly situation, you should use something else, for example, a single atomically incremented variable that can be read out using a single load.

Quick Quiz [*].51: 
Given the performance data shown in Table [*], we should always prefer update-side signals over read-side atomic operations, right?
 
Answer:
That depends on the workload. Note that you need a million readers (with roughly a 40-nanosecond performance gain) to make up for even one writer (with almost a 40-millisecond performance loss). Although there are no shortage of workloads with far greater read intensity, you will need to consider your particular workload.

In addition, although memory barriers have historically been expensive compared to ordinary instructions, you should check this on the specific hardware you will be running. The properties of computer hardware do change over time, and algorithms must change accordingly.

Quick Quiz [*].52: 
Can advanced techniques be applied to address the lock contention for readers seen in Table [*]?
 
Answer:
There are a number of ways one might go about this, and these are left as exercises for the reader.

Quick Quiz [*].53: 
The ++ operator works just fine for 1,000-digit numbers! Haven't you heard of operator overloading???
 
Answer:
In the C++ language, you might well be able to use ++ on a 1,000-digit number, assuming that you had access to a class implementing such numbers. But as of 2010, the C language does not permit operator overloading.

Quick Quiz [*].54: 
But if we are going to have to partition everything, why bother with shared-memory multithreading? Why not just partition the problem completely and run as multiple processes, each in its own address space?
 
Answer:
Indeed, multiple processes with separate address spaces can be an excellent way to exploit parallelism, as the proponents of the fork-join methodology and the Erlang language would be very quick to tell you. However, there are also some advantages to shared-memory parallelism:

  1. Only the most performance-critical portions of the application must be partitioned, and such portions are usually a small fraction of the application.
  2. Although cache misses are quite slow compared to individual register-to-register instructions, they are typically considerably faster than inter-process-communication primitives, which in turn are considerably faster than things like TCP/IP networking.
  3. Shared-memory multiprocessors are readily available and quite inexpensive, so, in stark contrast to the 1990s, there is little cost penalty for use of shared-memory parallelism.
As always, use the right tool for the job!

Paul E. McKenney 2011-12-16
perfbook_html/node122.html0000644000175000017500000001546311672746162015650 0ustar paulmckpaulmck 10.2.2 Linux Primitives Supporting Reference Counting


10.2.2 Linux Primitives Supporting Reference Counting

The Linux-kernel primitives used in the above examples are summarized in the following list. The RCU primitives may be unfamiliar to some readers, so a brief overview with citations is included in Section [*].

  • atomic_t   Type definition for 32-bit quantity to be manipulated atomically.
  • void atomic_dec(atomic_t *var);   Atomically decrements the referenced variable without necessarily issuing a memory barrier or disabling compiler optimizations.
  • int atomic_dec_and_test(atomic_t *var);   Atomically decrements the referenced variable, returning true if the result is zero. Issues a memory barrier and disables compiler optimizations that might otherwise move memory references across this primitive.
  • void atomic_inc(atomic_t *var);   Atomically increments the referenced variable without necessarily issuing a memory barrier or disabling compiler optimizations.
  • int atomic_inc_not_zero(atomic_t *var);   Atomically increments the referenced variable, but only if the value is non-zero, and returning true if the increment occurred. Issues a memory barrier and disables compiler optimizations that might otherwise move memory references across this primitive.
  • int atomic_read(atomic_t *var);   Returns the integer value of the referenced variable. This is not an atomic operation, and it neither issues memory barriers nor disables compiler optimizations.
  • void atomic_set(atomic_t *var, int val);   Sets the value of the referenced atomic variable to ``val''. This is not an atomic operation, and it neither issues memory barriers nor disables compiler optimizations.
  • void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head));   Invokes func(head) some time after all currently executing RCU read-side critical sections complete, however, the call_rcu() primitive returns immediately. Note that head is normally a field within an RCU-protected data structure, and that func is normally a function that frees up this data structure. The time interval between the invocation of call_rcu() and the invocation of func is termed a ``grace period''. Any interval of time containing a grace period is itself a grace period.
  • type *container_of(p, type, f);   Given a pointer ``p'' to a field ``f'' within a structure of the specified type, return a pointer to the structure.
  • void rcu_read_lock(void);   Marks the beginning of an RCU read-side critical section.
  • void rcu_read_unlock(void);   Marks the end of an RCU read-side critical section. RCU read-side critical sections may be nested.
  • void smp_mb__before_atomic_dec(void);   Issues a memory barrier and disables code-motion compiler optimizations only if the platform's atomic_dec() primitive does not already do so.
  • struct rcu_head   A data structure used by the RCU infrastructure to track objects awaiting a grace period. This is normally included as a field within an RCU-protected data structure.

Paul E. McKenney 2011-12-16
perfbook_html/node229.html0000644000175000017500000001144211672746162015651 0ustar paulmckpaulmck 14.2.11 Locking Constraints


14.2.11 Locking Constraints

As noted earlier, locking primitives contain implicit memory barriers. These implicit memory barriers provide the following guarantees:

  1. LOCK operation guarantee:
    • Memory operations issued after the LOCK will be completed after the LOCK operation has completed.
    • Memory operations issued before the LOCK may be completed after the LOCK operation has completed.
  2. UNLOCK operation guarantee:
    • Memory operations issued before the UNLOCK will be completed before the UNLOCK operation has completed.
    • Memory operations issued after the UNLOCK may be completed before the UNLOCK operation has completed.
  3. LOCK vs LOCK guarantee:
    • All LOCK operations issued before another LOCK operation will be completed before that LOCK operation.
  4. LOCK vs UNLOCK guarantee:
    • All LOCK operations issued before an UNLOCK operation will be completed before the UNLOCK operation.
    • All UNLOCK operations issued before a LOCK operation will be completed before the LOCK operation.
  5. Failed conditional LOCK guarantee:
    • Certain variants of the LOCK operation may fail, either due to being unable to get the lock immediately, or due to receiving an unblocked signal or exception whilst asleep waiting for the lock to become available. Failed locks do not imply any sort of barrier.

Paul E. McKenney 2011-12-16
perfbook_html/node375.html0000644000175000017500000001532511672746163015660 0ustar paulmckpaulmck D.3.3 Initialization


D.3.3 Initialization

Figure: Initialized RCU Data Layout
\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeInit}}

This section walks through the initialization code, which links the main data structures together as shown in Figure [*]. The yellow region represents fields in the rcu_state data structure, including the ->node array, individual elements of which are shown in pink, matching the convention used in Section [*]. The blue boxes each represent one rcu_data structure, and the group of blue boxes makes up a set of per-CPU rcu_data structures.

The ->levelcnt[] array is initialized at compile time, as is ->level[0], but the rest of the values and pointers are filled in by the functions described in the following sections. The figure shows a two-level hierarchy, but one-level and three-level hierarchies are possible as well. Each element of the ->levelspread[] array gives the number of children per node at the corresponding level of the hierarchy. In the figure, therefore, the root node has two children and the nodes at the leaf level each have three children. Each element of the levelcnt[] array indicates how many nodes there are on the corresponding level of the hierarchy: 1 at the root level, 2 at the leaf level, and 6 at the rcu_data level--and any extra elements are unused and left as zero. Each element of the ->level[] array references the first node of the corresponding level of the rcu_node hierarchy, and each element of the ->rda[] array references the corresponding CPU's rcu_data structure. The ->parent field of each rcu_node structure references its parent, except for the root rcu_node structure, which has a NULL ->parent pointer. Finally, the ->mynode field of each rcu_data structure references its parent rcu_node structure.

Quick Quiz D.33: How does the code traverse a given path through the rcu_node hierarchy from root to leaves? End Quick Quiz

Again, the following sections walk through the code that builds this structure.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node413.html0000644000175000017500000002031511672746163015644 0ustar paulmckpaulmck D.4.2.3.1 Grace-Period State Machine Overview


D.4.2.3.1 Grace-Period State Machine Overview

The state (recorded in rcu_try_flip_state) can take on the following values:

  • rcu_try_flip_idle_state: the grace-period state machine is idle due to there being no RCU grace-period activity. The rcu_ctrlblk.completed grace-period counter is incremented upon exit from this state, and all of the per-CPU rcu_flip_flag variables are set to rcu_flipped.
  • rcu_try_flip_waitack_state: waiting for all CPUs to acknowledge that they have seen the previous state's increment, which they do by setting their rcu_flip_flag variables to rcu_flip_seen. Once all CPUs have so acknowledged, we know that the old set of counters can no longer be incremented.
  • rcu_try_flip_waitzero_state: waiting for the old counters to sum to zero. Once the counters sum to zero, all of the per-CPU rcu_mb_flag variables are set to rcu_mb_needed.
  • rcu_try_flip_waitmb_state: waiting for all CPUs to execute a memory-barrier instruction, which they signify by setting their rcu_mb_flag variables to rcu_mb_done. Once all CPUs have done so, all CPUs are guaranteed to see the changes made by any RCU read-side critical section that started before the beginning of the corresponding grace period, even on weakly ordered machines.

Figure: Preemptible RCU State Machine
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptStates}}

The grace period state machine cycles through these states sequentially, as shown in Figure [*].

Figure: Preemptible RCU State Machine Timeline
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptTimeline}}

Figure [*] shows how the state machine operates over time. The states are shown along the figure's left-hand side and the relevant events are shown along the timeline, with time proceeding in the downward direction. We will elaborate on this figure when we validate the algorithm in a later section.

In the meantime, here are some important things to note:

  1. The increment of the rcu_ctrlblk.completed counter might be observed at different times by different CPUs, as indicated by the blue oval. However, after a given CPU has acknowledged the increment, it is required to use the new counter. Therefore, once all CPUs have acknowledged, the old counter can only be decremented.
  2. A given CPU advances its callback lists just before acknowledging the counter increment.
  3. The blue oval represents the fact that memory reordering might cause different CPUs to see the increment at different times. This means that a given CPU might believe that some other CPU has jumped the gun, using the new value of the counter before the counter was actually incremented. In fact, in theory, a given CPU might see the next increment of the rcu_ctrlblk.completed counter as early as the last preceding memory barrier. (Note well that this sentence is very imprecise. If you intend to do correctness proofs involving memory barriers, please see Appendix [*].
  4. Because rcu_read_lock() does not contain any memory barriers, the corresponding RCU read-side critical sections might be reordered by the CPU to follow the rcu_read_unlock(). Therefore, the memory barriers are required to ensure that the actions of the RCU read-side critical sections have in fact completed.
  5. As we will see, the fact that different CPUs can see the counter flip happening at different times means that a single trip through the state machine is not sufficient for a grace period: multiple trips are required.

Paul E. McKenney 2011-12-16
perfbook_html/img278.png0000644000175000017500000001675511672746112015333 0ustar paulmckpaulmckPNG  IHDRKyD"S.Q4+_+&:ԪF+Vt6EnB7ZT8d%WZ4fwIrwwuq˒Rl  E#&[%` cl kz?qG+m8 =b疰o!pS~!=.%`6!C4cD1.:{P:5i(]e -ֻ$KJWkMf@{KbUQtgD_O\|ܯG%OUOV훊(@ezP*@+ :Uj(HT8;mf03v:;(Ɔ.,)cmNCZk߉#:@ bYN(N:W'"T7p[Fփc\;oR -.^-c ^useDgq1#w)#4˱@ w'A R2JyGtxOz5=D_{-S &zDtj&]'9/m&:E↾=Cl[R#mI='ے_kKB:I>%%(xEc|Ln]<[x}<:O#y]U.sj\iq ya3xo.bl'Ǫg5 /*|tzF2m P7 i?!2iƌhfnYG4?iWi4M4mo'п# aQ@q q \u#-ïҺ1VwxMQ%+Mӈ&"KLb-$}9,BܞVg jyFG6P M=L!Hk =7Zpf:҄/V7ַZ[0ejH`uxly|6i=i"tfՓ&!o_!jR e."5&2RHڃ )Br<g PFP."0z '`]^ tfVբ/v:O 9@юM,+_;iljvB$Γm'D aoqj`2yŒS) S,QyMe!G.7~8:Q* P_J¤9G~=*MXqfJn%Ls`ހudQ(wM+|?C`E0xd{NHʺv !؞CrֶQ7|S}搭-]#j% ݤM۬nn?+$iRI?&Jyl2Ӵ8$Go7)$IdRHѵO*$U-$3dqB/OZH1 i'aiS,kT,{h\w9/Bﱩ>v pQѻT\7.=eɥ@&=NY6l &/}(LUA^GcYͨ]ÆG{o"!8_֒ÿ<gcYLJY0շE,w*zrek,u(;Ř[&.}IBzV} eET QW*>:PND#zͦ 1OSIDC[?nbW,O@?0ABBܫ$`iYe44%Dg);e Jȩ$` eiE;~ ArOM%6Ӕe4CY"ZI`5ddO=N(%e&6|TZĬV^AwaCLS/KsRԍtbb V 6|0g_LkJHS;H);>kVd&`ft:3vC!PŦL-x(lڔe o R,}C8A`e (̪xjuKC, aeU9:CfXֹ&t'5C%6K$pxܴX.!-1- YbreY`s[- ˘+_Q)6n> N0+0G_MFBzQ(Qy]d]߉,]|g|nWJtmD f9_"ie- V^KQA0d(AV0=5L7OADZ~w+~H ] ,W)o`T,d-K1u"6 ,Mq8u~ UYSCWpA`gMJL 5uiD>>,dYSeՉ6BQ"_Y 5ܯ!j.O[nt}j8QWXVlkPq ÓfA:?eZyS),57rH3Q2&Ͱx,+ޞ 81y,ݱeԨM ]КT㭲DtE 3(8Tdzlb_>.hAX#0o/{Y$R9^A`;ꪢG`c o,wLeYh Rs LzaP)kOrԶBlO㶖n2AB?tG?>?n D&+BէMdt؉Ct9-%[H&(|V_2qL1Ndm0?lu;Bu[k{n]qcb鐣1d%[Ӄ=+9?G¬*4 ,KwpX c@̘oDM!Y!6&*XaZ})C9*˧hE}0-r42,a;!5Ce<ܹ_Yn`4gDSqYhյMh+t7Dh,9 rh$Mm]~1~O4Ɖ,Zl-en&jo?jm2͖MMF&ͳ6WqcAg~&qvr[66z8,Eܴk9nlΚR Qn9/p1TFbNw,\`b]͚"r Y :FFYq? Qey0gYF@K,, tiIu"r {֏Oe=ǧȲ\žSdY.AaE_k%pB?8w ^uc_@Hǟ\O(E[M+iZ|XMJru,m`U.C+Y݆nGv#PeяB4kW }ƅ^BQ2ve99c ۨDm@/mB6TQ!r;r*~;-K%+ue&@} $K6QI$l'w**j$:vM%u4>,j+<} y YQDeYP0pβ9f0(.\_&CҞVF+K~ht˲۟p>~Hug|?*NrWƍDzGDY?F{s+&dy1Yjya3(|3W܌lFXͽlsg6ͽlg=(b,M͒KN7m"뱬[6jloDbYl]\(?iXxȱ0eEYW1IJfY^$5"ƱYW0eͲ,x~xOgfO43D3\s;gO ;;g&|`Mםug&FH=͡S&6ko j~&B7d6ѥug[6Ѣ,&ԏo͝-Gm,rh΢"!2,! ,]Tg,%\idz((dY\gYey V% /j5{(\ì8YeYeY{""CC/As= ' -쒥M& '-.ODc^oyH6` d-diyDzuCBm0.k 75=Q+Ĭyb./XӛrC.8E%p-?ү!"efY^3,%y?hb,+:5ue5WJ_8(k5cQgZ>XȲ #b#1_p6QDOLK8jeQnMe(p,_p"r8/8c |'3L ~IENDB`perfbook_html/img65.png0000644000175000017500000001026111672746073015235 0ustar paulmckpaulmckPNG  IHDRWXJPLTE@!""$8D6SfUUDD33!!s;fflf4U݌VV33N*3'-EUwwfAAQ}  wcZ.ݿaU3M'Hff"A33aaHoUUD++Z[wwDD~wLL" ""?aẃfuwwD ll"U66WetRNS@fKIDATx] CL6x&(rQE Y of7! `%t_&$L&pQ}WUQ;wշ}Mux_}'&%WWSVJ8Xs@ígxN_]8oldkEt|VA)mFUxjtn}āmB%4?X_E)@Xsq>x;}Ϡڠݷ65U{/k< gd6ff粕Ol%;YX8U L*ų*_ Ou \X U|_mk 6|Z9Nn@:&0v2W.,]] +KH`Z'$fhP_ [VU`O'|H lqpd)]` &8eq#+&Rt5TZW,dgybL . :ZJdd;FvKfFy3X0xu~`g>+ F*$rE`Ml-U'eY0|ϰnKY zJvf#^YݪaCmL1zۀR,{`chHjDB׏d*l O >!D )ҡ3}ߐuٗ?tKٱ#[-r ng\6?,z5FWƴ`c\&Y Tp8KڑkHd?H/)nUp+U W\T.LS':.`nlJTj`@>l?}׺ڧtZZNz4=aؗfc\JFvT >\}bW t42042j?XCEYweqUqɵ5T=*rvP\*<3ٸƧ (\oT@kև>R mDir_{\ N{LWͯ_}Dy~R + 8ζ?j+j@`h*ͽ/@ r%ȳ+q[8:m3ԞZ\=ν eϢǟ`n@\/laVEki2ZNQ|K-8JifJ(`:VKn%:e4ȑg%ɵ\VAcB*pˇY$/А$-[\)-d, RvT<-s%d_SĥXցm"hI-䊩kp] .D~ 9k>_/(_U3}ǁufuŁ vpUywׁs_#&8qu3jTLjtF@p{x<ܞ q5#Y,`f Purx\3AĸK\VjRmNNrC溡.6@ǩJ++j:وmbVa6 a觌G$;ו A4"\g#ƀͰkmeQZ!I`CcUTq%z՛'/ft\W4o0^[3FŹNZ\y59L+ 4:Uມ.4#,J#7(pRהK4zظ]ib1\/$fBi*zgsr%F iְqf&L i,u\)zYnp#Oy:= ]BWǺ]m*B\4l#T?B{ۦwʷU<6=^[ v;` -7.]}> -y#!&B+lͧGZvխ+,[j8YԸL4[ʍJ ]2@تTBs`bk7BWu_[ə޺j[q_wC|\W!jk9"~Q0_ASVU#֑'zOׁ'^zy"W_Cyb>oA]ȳBWU*t ]Ե^5kC^&{uZR5P^(ku5NmHo{u]:`sՒ.u6~ ?t.89t FJ:_[kuiߒجu.Ϊ[ݻetu]EY!zWF] ;| uB1]J07;!CK_D_VsW |N8jzhE}o :uDsJ `Zpdfe#寗TN@N/_̚l4"?T%g_uFI_udo VE`ְ?'GEl BrjEyvTe'%֣{uefau&So*W͇ Q>8y۝A&B,:hԵȳB׷;duŋޏ2Rzx>4%]=0e_ &yBW@Y=]]]՛bēOTc[$ ͯQmaS"ϕX!O7=ی=~3^;ovo2Q'dvc6J>Zoh#E" ~Ue-*T Feo?K=D-|~@kYpE"nz[~DX/Wl{*W=t\݊QuCmTDD"ڞyVH7_E+Hm٭+zh_m,)Qn]֐W8ɭe1Wuٳ; $i%@cѪi[$JA,)T]vx-),{ J>A' ?B `KCPfw>5)3 ;c]mPk|'PP1tpLCcSEVAUZX=ǓnT]ž"xQė(4+e?Mo >.HT~1w`:;V=>IcAag)ua,4p?:M#hGd753p[4. ɻy3spb\}Lp;JggQw'CIџ.{-ͶߊTAW$15\GtW=khzw7vp|"v 1e>V..;F8Tjig {a1d`SX<VwsOJxQ9oj㨔m `:`?( Na=Vy'$$N[K.IR@cKQ_ʩUU3.~wܽr*'AC[6rJp{dy8ŲÌlpp`D"4,xѝa7Ey$[$}h%9)2vSq<~K-f8^IgI#ze:|=Mtu5[d$Au<-JԾXک!٩Dp%ﭙ`v3.U5!R-ܦlr+aڳT. YQdDK틅[^ҴjTP[8.6c=*'FW`J!@wX`n:nHdM)kR%|9qAXlREl:י{Re;`i9uCRCZ*ѳC(wcnJgmXt,;odhui~þ.sqNpbӡ%&]M; I&KQ>g<ϥo^2@Y$>gOHfska'p^-$\*6_w3Wkc[J B&4N5^Wm0p̄t9;~@4]|=E0Nutk-'YJD}mct,aBQd݅yNϩwׯ_uG߅Vfˍ]qj)G,&RE7*iVKQ|HU45-EL,`1)p.Uqd]DN2\|Hۖ7ܬ *rn$- lgs*+EDS5~̎{|Iπ>\Fss+9\.9|>[jFird: fu%b"m2*Ö6rhuR:@ZAG{?N6|+!UH&.txw*fr#nɺ`qƓ|Z?u9K6gLoHTw]~ҦiP^`:կ>('x5<K4}@v 'a2#-+jKnr -a'N|!d! @+i~:Lz/&'N8Uh /*~CwU[mZSJUp 0. C=Xs$C4XU}~-ZAO5k\vp6ǡQH CIե $?$kMk>pC%:ԃ2faCn%ǕG(SY(0E5JǪ@XqAC=Դ8cmzHt Ցk$;y3BvʏY1$2DZ1VQobM(Bx$NqLcnt{CMdTS^GG]R0'ם"sKE4JPzWc8Zh#7j/5kD|Q:uII-Cv\?n̥XDR"'@ėiE˰*ZX{6Mn>ӊ: 4497';ʩq04fӞɞSa.nAz0t mqw!J|E_9.#Lr#U%ў ~h>˸rێ-.rՀ y8ymд(p]=5w>28qZ'S)  Zʂa.1]C-SSR\IPk)WzNi%2%WSRr nǃZʕ/Z̟'(9\C>- 2m ~jŶ<: ^2'eXX ea[6Cs݉}[|{2W6*(<@'خhSS=nS({pMte0`Y.Mbh ܞ w'khҘ}8k':ajb C׎Ȱm>:4R:w\m ݉])Cx9|`1#AK_>=WB:qHp:H}o҄Op{`E( ㏡w+_lq|lVOTƺiS9ʮV!uZU5_COԀz?e- "[xG}o՞6xi枲Qv"N=e'~!ܧe~a84EKCmyܖ.'wu\ؠ6j)(e\32dz-%džx޽)]mgAK9n'N }U,rֵp0|9zl٤VmRonu"G{~٤qOtZ\įd6뗟+; vk/#4(*ZO'ąg"ձ=IENDB`perfbook_html/node2.html0000644000175000017500000006751311672746161015507 0ustar paulmckpaulmck Contents

Contents



Paul E. McKenney 2011-12-16
perfbook_html/img279.png0000644000175000017500000001337111672746015015325 0ustar paulmckpaulmckPNG  IHDRTcBPLTEb``MJK# hffmkkXUV856C@@wuv.*+EaqtRNS@feIDATx]FdXUw.xvk5E@D I$U2r^@tz]X(3^=۠|xLÝ-ߞpS(|P©m*Uvcr}۾s[Ҍ[[WXdj^7ʹ/q}jUkcP-Սk8~sOxuz{RrmuO2u[/+\S,W<=r/Si%\hF2cEˎ[\8uPuysÎMN'խw_zzj h6MVbs6<<%jcv_jy+5G ~ˣ4t:;ʚj|oeiviwl4[=u"mh ^<d8Q%LSLώhtHpqqA@lu+L(y`m:xoVˊpK+1; g=lǴ1 g*_LRq4+SVQ+ItpU*În g{c]}S6z=aO$;]ŋek~Yox* _PTX^o_/kIp'MR=P,MV"Rdr푻[ meww`ث}NjZ@9A# m xq-Uz=2[+\dwq8dïLَKvabU 9xk FKqA4*QbE T=@Iy~] ATqkfy7?4* ݵnecsȭK}4K)zA gdv8ecqqnB bpx1DaYٿQ NJ礡v@g|PUkY ,bH=/M2c 0\M"H@ uPj ҡeI),)?b71ny@ o$RfAE:pt@+JNA65a[:Y*ZCRm!Wsa뤚Ȩe2J' p]Q1ɾʄK.߭F2bB'eMl!2|2P$ 0tФ~&_PkQ;b VkHjG:8,lh £(q4 4) WJ4RJ(PY Q1К:շ=7׃oD!0HiP#M*R8K;{8T]bDۉPmˇj3 9JF4Sm{rDiGϘU&/=21L6j=+y `sTKuwNsD8\sn\.PWuXCqkްkmT Kõo4yW Lje mБvϦڴAaɍq^S4o?E}vʣ#g+eb ggȚۗGpnk]%'\&PXsC|SUiHQKaHU)Eaa'ehe& w+t *d]FVxx*.!{ *dhGH_"-h:18pxS+|e4lҎ2wZb S~ys 'U?f_z UJ%Ӽ,zsePfE3E lŃ1A^лj q"DaIIaH8ˋW2 {(̇%uҩֿY"WU9C?#d|TO0PVvFܑV~#=NDCPǷg!o Ҡ"*]G)F۔h?b ?U'0;N|c Sh>g@-G!NH`jY5h c*_e!_s`ƿeM^j;["ǽg%0H6UkU-&73pRv?k<{||^ڐJK~"yg &*J$gKUs$%++[s*5j7fCfBOj#?ab@C|P^ x[vdAT'RJu|=j\[|KuDh)_-/W+ks0#=  -%\gqNeZG?{'3EAňE øy7\n^$a۳ ǽgPhI J+JEGKLRU %E@y]E\`۳L eɃ,-+ Y+%9MvI䭿4sӺ|:q\gnct5\)}/ 5WX4;Hf[X`^psu q@W Y Q]GrZ%pM. R\]+Vu9P臫U@aKI1-v@!o# yu_i-Md]J)1iH˜5e$XhQ+$RC-D3zAmمp%+Rnd>BĪoF;TtżGN-r&d"^^kMA+ @O' RڛЍ̳u+kC)u`ѓc^?87Z#MY}&/'S~>@al?Gzgfs Tz UR/=@ICu,&S)[w $Q+XjIO6eY/Şܥ}WPD4a^+bX3i9ULwI*e'K}_x`2NtǓsR_L|'^%ϢN۫/i2[E5$fdӹ .\Y. W{\@/ 63ˑ&h_AASFsEJb}c)WFF:#1&o,uDf2 iHsR65b~a$Z1ϡ\A>i;GQf$&B(\')fG?ɀ$hh1}9? xL$qUQ2ayaAc9!pJQē3EpxE5PTތ`Sb6V-il\wF'~,.&5>B+*/Xv<4yj%3N#w!HFEUGiyk_-[ue+DFl"Q(\3u(JfReYu(bT8UIKU89]h(#HK%#`K2 ӇJū9PS'#%".8̅'u"/IX*#rGؒC.+ 5n\jrPxtRħh}(rUxys}$Gl$`6|Gh e6ʯ;U.StBKJd\ݦ#j~;>Ԩ"ݐ̸ǁƽON'Q 7~-i?5̸2VwbQJ'u0DSז2% %[`fdaKR8AXOVW#ƒ M4m3H녊ㇺB-:T=d3Y6Fp^yrX.PsBzN7;V %ۏXӡHCᇺJZ4mY !d'HVdХtS9H4dPw"{ddזcWfؗ*<{Q4FH^yrM/]R:KlPC96Aݶ_0G*ʕMk^a{0W⪞rدG-,DH$H<) )w嬄H$frhR[? YעBdwLG4~TG$BDvDXQQ L)¤c Dz\TnjMd8ԎAR$~NrDļ]3(Fv 6IFzaP,jcYc-I*U1z+Q! "'SlD 'rGT<#S(wX91Օ5yؖc*=zl% pŻrh_oG95 zE}u8T~Sa29;bg N^чUHTN>HqҀ~RyST.)#X"/ŇUKIO*a-R;4 REKElQAFV՟(6>̅fO]8j&lYl-b-lPOh NTpZ'YJ`d\9 la-`uXf TYh%d)Eb:`-;`eX TS؂S"g~,t02[XFBǴO}lCޕ3!?ߜԏRՔf Bj'SCQQ̳?HX )_spIENDB`perfbook_html/img177.png0000644000175000017500000002764111672746024015327 0ustar paulmckpaulmckPNG  IHDR)tRNSىH IDATxliz?<ȉd( 'hqq/4+7kJ![+RSRobCŪdYi6-=,G "2g}wy>Àb\`\8(;(BARMZ)Gw 7H^d`IE* w<s?踷 :Kxxg>" *,bPj#PzbNxX<uxtJ6z#*2 JeԀa%A=\*/Y6ސ; $/A*- x/[z(ވBmP6BCmZdS?(凮Vyǽjsڅ+(bT:8U,E_(>f1֕IWuՎHD|+@J1cjfz݇A1j.[xM7z0(53gɟˋ- p21"-_Ih[NL֢h\ }re'W6m=!&+3e ;rs(bT,M[( .`tt|U#AZqbe$Z8PP?n{~@Jј_/MH)?m1'Qdqg,Rv{k/U?Q4hE.dkqjkZ 3i(K5h^FJ1 `ևwHMg]!Z"Vnndwx Y,IJN,bX[,E pj)UN7ؽ3?OĂ5\?=<|qxxx&jː5Y+gG.h9*%̰+hcזA^ jmMIVv =4a;Ir~0-ό.$#\9 lkakEy[FFFڶJ!`Q.8ƼLa$|~VڍE [pΒ<!$#r]!'^9͕4tA@ƸI/WnB__YTO^v_I-,}T4fL9ru zj>WؾX)sE22@¶ l) WdE,}=5~-ӕU0]:n{gE${>9K\aAtM~V =RZqM Yd~FQƜ>fryYU@VEnY叮h//hyCڷ5o(,v[s@夜*/ѷ50#5!,oHdĩx}F8Ÿ*B1 kgz1u[Mw5BmR.-i0y  mn0 Pw*#qۙe0fNU>cP+j5!ݒC}c8y; 'tQzǀ QYoge8"5dh1+WiO61Μg8HrI(lZ뒥 RQ{QH3Kĩ'L?ʂރJ:^ g&FE&I%x>ͭ:C8NiG<^FUzNmիSL/%awPDZ 8`4rs(- ,,,vVAa~⼯j$ b(p0: H:YC]$H[\]^/Q CW$iNo=ޫm"ٖlýC)]!_wsYZSqz @발rMF;mЕr]9IFoMuoV7~ԣӹrU-ɤys@iR"ӘGxGbPFP,±{T()aZ1V"2`Ӂ TWS)8jFbPEjc@y"O8 Ǐ@6_lZQEJ4ơVՓC@JPH|mW(jQPՓCAH㠸/ VA]OƠVEI=$]I_.sJ5B*oN/Cs.Uj'r;9t oۻ/-H']OlؾJ q[#t* pGY*-Aqfy&63\l%gYY_Ҍ89qa`t%tEbakS+ۇ8P1pA*UFVKm[>jj^Xl6snφy:Ijrh1T,r83 U*Q(1:32 U6r8Rq[BxI@R>%iITmRӓzr( E}ki}C7N8ӵ 7ܘٙgR`ԆK{TSaϵ;p15JENzzDlT֍I K:*j6aK#칸*hկ},IG\e5ԟb9511xAbEX,V*bxbX >ꯘW5mz{ _1MR8l͈y+oqY (0;yZ^p2aI`zFLʀV/Nbhۥ+ڷؿ Uq K 'YEQHgDMU [$Ъm;L9 $YڍhQք)ȑA_;hP(,H7ljd>S hZN($=ڗٞKWKD~K,ki>IFk׷q zfByx'qhmʤU 軍s+9j 9h'N1 i҆Ԡe?K "}:O4(Yʲc6Rj(Pmr8^ aʾR8qjy> p F5fޔ (E 1|T#63R(o<m<`sL) )ƒY()ic#P;5rsөiKi;!g:[[ق(@<9?_)M,n=3? _hA0)BX [ڛ3^~JK'լh:.C[q]VSJ3}Τ L? {c|>R\‚lYɔwן"=w?ף֧sqRoG{VԳqR9蝟NͩԃeeK5fz5Ο -j]gaɸhC/J9D); G'ϳc'1GK&f%3 ll:ؽ]j@R7UnϾg^((5XKc#Qc RV[ []ؓ)8M2%S|0L:mJل6hRS#vr+Ĵ!3ݔI>s|IN5_utgNU(x'Q9 T Lȝc4e8zZz1XuJ3jG۰>鷍zڨGzIY2 ڨJ Uk6JA-ިFUݮPmhek⽀ɜ̼ :`5&n7;uՖRzز|la@ oSPBݨ͉ 6 vގFU)/𧇇?9Cf %M3/o@J*l?{T%PגU>-yGKRdP|Ndʃ$NVA?GfjIք² =]N3BNdk\AaQXM} TЗ8B٘W9ESI`tH$II4鱘J <)OL$q`N3R&QԨ*6RE[}">%YgUq{K H>7(ͧ\NhWE*_rlY,G ؗnL8UǴRR0(~)~V**z("_EPm%+S|U"Y ߰$T g/Zo.@U|#2T U`>{dԅV&+_VJRUdm5+nYj?w~t| \kΏ^]C^g{Mk.(s@hi"-Pvq@u*:SEX:#|OX}ZʢvpEk͛x>k@QE5ĵzEQ-M=cQ(0UnrpU$P*:;5OT5R{&&y;4MɈ(*W6&eD )#%T5ʁrvRdU5J|*99$ɧbRFJOi<+!`P'紲6uu2;cQczWIeµ:a_|M&6Y(f'/ﺓnW'Z=$o \\5"y K,6q-+fSi>Qoɺr$#ZC5 '֧>:uJSrgqRoJfZR怐uPBK&}'2[`VW8S<9ԧMw⸷/qNk~()9!mg$rFNdn;KPW$)КdDQoOEʥ%XrKg`ZazNKu!Vr~EfE:<~?|N4~($Ci7Z2Fay%A2'eDXt$l$O&2 QG6Ы%P&pkUz! ANsŸ~.kjBIT22149E$Jήkmq Mp?\SFH&y֍JQ)"'NI8QGZ[ڲҞZ⨟:lc<yhe4ł-Լp{+Q2byjƳ&9w➧wSe>ZEjH`76\`Z]cY].>P ,q4oŽh9b*|n$yUst8&fx6bV]`n)؜_qjB;=A Wj._r=zFMy# 3fRWS3r>> H$Cp!E KmG2{2[8 GH~  )>[q4dga6䣰CS$W {`Y_'8:_| .R(NIDATBó 8{>kv2}bK- 8;}}Q2Ip=ʠ2(YeygO.ޚҮY K1؏{@KIs˱uwsiDoJMê)3=%r":=ފ1{ LX7cO޻>'>{w`&Ng@Wg^ن_߼'a|s;}~WI׿~O"{YɃ_z(|Ab'|BkY-.0U [?¬0eoJ&YR}Nz$W _+w~g71vq/|M>k ,rwmAI$I:2>~40;G IEun"WNܼMy-vq1#K܄+'nZW!e,}G+ZopCPS<73opJHB`Gyqj? s*9OBA0:(ULw~t' FVySR)2fWYATH'֔ lY+%?Dz?I ];˜^vј/zr"鿊ObcV'@xUO([4Ւ`iN#)R߾ eRϸ t VG0q94Ei3dK,yL?3 okU#줝Ipĭ$|Owp/TʧvXw@ wV3XYlg٪iNSi'ļGu?2n|X-rೡ)GSY=ب~YiG֧^x$O_i U8xaռfG[iql>@hJ8b}є^xqZiq>AhJo8zY)OcvvɁAP3և>ug8h^d֑HOuJۥ >2נ-|&5娪S ^1hStg$i}ÝY4h5u|{.w#އ:,c?Ze܆7]eaMG(9X8I;}%m/Iu$\7̲6Y]ZzF;ZI:u)n|S>:}5uYH©]XYu [N->- >Hl)Bz+h{d?y*3ԔA`dHg)iNqUfO ìJ1ʥXT/`otCŞ`}ۭ -h o8c29G*]-Ō>wۥᎸÙ7/)ՒeV:n۷Bd[Ԯ9GjJ7^`)Ћc zq C/!`1D0d^:k0hRx)]F6by-CM*H PSV>$ 5oi?jJapq@(+! W џj0Ԕb]BGK0L|]Zߜ5`W @r&2_K-,ZGfnlxϼ.l^=oͬ$[bi|ZCMvoxzӃq# (D^O=I3edx(<ؽ;r [~O4b8J"uJ"&yxgC/!ELr6c/19J߼icޕY6.U9xqm[i)$IRn ‚"b%laVk{8piʚgNH\̡zP^uFV36{7W Sb\d2?IGP`d^NMH|$9<)rCF g&EdՊ"]J~8)"׋reD]Ȥ:Z(wC)ҪuhOC=Ze)r$S &<ǐpiCO:S@:/B͠[QU@$ nßWNpsgqgxgdgqoq7wv^7Aı?cAq}hIT5sQD&)\tB~#LloHI%C&$rAم/mP%(rSse#QT.ќ}0+'l2 D3Df*rix$9Q [9YA@7njo~oRxjO_o14/7?hu1 IN\[ԸNw7*9_Lw|n/hS/ً1JϵXշߍ,%~]Xա ʹ64a̧tgGu w 'h+e wvdNAnՖ 036@A!iZ!⃜ xW+Kʿ_aX[FT-EY~!cV <%m!:*`2)Sa=A02v2IbH`'0> %pjrԓz"YIAUGR=bKq0dlt|o3fO&qw:sSC,&դiC>[*/Yu`h]W<=OjO8vz}kkM: #DU:&OԜo[>~^;Ehh& #7R_6ޝǯ^yShdm⢸VΡN"i 3+D} s}Lfbfc2$.&fRjyEH-oÑÉn{qd/4|a=d`u\Nr=Թ ePyXQ\!L%ae$n&f6`HYVn&f -dx(ͣHx;׋H# `;r<ܽGjm2 x}8a5&eb 2 z0i ڐ|B0G%p~x{}iM-ǰŝ֙~VC&}d 85循-q_ ٵ_-J>]P>EϐLol@Qzja56ooa*J!ńipI79JG5T4'ߺu+D$IU ֊1lJLp:nS}#p LVb\1co˒OQZjD(7.nu|12=m<^n#y@TL$4%+D39"7!FT7 ,|D\EmF^ml5,^9Z4Bұe}Ĩp00L@FjQ| s(Aq[2iW|BO)@ۋò+Dɋofٴuyq }ݫ Bs]K b2w-IENDB`perfbook_html/node148.html0000644000175000017500000000571711672746162015661 0ustar paulmckpaulmck 10.3.2.8 RCU Usage Summary


10.3.2.8 RCU Usage Summary

At its core, RCU is nothing more nor less than an API that provides:

  1. a publish-subscribe mechanism for adding new data,
  2. a way of waiting for pre-existing RCU readers to finish, and
  3. a discipline of maintaining multiple versions to permit change without harming or unduly delaying concurrent RCU readers.

That said, it is possible to build higher-level constructs on top of RCU, including the reader-writer-locking, reference-counting, and existence-guarantee constructs listed in the earlier sections. Furthermore, I have no doubt that the Linux community will continue to find interesting new uses for RCU, as well as for any of a number of other synchronization primitives.



Paul E. McKenney 2011-12-16
perfbook_html/node367.html0000644000175000017500000003121711672746163015657 0ustar paulmckpaulmck D.3.1.4 RCU Global State


D.3.1.4 RCU Global State

The rcu_state structure contains RCU's global state for each instance of RCU (rcu and rcu_bh). It includes fields relating to the hierarchy of rcu_node structures, including the node array itself, the level array that contains pointers to the levels of the hierarchy, the levelcnt array that contains the count of nodes at each level of the hierarchy, the levelspread array that contains the number of children per node for each level of the hierarchy, and the rda array of pointer to each of the CPU's rcu_data structures. The rcu_state structure also contains a number of fields coordinating various details of the current grace period and its interaction with other mechanisms (signaled, gpnum, completed, onofflock, fqslock, jiffies_force_qs, n_force_qs, n_force_qs_lh, n_force_qs_ngp, gp_start, jiffies_stall, and dynticks_completed).

Each of these fields are described below.

  • node: This field is the array of rcu_node structures, with the root node of the hierarchy being located at ->node[0]. The size of this array is specified by the NUM_RCU_NODES C-preprocessor macro, which is computed from NR_CPUS and CONFIG_RCU_FANOUT as described in Section [*]. Note that traversing the ->node array starting at element zero has the effect of doing a breadth-first search of the rcu_node hierarchy.
  • level: This field is an array of pointers into the node array. The root node of the hierarchy is referenced by ->level[0], the first node of the second level of the hierarchy (if there is one) by ->level[1], and so on. The first leaf node is referenced by ->level[NUM_RCU_LVLS-1], and the size of the level array is thus specified by NUM_RCU_LVLS, which is computed as described in Section [*]. The ->level field is often used in combination with ->node to scan a level of the rcu_node hierarchy, for example, all of the leaf nodes. The elements of ->level are filled in by the boot-time rcu_init_one() function.
  • levelcnt: This field is an array containing the number of rcu_node structures in each level of the hierarchy, including the number of rcu_data structures referencing the leaf rcu_node structures, so that this array has one more element than does the ->level array. Note that ->levelcnt[0] will always contain a value of one, corresponding to the single root rcu_node at the top of the hierarchy. This array is initialized with the values NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, and NUM_RCU_LVL_3, which are C-preprocessor macros computed as described in Section [*]. The ->levelcnt field is used to initialize other parts of the hierarchy and for debugging purposes.
  • levelspread: Each element of this field contains the desired number of children for the corresponding level of the rcu_node hierarchy. This array's element's values are computed at runtime by one of the two rcu_init_levelspread() functions, selected by the CONFIG_RCU_FANOUT_EXACT kernel parameter.
  • rda: Each element of this field contains a pointer to the corresponding CPU's rcu_data structure. This array is initialized at boot time by the RCU_DATA_PTR_INIT() macro.
  • signaled: This field is used to maintain state used by the force_quiescent_state() function, as described in Section [*]. This field takes on values as follows:
    • RCU_GP_INIT: This value indicates that the current grace period is still in the process of being initialized, so that force_quiescent_state() should take no action. Of course, grace-period initialization would need to stretch out for three jiffies before this race could arise, but if you have a very large number of CPUs, this race could in fact occur. Once grace-period initialization is complete, this value is set to either RCU_SAVE_DYNTICK (if CONFIG_NO_HZ) or RCU_FORCE_QS otherwise.
    • RCU_SAVE_DYNTICK: This value indicates that force_quiescent_state() should check the dynticks state of any CPUs that have not yet reported quiescent states for the current grace period. Quiescent states will be reported on behalf of any CPUs that are in dyntick-idle mode.
    • RCU_FORCE_QS: This value indicates that force_quiescent_state() should recheck dynticks state along with the online/offline state of any CPUs that have not yet reported quiescent states for the current grace period. The rechecking of dynticks states allows the implementation to handle cases where a given CPU might be in dynticks-idle state, but have been in an irq or NMI handler both times it was checked. If all else fails, a reschedule IPI will be sent to the laggard CPU.
    This field is guarded by the root rcu_node structure's lock.

    Quick Quiz D.26: So what guards the earlier fields in this structure? End Quick Quiz

  • gpnum: This field contains the number of the current grace period, or that of the last grace period if no grace period is currently in effect. This field is guarded by the root rcu_node structure's lock, but is frequently accessed (but never modified) without holding this lock.
  • completed: This field contains the number of the last completed grace period. As such, it is equal to ->gpnum when there is no grace period in progress, or one less than ->gpnum when there is a grace period in progress. In principle, one could replace this pair of fields with a single boolean, as is done in Classic RCU in some versions of Linux, but in practice race resolution is much simpler given the pair of numbers. This field is guarded by the root rcu_node structure's lock, but is frequently accessed (but never modified) without holding this lock.
  • onofflock: This field prevents online/offline processing from running concurrently with grace-period initialization. There is one exception to this: if the rcu_node hierarchy consists of but a single structure, then that single structure's ->lock field will instead take on this job.
  • fqslock: This field prevents more than one task from forcing quiescent states with force_quiescent_state().
  • jiffies_force_qs: This field contains the time, in jiffies, when force_quiescent_state() should be invoked in order to force CPUs into quiescent states and/or report extended quiescent states. This field is guarded by the root rcu_node structure's lock, but is frequently accessed (but never modified) without holding this lock.
  • n_force_qs: This field counts the number of calls to force_quiescent_state() that actually do work, as opposed to leaving early due to the grace period having already completed, some other CPU currently running force_quiescent_state(), or force_quiescent_state() having run too recently. This field is used for tracing and debugging, and is guarded by ->fqslock.
  • n_force_qs_lh: This field holds an approximate count of the number of times that force_quiescent_state() returned early due to the ->fqslock being held by some other CPU. This field is used for tracing and debugging, and is not guarded by any lock, hence its approximate nature.
  • n_force_qs_ngp: This field counts the number of times that force_quiescent_state() that successfully acquire ->fqslock, but then find that there is no grace period in progress. This field is used for tracing and debugging, and is guarded by ->fqslock.
  • gp_start: This field records the time at which the most recent grace period began, in jiffies. This is used to detect stalled CPUs, but only when the CONFIG_RCU_CPU_STALL_DETECTOR kernel parameter is selected. This field is guarded by the root rcu_node's ->lock, but is sometimes accessed (but not modified) outside of this lock.
  • jiffies_stall: This field holds the time, in jiffies, at which the current grace period will have extended for so long that it will be appropriate to check for CPU stalls. As with ->gp_start, this field exists only when the CONFIG_RCU_CPU_STALL_DETECTOR kernel parameter is selected. This field is guarded by the root rcu_node's ->lock, but is sometimes accessed (but not modified) outside of this lock.
  • dynticks_completed: This field records the value of ->completed at the time when force_quiescent_state() snapshots dyntick state, but is also initialized to an earlier grace period at the beginning of each grace period. This field is used to prevent dyntick-idle quiescent states from a prior grace period from being applied to the current grace period. As such, this field exists only when the CONFIG_NO_HZ kernel parameter is selected. This field is guarded by the root rcu_node's ->lock, but is sometimes accessed (but not modified) outside of this lock.

Paul E. McKenney 2011-12-16
perfbook_html/node369.html0000644000175000017500000001020411672746163015652 0ustar paulmckpaulmck D.3.2 External Interfaces


D.3.2 External Interfaces

RCU's external interfaces include not just the standard RCU API, but also the internal interfaces to the rest of the kernel that are required for the RCU implementation itself. The interfaces are rcu_read_lock()), rcu_read_unlock()), rcu_read_lock_bh()), rcu_read_unlock_bh()), call_rcu() (which is a wrapper around __call_rcu()), call_rcu_bh() (ditto), rcu_check_callbacks(), rcu_process_callbacks() (which is a wrapper around __rcu_process_callbacks(), rcu_pending() (which is a wrapper around __rcu_pending()), rcu_needs_cpu(), rcu_cpu_notify(), and __rcu_init(). Note that synchronize_rcu() and rcu_barrier() are common to all RCU implementations, and are defined in terms of call_rcu(). Similarly, rcu_barrier_bh() is common to all RCU implementations and is defined in terms of call_rcu_bh().

These external APIs are each described in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img129.png0000644000175000017500000001610011672746151015311 0ustar paulmckpaulmckPNG  IHDRBCtRNSىHIDATx=@uM^YFoD'&dhL&g7 H4| bw SC}:uM`͘0Nw;$"7=C*F%$'/@Fs(=gxSRb S O4}>fؘ*9YnLʩx›F4ghM1oy Mq`g3FlМR)MZ$&rJ_KAQM%RH41=GBRx MpMF!,Vs>B$`\8Y>0JR1HwSƛob9YLd/?G1ntsƻoD9qAaB=m꜋R^t}.O`x֩ry5NǓ;h*p8Ţp\*Bds&Ig$mreJZeay0e Uv!;YN,ѓ5P4x$jn k ȡ$º*  ^ܣFr +uo#Yqi3a؋u 6ܐ-+s$ 0l.^I4J{ UM,żo@ӻfe'" wgм^nbc\v{7S[4jr^)+IoU5umrO9\ PibCP'EGm(N\ql\R`n|FPfLƣّu/dWô ڽ^Cj {S v6Pi:x3VX,P~qlXN ZC|K*ذaP*4l{-n!rZ9&G r0pAJEי&طߴ0%t1=u,颵dȼR% d24a@{OНV*{*e]~:a*zW-J}ѫ~m2 J{T70zFS8q+mv1_9~hG'jT7IDAE'ɮTnq$qD,anЈ0|2>Pհcӏ|X%?SsEԝޗLНp$2/f"':>8E(qQ7JTdMA3 YJGD9A_iΈ&v{M݆2B] fS*(%$$a%8ʩ+pzMزů]]sq zw0Dkl~ع5zނLs-w^Uc? x?1E6a`ee>vpxbܭjpV 4ޑ )Xg3#4tlF+h<&sshD,2k,` wqUkO1O´mo6+ y/iѝ`ϑL$6,_p;4j v3 Xܝ3Avܞ8v?IylPsgHsEEyll8}MN4 aW)ckͧ(WDo8T+-r*n,c=N+.)'&$dąCAHYk0^.燉·YpȢγt9<< ѺWUhC9>.Pɡ@t:VCwl@tb1]UK+hm.ޜO 5bǔXր;[a Ww{^G`\ ݳJo^5v hrK 0WD .韵$ |~CYdҊ9Uxړ [>U`W(цs%8.)Cw}>^BP6ăYfx>ECX -(T 0ܲc")ǐjqC\je<4AS:cIV)vDZvBvC\QjjS]m|ϔmu V^Ñ \PVlf&N935> >U?&}i#_LF*>4qm]oɟ+`:d؇Mmkd'& GãP6:k&?*mZD/,k]} v}l U`K;6ܺ-0ݑE`c3hsjF?J4:-wd > w[7_Te2/[4h5xMCһ2S@>x8` `2MV>Ps%.I0ѱeQ:mspн怮 r˺Н栊$IYwBVcWYEFvγna2*̓'94&C\1$MvI}A1PӦ<^z7!כ~0LY4iJ5+ܿSh;8HhJ qOњ d ͸4?+FvAʝ;\RWÊn4sHpv_$xc[Vևc `]ǡ$hE=h~!n8t:[= κU Τ])5{V砰[EU9sk:KOԝyڏ9O<J䚃&m=~7U89؝/|Vs|BT@yc]R uKunbh).*SfiyYKO,{> nS]FL ĥ9vPvb )8_J^) eXv/Tn7EJ2fH,9>ZCSejay4XUx\S{O5r{J;U%O./LY/o/PJ PA*C{2([-7L+62?itߛ8 BbXKkj[3 rX ]`j5^ rL&>yp\<1:Pkotye 0dQĊ@TШ@mʾ<mMqh+{ ;/xM?…BߟI9uS4oȎr0%3xE#x<"[Mӆ&sSˏߌ"LpMߌǾvm R vu32Dli> R>J,jrޭ#c{#قِ-\%ItEr9=F!U=8RUj#&7{=V,IN} 5M)Jt~IFh9]{פNՊ3|\$’pe&6 Y0Y В% g<*c]P憻YY4%EK4o uQr9ǶV5.̗օ VBTKH\Y&r#N4.PA'`M*x+Rbf&.&M$ZFnU]qefÄ9T)ZpّnQWJ z"ִy\yҏl>0` (k;?^KP8"#[Us@c6{ ԯ%ސ%IH~t? .xfDx3^"/ތExrι7ZVz3\}9qv'uǞX5޴d9 n [{ [NNn5J ~mȶt:szn [i%[݄Vsi:3PmMFtՏK޷l*“iAHMVsp0^,'VS{Iޙ[ڥn[]K/{xfDx3^"'BB9N-c0% {c^R= !vJ(3t9Ƕcfy߂Nrl7k4"dLK[r}pWobqNVfb\/@/((ۯ(Bg]]{jzNk8z^*5!3߷`c_E tN 6*|C+}IENDB`perfbook_html/node114.html0000644000175000017500000003206011672746162015641 0ustar paulmckpaulmck 10. Deferred Processing


10. Deferred Processing

The strategy of deferring work probably predates mankind, but only in the last few decades have workers recognized this strategy's value in simplifying parallel algorithms [KL80,Mas92]. General approaches to work deferral in parallel programming include queuing, reference counting, and RCU.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img298.png0000644000175000017500000001343511672746106015330 0ustar paulmckpaulmckPNG  IHDR^E[m?PLTEb``MJK# hffywwmkkiggXUVROP856C@@wuv.*+DztRNS@fIDATx]FdD|gX5&ڱ;N "VXjV0bW aťԅKd6sz$Clco?ߧ3 liûfh:>C# 'TF,\s%;?| c˸vwLwQ\+R}\F)ƭ3JFªFk k Tak-_u"S`Ds8m@.5 vS9lw|Ò[7/~dsMK- R$s/ zuG>0XݠJM.b}+3HKVշ+%/-4Mi^+Oi:?T? $EP ();xkMk]/vᔦ?sMkr mkw$- 0=S\ʡos;dc5twgR#v= À4Q߂~R6qpZq4۰fXc-J^d:\voL!G+5"4KsSP&b̈2dC#MZ֨Ojz,4tV!_o7IW"~m` 9;FE)'!HIB XL m^#mN bH 1i˳LH۰G tX7y]hWWe!aQk rϴ\갋Ο3E؟įb$nu)5qG&d ~c{πsLR哴I}\lCgC~qOS<+evDȚ,U ZtO% *>"zߌv..aI=aϱ-țTn*̠qb-i猇_Ƽ:yF7o#9@9 cCi\/C9r=7?w :h F9Ɯu 1]c,P,^f^\5,=]Zkc{ /"WmW^FAI/#QS꯿@!z I5/>.mNuԻ"d&>ʚQI=3})cK#0$HRtqCiLu,˚YDħHcx Dg^!g^bC◺SPpN.|߶s79҈lefhV䚁OQo-)I<&aM*?x10"袳EC`LbK,F(:$EwA|T1ϞxW %S#ڊ-UAE[Zʻ- R mgfN>/9%{Gl[KUt0B6BJzb ?dWߚV-n?ɦoK/ \sИI~]:Y+g"dـ˞H_>H >F\1H'Ka\ͻ_ىA8)|L;s˛hjYF/5`,u->h!޵9ׯ{EݐQ ;) *յ(PvWrۑoLM m&I -Ayu]56;= #F%oHEo(>W _.~Ԓo#YBLj,`&n]xNu0#omUs`pJh +H%hƁUx͒ 4gp!P>(SpAAAAL ֧֭߷?ΩOH+sRj^~A5:)g>fCT~>b} yTYZ<(P=uN E3`sջ~"fygl78A>709*X ٲFrF ;|pF+wd@: RrP&7|y}w(aW%b=piJN&x ԩ LTTĦ6=/KrNj-|>}w@2)S*AhS UQA *^%o~ +\!_97љO߱K+w7OD!,И RbHP3Uwvdo=8>r7ۗ;CD7qw?pv؅BtFʥt/ofSp35N:ⱓ_,H54H+ƷF@ⶒz\)i[ytSlUw@?.>&翡 lh5ܚ1&Hs 4B)a&bMɛNOȬ}9=D$ f\ԁBrƤTcPXȻLVOƠ!*AVN rMZv|kth7&/'HM&Â)?b+b/`&S׀C14=lzȔau`@^3EڢJ->7& Ί% "$ NĖ{B~>d9 #CAAAAAV]e,֑򜵰j+Zi1v$m<[ev`*4Z^*#tRInʂjowd+LYQF!>oa~a'X)~zUu`M, ~=Ě`VлE;[w2tſB40:y5腵* qV!ćTYЗݦ@rny͖x%澛nhʤLAƍ $='R/RvTkN2ֻ;]_GM~GgNKO:i5z%TVuqD'~ MI4'$Y*;eX bl%>9B Rl˭dC?88m6q98'Xyny9O^SMɱ8 ё< ?9 1$~)&Xy| Ŀ_8gY> lScI~+#0WQW>9%8"ڜ Kq=-?ɛOf;,Fyϫj/ 4z'EyX|}H19Luxz;)"A_vG At뫪DcPM促U`(1[+HUv_l 0o-xANVPPPPP eu 6'%% bE?%o1]lԧSY DS<$9΢ yo(g|iIENDB`perfbook_html/node97.html0000644000175000017500000000713211672746162015575 0ustar paulmckpaulmck 7.4.3.4 Allocation Function

7.4.3.4 Allocation Function

The allocation function memblock_alloc() may be seen in Figure [*]. Line 7 picks up the current thread's per-thread pool, and line 8 check to see if it is empty.

If so, lines 9-16 attempt to refill it from the global pool under the spinlock acquired on line 9 and released on line 16. Lines 10-14 move blocks from the global to the per-thread pool until either the local pool reaches its target size (half full) or the global pool is exhausted, and line 15 sets the per-thread pool's count to the proper value.

In either case, line 18 checks for the per-thread pool still being empty, and if not, lines 19-21 remove a block and return it. Otherwise, line 23 tells the sad tale of memory exhaustion.

Figure: Allocator-Cache Allocator Function
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct memblock *memblock_alloc...
...= NULL;
21 return p;
22 }
23 return NULL;
24 }\end{verbatim}
}\end{figure}



Paul E. McKenney 2011-12-16
perfbook_html/node254.html0000644000175000017500000001244011672746162015646 0ustar paulmckpaulmck 17.1.5 Extra-Transactional Accesses


17.1.5 Extra-Transactional Accesses

Within a lock-based critical section, it is perfectly legal to manipulate variables that are concurrently accessed or even modified outside that lock's critical section, with one common example being statistical counters. The same thing is possible within RCU read-side critical sections, and is in fact the common case.

Given mechanisms such as the so-called ``dirty reads'' that are prevalent in production database systems, it is not surprising that extra-transactional accesses have received serious attention from the proponents of TM, with the concepts of weak and strong atomicity [BLM06] being but one case in point.

Here are some extra-transactional options available to TM:

  1. Conflicts due to extra-transactional accesses always abort transactions. This is strong atomicity.
  2. Conflicts due to extra-transactional accesses are ignored, so only conflicts among transactions can abort transactions. This is weak atomicity.
  3. Transactions are permitted to carry out non-transactional operations in special cases, such as when allocating memory or interacting with lock-based critical sections.
  4. Produce hardware extensions that permit some operations (for example, addition) to be carried out concurrently on a single variable by multiple transactions.

It appears that transactions were conceived as standing alone, with no interaction required with any other synchronization mechanism. If so, it is no surprise that much confusion and complexity arises when combining transactions with non-transactional accesses. But unless transactions are to be confined to small updates to isolated data structures, or alternatively to be confined to new programs that do not interact with the huge body of existing parallel code, then transactions absolutely must be so combined if they are to have large-scale practical impact in the near term.

Paul E. McKenney 2011-12-16
perfbook_html/img204.png0000644000175000017500000000027611672746072015314 0ustar paulmckpaulmckPNG  IHDRPLTEMJKb``mkkC@@wuvˡZtRNS@fNIDAT8c0` @OLG}d4G;'@>r%}utbtFW RIENDB`perfbook_html/img262.png0000644000175000017500000001457711672746010015321 0ustar paulmckpaulmckPNG  IHDR]B?T6PLTEb``MJK# hffommmkkXUV856C@@wuv.*+dE,tRNS@fIDATx]( EܪU[;}BD(F H(!#/$Q.E. _r 388TRT jMze9(k+ |gȡoPBֻZCnXwy&%X˹et>- Jupd,øm_iVNBV4B\o{܅'it2qk} t[a*l}Zߖ|e\xܸUUNzU7t񙎠2 L ,YA-d7Vf`^nxX7 큻5|FE{8u̔:T̏0-3E: h,q\_1KsEI5,b<3v}Cv]$* (z3(l 6ITFV5FmEA W#1϶{R|(prϸXe#aDm L?JvI+ѳܗ@PQ W/Rc3 ey4]q Tpq ?mpfR1rrPXwcTaZ&KJ&L|"|7áu|Z~vKĘ&Onb>)^q!2۲BA$t@??ݲϱ͝viIW,g PGʉ ~Hesz۰Wl|̉_zkJӱ| C&?Z䟽:k"A sbǎ^2N|P^ƧpUV;VIU!HX7 -BlI _NfZFqJAɗB~zXJ4Zv?c:*1XU2|9h!TCrt[|{}D_iکmg/Y՚ yliw., &qx-c.s}3kyJv.Kt$SB2r dtԏ6k?t:PhU%˓-"[ q!#њw%}u% "+;q!tSv`뱵G;׍,'2E0;ц LmF")A?1=n{!+IXcՃ@\%-@u١DWn D͠詽Yuɿ.XsE:wg.jO)qI;^w`hʢvc0(2:?6֏ C-hXV!c0 UzyyKpVYEź-#MF1nE;">iTwFd &*#:b*a$*&BR!ayXdP5\# 9PYd7=hu9! Az; qc<e֒ǃܟ@mSԐ){aM>k`<|LȄDhGCIpub/eX- }DpJRK{K}eܢﹰ+XI F q>Гo+jj5h:k`]lEph?*,^z6I{:dii/[>gx( NǃMm_T(@(6:~G_nx\h꧱!FC%jtf%:ghVr<|7Oyb?/Ukoe/y34"hR jl;R9d/#x(2YvsrX5&x~វD BKehc;nK>+&*ф<` zbڹ`)+F!u߷ ТŁ6Q#o/(IL vR8򡒟h?CN%Y8co~/@A^댩;O )_QoFKڌVMo{ӈݽIm,z~LSU%>.RPS6] ސOmeoAXkQ38M f;JoȻG0N:ձ,ES%?:ZIyɘ@ 0:VxlWǍWhy.f (!,MVy:GYE䑆 (I5,e_p{it2v`87D5h caͦ͒MHg)1E*7vB oVd׋;~AG= %󋘳raSxv] E r} gPX ~K1i6vLčVpFJPZie-{C\WWT/F:HicGROH`\ѣQ|băr͔Q024ﱨ OzWh>rv[ 7bdj[F$rߑ4l4ׯѿ4a0&@{Tq_&z(+ wA3| &WAW)?dyHRqt Q~ls+`h;]3ފЯTwƍk/R?5b :mgi(t?;D]b;;8Aj >]ҹq)آ\{l4bn^Lzы3;A`^]_Vw4`v @Rmg+gI:>T}JkKLB0v9C~++G e_10%#=,F3 '᛺zhA>;QKx@r%t^!%z틄>B[N2-w[ ~=dKl[[)~fG$QɯSp-9P3<)wBjBu @@S' qʟqWu"2%2"N.ο9P=EYbER[,X qu↟h]casz d7|=_3DK15:L:Ӌb-|> ]ǶU~lD;9hkzIqm^J% ̡CUܤ~fR9/ BU8Er܉$)!sWh0 Rʧ_j\ݡ.|R(La=8P׻j:5 M`j 2U33yz/.ݎGxNaUJ9G r&uh.qvEJEKd=s5 \Iy@Ak$ -jt]T0dv\qf.'ܤ$a si.RnkZךi¶~ O_{G@?Nq'>͛dbHw39mYk v"dٺ7@Ρm:6vF\z g>9 Ub|t8fwN^2g03z`b`>p< 1/o6i_^p\:~@v?T~/ڢI@-N()_@wKa&AMc*d6?t(o--{DDnAx Fig.TYs!:T]-PM 7yu\J护"WhE-YRmH,d-&2,6 [ AzwgZhXΌ-X{uᆑK~+0Oq5Z3nzGIr%FԲ)hә|3w.!]AfR2j"QWI9m=qƍ >cg2'8]XyK3}݊ڵcx]O~9&P?u R*hJ1]k,׵c"$KZ1>nHv"J9QU_Ai>jYUw^6ȅD^ Hz7w6@mщpU p_8Q;Z t=H?rhxVjVp3]q_4cd27x0"?sw˾ {`Tn]턏[nܸq7>U19{NqҦӼb[ [O!{m([*gOJl%7g/4ZϸaV? n\ LId,Pܠ'y筴YU( lUYi HQ8C6+R񢐙4ja dy4{N:H<\t;xNte)hmE`N$ .%͡\ N.^ngBF$[nL_fSY6tV6eֆvǘ30s$37AFÍ.3:vϻk q/bYfP9clpo@QOeZǡ tȒGrX.ÆWOp_/H]L %Ϗ>և"&8G x~0u>`=â{~}!d>݊_YqnyHҺqƍCxmU'mߋݻl]?&]Ѻ0)Ӈ\m݋o6 *jŽ3;F92g^݋MuWuS{wUqSќ)煽TàGX3g.9^7ydʄ'pƪuyopGՎk|Ȋ*2 zΓ`C]V]1oyͺ32\uPXqV89m;#UEV{rN`ug:Ki֝2`RHfܲg'VP i~Dz MWyef:~4O?"=c|-K T"7x ?%,4`()U`/A+Xs *fYtSjB0~χ=R< _)&z'E5e@!GP9#n b# ),R|B,=I2p0B,.Tqk\5eJ,&yϧ-ĪE֍<Xa6K(?רqe@2K[x\%$s7^K^wRVHRd=[}67v&W$ٿzA ŹH\"/[ 6u0^4ޡ `ǽz$(ȺUF/R`w2)Gn[lZ8Y42sc6I G2+]xb|"zO/SfGިX`UmʲrK+%h=BFG1U }%UjG:*֤^"MchaO|ڿy : +1y&-qٮKds1nMȵ-7$x@+EeG3@) s(m 0wKŁkY:3Zwu4mYiܖ9[[=4Irs(gKc(IENDB`perfbook_html/img12.png0000644000175000017500000007176411672746055015244 0ustar paulmckpaulmckPNG  IHDRY}sPLTEٱyyywwwuuusssqqqgggeeeccc]]][[[YYYWWWSSSQQQOOOMMMIIIGGGDED???777555333111)))%%% ~~~|||zzzpppnnnllljjjhhh```^^^TTTJJJBBB@@@<<<:::...,,,((("""T8tRNS@f IDATx콉Ƒ0έÒ,[> dȏ7[sktY]Hp,%w8??u̴(Eh*ˆ 'M{I ΂t% ߘblT`B![Ukif]3AqKKp6[ցDP$sxЏunviؘ\_JD(^ǝnGq,PZ>|Z8;dbaiC7(E xI`ϠoKV&>oOp5p[4aAk F8gXcQ`ωgH'1j,cѴ'lSȆom2ƔCOap-<* 6lLb ) !FIccxC݉^W3;o߃!zFfMO"޼1ܢnҘz`ڿQqۢYXd#mЛC^f_XoWJscnp~m4u"Awj /Vmӣؤ/8ZhBK~?ZkB۽үc1A#H1ޖ2ө7EԸȐ5>O>D;G?qqt|;hϻE):EE  7MoݯmR3%'p)_d!4&;1҈#mQ-4_ʔ~w"MS2d3~ZƞxG,t_v;8qn9&'b7 Qlk%S'x"&$١m1>¿J4|uK6I ) 2]}/0LfW L D[ YNz%]ֲ Q37+0Gb[E1@X,8?d~>Jf<@%P XdXKWWR rpgmNv<^} p:զ#,(fدvsRy;{Pw<,u\FM RE>3 Zd]WCů{lh(R7&iN/{#B|S<YaCcjyGJɊsQ1țm>h?bn5p S:FQ((!'>kAON+z\etXI*BH m&KѴ#eꇑh>/%=5ۓpO$ZބS 9B^X:q^Y= ?wfh2v~ 2jη* Dhb`а\G)xO."#~9gĸHϳ[c"C5ѣL#@_gc2W}B#z"P%"H` b)D:ٯЏ{iዋ=w v={O䛎eG^X\z%e [ d-u$3xʗ$zWom'i99u`7y|0럲]s߷Y )5wKCmv; uW(6r͕SM B|^m&ܿ([E ;Ta 1.K`DK A6`5aF.f Hhfh~n5moeV-ɜ}8*tV"i]~HG=Z.j J&;V?8ܽ8Q ]u"w~;sv466ؙi"l4?$UVTm[Y}N>mpY2 WUl[Xj[ZcΞ}iK2@h567Y& ۾6x{"ؼd7 /Gp+gW\d1<[錔M~T8ݞ<[G&Av"=ukVRiBikN\"vNf S+̑hEXn=$O |SӾxKT~n0BEH<'L*ez1ْїg?M$8|Q896᧍V@勡O.אs霘Z;_V?#ZP4=!)fs!g 3FW`zȍ^LBcioMZYT IݞX[/TDFl'M=/wTᙴ{^1dukec95} @UU/ "Lϋ:iĝX%&\10|T *ĶmeS_Aݪ/1KwsD $E+\@^HW&FPMڑ bΫƄGQ@^5*' M1n5q܄GEcԭ,K Q6+ R6.ƦVy3R1EhnrwqRCsKL.^LI!%ZU͠ h$P8'Rp?tͪ{I*-[~zXNLJj?iz 8+5wj|<,.YܖmP2pX ua;T\]Z"k[7?ܙ # &d\uԭVp^8Gcrl`]g !䋒**z{@ʍIk539I5'QfN݂V4*"rxu%Wً(Qu܌nTF[P&b5#_osJW!$h{"42_L4'+I*` o_YwB7`3[s@6f@iBc z%)eq34GLVeBZyd^/hTX~:3IളrD/M ?[rwؖ;X8|[x@±Cod{B6 |+z/*jn@7q@rp;aoCr HÖ&c,hz")w1D_l&zV!lCfJDGjo-5& &fgkHa(?P HNMtma~HoK41+Ⱥᆲx)l1Pz(h#cz2f~8섚}$dp H4{3%* 7㜼;Y i6ʇ>סV`GL/VGV1yՀP Z,&|?W,}Sl@hѧ ϱӉ1 Wdh}ˆ^&8K۬aӂe%T B Z$mq #>B? ԙ[:&[w}їdY's*kseg;Ygd$,gabNuk,b̗-o:4։6Ĕ䟫7KQSz(<)#KR:G:e]z:w3"];{CϜz.*T pZʃ+f-I$!`yMEI*>V IJAbŻ; |Y5nzSt^: `bW9ȀB<R.<e44E۔"&J F@n4RRip B݇C? ! FCDp<0ҺfO|}2.,=ɤ0A(QIisUW֫̐M~tHUY|X6^Ł>i YaƁ>p,FWS5{=(F2px4#i9L]UuR^ExU^.6R'2;~cO"ݛ. mbdWO[+&ܡpAP2<1&@-C3,e+lp{dH(h(r@?#g:aM,Y9 hLy&8=m&o, hLhC%@U c`"$WJ_$'(R/_s<]" Yv?:yxqzpCd 䔑f}Nc{rönYQ_를ln+P$mt)ˇR#z۶3_~y] C oo6R>rMQ=]ΚÐhm/\6hQ߸EfUbD>DC?AMe^rYC0_nwuD>m؟]#Р62,PZ:Kq_T`ƥ"%^!҉eҝ&xvff>w[}tkem.6/vP䜡2;*ϰu凘!#SR!~G7À'8ͮ`A0cGD\eg iC 6KaLq. Za~x]SUFz0`V7l(y_}m@pN)D+J SNGy! W$s %љ+9)ʂ;%s/zAS:Ez@L6=nΞ)nQ~hhLכ"}dCӷڏa=Y`\Q^Å0M؅ꍞHxzAQJIR1)Y*;9K3B7Z H@Y!&] [vȽA.-Gb&*.ht#׳3y, ;c=ƺFlxz6 y6 wCPsi“o}L^+䬸U{6?9f17|糬9u xؾ-|,+Ҿ-?,?~FǂY 6̂+Rb MxSYd|px#R`RW;ϗww[yY%Ӹ>v8ht39qyN)y;`K)޼D&`ċD:|Fsxqc{apw,2挋d-@9OLp&UYlD2Z8#kB; vN:gX˰a9d6k|. 8B5uUT]iΛ2Ǿ Fc|GȘ9()U)L[F#yN9f!\am 5h3݅}\.mGnV{/[ۈnJ`o3G)W4g5oʹYK9-:pqG spd->`$qeH dWTgcvXov̪YrEn,P~ 8u)qjbg[~xъvDd%kdh wq{Z6 Kt4= Etvs0:Jv(;͟{+_tdʃǴFK@v2$>dݮJC؋ckm2Q)\|>"SJR1HHkvN}tсD)jxVcog @9Ѫ%Q Uюi>6˙tz<Έs (*fD" v&<=mm %$N 9ߔkU}D"txHϭ%5'8/񄸎D]F[̥9'Bon,z.}"|"HmU^ΊFvԬlkvp]-YEwE46/" \'.C6R KHh}!2??S2L#=o9ObJn{.JVd΀$A#B̉iSȋ'BcSwiJkAbSS2KLtnno9fV K~嬧Ć`rbTȒ׬Xlˆ/~Y˩5>\vt9\؆%%SyKz}JU6#l->)ɋSi Y 1҅&w#&Ln|^9>{w(|43_v0le)}IxZv۟˥3=6TEYf қ Hw(Lרs YFYUdScRiGGe!#S d?^qβtR KhkH7idH<$x7I%|ms_2p_Ysə,eK͔qqjsԋw]ɍq%.X++6' &{/u8ir:Rg,NP6~њt%; ]2(mgN5wF Wh&>2W,j* /pAuA~C;Mq&B\amxA$;#}ҩhǬk :Az243IK*8ӸŅ|֍S6}NYn mH$Ibq~!j4 ] CCQ2D+{ml&QA$ItʭpLs6>/"U`q,"Z+^]k6߅f>-K۲,yG{U`zdɳ&yc:nɜ-fz0-}!hIo@H9>/j)0yք.F2KOȞ'*Eޓ>Ozʤj=&>ڿ%v&'LYam^52P\K &aEvyʨI,s:bXрHdh,`9+֯ VR’3\[J5zpTJ:p,-W ]+(hp":svFr^*YYUsDb^^|Ǧug4V!&e'UX[Mσ4HR <X М3bb!FW闌h 36$ĊNzQhGo~(-.8+z"s(Ÿ:glWVYWFPa+ZЎk~ eMMZel,U ;QlV0)Kղ W<aԪzp!r$ӈe|qHݨXQDr[ޥJnb oQpuD-14>8{s=IXH|J7[k!zJSZ)B)'Jmqw bMr'wOHcΔ]1d #K߸ivɎ ɿ+?H@ 77qG=TX(%%-A*[&! >U:d,_e)ub|_^U ! [2ɓr8B}Qy)2J$ #KzxAwK;a;FmD6 {>Pݟsa%pNA:}PC(3Ѝ#kM_BNs:uY=qR:Z*c8có)<R-鬰2#o%&G$o*9[#gp,( 8N>ҋ(?8Ȟ+RGaG^QCJ7R$Č`DYawd' ܰ2|y~r@?--naQ}ǍTG~0Q3iY,<ӳǻ]˴?`K { D%íPSFwO5W㹝̱|Htl~Ҝ'+w?jۢ§1\6\6yU4! 鵂Z2Z=$WJ(Qwh(cjƐEa[m1XgmpQ&DH#H|&5BmY4lfOY[~85tKȽ6i 0x&p8+$z,CYJŐȶgxu؂[ <Б_sT!HdøJX ܳopMr'Fb$Y6b YoD2rF@}{1\>혴:u8C\ZNR hQt z{:F O~Y9{vpT?KaprEXNZ(϶ϝb0uYDdbb'5Iՠ/qIfiY>sI8,MbIRrhs/)17^ \i r1d X ҋsCzSIdqXOЫaZ{Q1>VqO0q$|=q z6*҅տ~BA;>{fmk3iͨ8n ?wڑuW걃]mna.7QI"k `!qx0¹I4yi\ iLЅ7fiJ-& *h\>Y/ATGȔ7BvM=!Rq%YP; WOaR.D5SƑ7gi!y݉uNπ5*K>0f#9 1 -eaF?~j~S`'{MFcܔl 2xuȎ{ /٧*2ygF^=o|t'wV*+b,5Z;a7D6k37=E.Pl#.V 7DvrDoHuVC03 Yۛ>.o97G|hRVw!e pdbq :iWCd7Ꝿ8 }o!aA醧J)!Q}dp+ze~w>>"ͩqd"ͫe-zKcHɉ#g#FՃcϰfN36)A>J˓_Cd7OqӷD3dcǽLqjwlC~xXC7P?8ޝG)/ѫq+\jрoC`v=d jV;_GE;Dꬳ`?YIxה%Jo]#F3?o7]PUlO =eϔgX3e,_Mى0i2أ~{]Ӡ,U b4@YBÕUla) J^?D'o o[? JE~O x`^՘Ot L2%y~le=6 3e#}TQ]=JY V5gI P&2q6lidX7.q/,+(M 7x }hWACjYr)Wi߇DD0+e:hiʜ9Qvors,S|*IwN:RR#dʾ5imeP)3R,kݐaCDH -j#yL7,#Ã0Df~LJI2q`r)D̔x`KP[My64eczH IE0BUKRuMFWQbΦNKWe0$:PU BzDӲMFA(.Xa7lŤT1lߗ <8k ;_Ͼ^~ΑJ0,'$l^jɭ;O?Z.D!>'h IOL@-xQƚGRv MP߂DQL}#@/~}"[:h%=Mp$X_,&2~mgRn+i:ۿ]Jc< =I}I9 J  8/w|2eЕސiEDY aګ} !dJ`a5*7Uww_sUHI GfEtYVBSV)ByU~;'-nqnwT~V64q"k0mY㑖gq.#R&3hZ6ѰlI_^[ IDATGtDPtԑ"a *I#|lLo,.m'}Rwf> b}*mښ&C#{1ӦeN3M IJˌ'lgq[w>}no$Wmt`RX \U]DTؐPu #S@_S_a} hwyK+>w59kgmhΟvsptoȥC@j_g^% B5QQ99ϹR}$t彥ŝW_^{e{>/d-:|x 0|$F CQN5A/E}6nNJ h>dv4vM5ԈJ8Gδo 3(DX%5Ȳ)FlH2,T)~<%NkvH葓ZPߢLjX]_)4ϙMK$$LYζyӤh!!biܭcPYE(;{_Ռafe(}**fc _̠Mu8(!3pAMdX?J"G89;o;V`hk{,okc҂HI|PECa y`' VC] Szx畁dwgc:X\&Ÿw@*8pφ$1ō_I' ]s%N M5?Zsu{ e xjnl\׆'Zؼl`3+xVWaJam.R!C\j^LDeʤcsՃl㵆e#p.gG_?>K/vRZ)nvxtǾ?H?:;HGf j:TP>@wƝ#pe TuJyzjM0w6uQyIyI)i[8劼({2˴Ӽ޾\?(,o"G w9la9 TVnੲV^sCFO9$~3X<W T=Ϗ"UH"6dFܚ^-VW+^RΤQ F |]tpw5x\"DDdo "uVO2s}UD O ,^c*4(߻7(|l] H:Ԑ +69*Ƕ&0^H֡Uq!vԶ&N5h}%1X׸6d[sÑ[Ŵ'ziGi;zwo緒s0FY(1,l~N'7{GBȧ 'fZVEFT^(9-G%+2W Q!`V^D57tap.w;Gwpս-ObQ:ZN4[uQOE՝z3'"uCdz*} 9l!;JH-:$ZB45:KF 8pxz5dɑY4M;9]A,EglMAEHGb lu#WΩ !k MndS|bsU6PwJz+Lߜ|yE:jT!I=A)OUly?ݒwB6-nl !Sᣉ.8j'ИP$7D{5AiM' ēU2uTUj؎نX=6oՄ !ȃPL*- 72{?_LPR[ås^"_m݃TniSV),k# HT3>7]WC1\HFrk+?G&~X ޵y]=4q t Pltիd )i.lNh_/%Gs|h,x-Xz4[iϯϥWzz~d +~Yg)5DpVSHBMY@f6l鶑av~zKls)U歃Gә|j/jŋZȳD3h  T4/V6w3-^@\^8瑯FyhOGqPͲ$;v dh[JLʺx6E@Jͧm])euag.x~.YnW7Q/R!3^ۧ'Ճ \v$I4[~TBmD[C"Z0UE 9IAO$#M$ ۔XetaT`ŠA8 R xhTg*9@R Ѝ)vljzʷzΥ+^"WO1uk-#n[LD ؝/aNNyU]RZ-)ԚX}iW^UJha`X`XG Nۙ/" >ILU"1سݓem\mXIF%osdexc }ܻA"%Ю̿M5X"VN Mw |_ϰ:p \ʺC܃f,ggg|Ydat^V /lXML<_/WY7ovNX_dKS)rΣ،Aj𼼻2Y\u.Yz0#VI#D^`T4ʡZ<@+Q:p.g|va묃u+2A fxS݆6ͮOzFn,~_2V}ߖ[ G2Ϸ;ldy?ƣgM.vP4 YV΍tɚ 5ǥ֙-e$7<>}V}ִj+G~$ T8q$Z2XlQFNۤuꍟ0݅DRWPɕ$uZ{(9YNhv(ݝVik=Ѱ~ܕKwڅQZb6>d6h6]k)PMisH1`:nq`PͲ<"jb \ʰ9N]$X\ ԖByz~w{)Q6Jo8Qgֽ0^Z_{bsI r ~zOϾ/!RtTYCC2UUJ%;y9Ґ)-R`04 *8 ;u0D;N'Dhh1fΘS{/WC+?aM2G+[-A1 K+[/7ijU ȌTԷכ}|\HôL]0:ֹj(B13>(HGUr6Ou 8٩h 4ݚi"("gf ;f)vP#@SZ}ֈ~)Jeo Yث;EjAU'_;ԆSUdXMd*I2LɄ} n$ILo)O~|uyv( g ›|Tf߱L藁DF?RrlFaW:YܜsŘVnK&t4sO1736qdok7ffЌbuI]7EVVZB2n3eRvURkIYM]3;)>EGՍn $1~2 %258t*K[3. 2,ݾ'U0+Af*9n;-BssVV?C2 1l7u M'Y@UmTH;N˓7XbE: >˜]q$.*v "[ϖ֐QMzfF]oh(R烂f9 ,of퟈q7W.*|()pTM(#mTpGk 2z$CX}I p|JD |Mwru /N0 u<a740 YI"lkbK&#bbtywOJխ]*]3NouIMOfrm֑re41^{KFPDE3E>z{aFrD<\@WL7dO:.?=q$>i/!"e~`H›ea*!KJ'rkIYcK6pjBlcpoW#IQp #[lg{p A뚹LŰ&)I1Mp &hq\~6 tsF%Du =~jdJDFxvvzlC ϲ߳GtlQ@3rr*U8IQ{1\ֻ}+d|į,ʘJ\7g2L{=1nٵ^O|+4-,9H!4K 2l*k[],%ڭn[ܥ˪BKa9d NYcX'H%/]HƣHKWDICi O<:.cַ$*-x|Xm&1s@^W1Tk~3 삓m${2C|kDm!!m|Z '{YimD˽CGCSLMe ,]7-`Y3snm{79/ZӷY^|WUՀZv?&3J! ͖o"K+@>pI]g#/ 7O4Z]X$(ՂMkrmo) oMDZ6lAON_ɇ㷐%v +\]pyMSlg0;u3HX%%ii2N]! xUrJsH/CX2Q#9|\Ț^q"D:oWsSM(tRHR">+q,4AYϥWfZIL;lC~s{n82 т`'t{N/9_-f 0%n*{_4˦Tjݳ#|S/ W6S8/vJ\-Or\/ X/r [[_bƟz7߽* -~8H(|ocgTZ#2NzMq|˂DZm_qiiFڐI,!P Mcvﰰ{{XEIv _lJ|h*["z-1NM\6AefśݾaO_SWXF)N95  z))F _ՏY0o:ǻEz-;:4'FIG撼Hed Zzy_'6>8]Wܞ.p) y0L]E0[of n1>eytkQDZF| o.~ )iZ,^6c+nyz4E+%w0 ffAj~_g1s1S+$]ȲBݒ7G80V=_|,zLnE'[Y+Lp}%corbޭl/RY z]H3^G̠8H,^éecda=Yli{-{[FƆC2z>lx 2΋Y^p:x}*Җ80yꡨaN7iQzքRh$1y"I3%P̎Aҳ%/ɰHL//RH36l qcT&W. NAw޾yA%|:y%7Dg Sy!)etS}E+1_wqIR4z-fba=p'i؁'ԹLB~fG~J6u>y٧#: ÆnbӢG'2\,+fE4m=kb!WhlEifQl$Z\d$-[@z 0Ǵuz5e`*$0ƃ`~+ֲd9čO+fus^ cr&ҍ?H]AK Û _1w'?qfX.\]_C@vd2F >*ތiZb?Ccwב Gc[*o ->xy[7̏^BK-ٜ6>3V RA1_=]8pg~x i]>҅B^H:Cv ltu؉ghS^A@Aqx2΢+4nA`t;,TI۴uZi<9 `›~[j|zs` [Q@jtտӳl|ng-(GF\IWfǪ1<0 Q9Ϭ?\h\8{ cھ͸?iڡhkQ_jUZ%P'{ڿjA4SUꏓa=ԎH4ub^O KB[O=/|}~I'|—'SEU UC/qMl7!gZ`FU ݉鉧 +W%[ ܞA3z I!~i bhK eFz+³Ybɍg0bRd/Y/OF(?!ձrql" ~ˋ\bw e{4?<6FVh/gY!Ѹywjmn,ߌ`n;*ka],De=fh>Zp9 }iR/LQJ7$k[ݹf3E2 uĮ^zZѥA"C2bG[w'tlQY|ޢ `K+*,2:\87\eES8#۾:9Z z}0锋P) x]UX/LkngDη%q: H1o_*CFO[qZW}qz87I/8/u f+ݣ XubQO&^7$KoF -wN~s]:D 9~WHx?I:?ګ[hbKW[' 4 zu͏?qP<@ 5ngq?GK"͎9NoK|0M.v̿V>ɅiԺC2˨9PvC_j"v^M =BUBU4>z+<; )Ug0?3۬#5Yǟg'sesq35/.fnjz)fٽ',ͤNۂ,z7ӊ\0KHY$؋ÃO$"[݋3+,'C#ҋ,R -FZN@ϱ4?rWgMz#mWoqN賵ElZ& Yna@ܻN>\uDJ~ppLR1z\GӆM Ubh5D5@V3ol @@;AB%353FyH rSM U/Bf}PyȤ:>%yyW#}VȖ!juK2H,ꦪS岤mmOH4\v褃0 AyIdJ-ĔyӡrVc n|pPk`s[)*Zf|kYJsĠ³kGš~zc?{g$* "y?|u` "GZTacŌZ |7֛%qV_e@l t}% {$̛iwRaCoi!v4+@\>IpM=t|:xum&K*985X]ÛyTRHџ :.|߇72ґTcj9<Ӓ)`juɥ*$燺Tl$,{7z;w&=_O.}M1s}u7osfk} 3i-sdpIL>i*^)7W ~֗-*&6B6"99~8Ҹ}h870#f zs(zj&5화LE7uJL3ݽegҪ~V] I0}1pę21DQ5mNdz?Ġ#gn3Yn>"IXnCld^;> O&s 蜛-&K~#Ј\i |xF6f_㗿z6|Bj t=whkK#ʤI9gDhƀ au~wiN3,sGNfrPʹlpk~*+ Bpv`jίHs)5%{g"|T\~zm(Y"(EM12FVt}ϧpZr)^?&fe2.X~˜ͫkx rvMR)4}%YAz_MmbVط4!H*:&1`X,L,*,8/x)qBJθf%G+p{kUw1VB#d}M[Wi{SHPͲlqnq$ۘUNI0ȿ{Elr]=0{Bx~9ZTEvZ7=̺W6dP()Q3e@\ |s*׬YyOpE>(q5Qv0 kUx4N嶞uew~_We|UIrm~aq*xxalIǡ84"$U6[ 361 AyQ&.eMHGNNT8nn,afo'N nYo`3A)A w1k1k1k1k1kYp RIENDB`perfbook_html/node4.html0000644000175000017500000002070711672746161015503 0ustar paulmckpaulmck 3. Introduction


3. Introduction

Parallel programming has earned a reputation as one of the most difficult areas a hacker can tackle. Papers and textbooks warn of the perils of deadlock, livelock, race conditions, non-determinism, Amdahl's-Law limits to scaling, and excessive realtime latencies. And these perils are quite real; we authors have accumulated uncounted years of experience dealing with them, and all of the emotional scars, grey hairs, and hair loss that go with such an experience.

However, new technologies have always been difficult to use at introduction, but have invariably become easier over time. For example, there was a time when the ability to drive a car was a rare skill, but in many developed countries, this skill is now commonplace. This dramatic change came about for two basic reasons: (1) cars became cheaper and more readily available, so that more people had the opportunity to learn to drive, and (2) cars became simpler to operate, due to automatic transmissions, automatic chokes, automatic starters, greatly improved reliability, and a host of other technological improvements.

The same is true of a host of other technologies, including computers. It is no longer necessary to operate a keypunch in order to program. Spreadsheets allow most non-programmers to get results from their computers that would have required a team of specialists a few decades ago. Perhaps the most compelling example is web-surfing and content creation, which since the early 2000s has been easily done by untrained, uneducated people using various now-commonplace social-networking tools. As recently as 1968, such content creation was a far-out research project [Eng68], described at the time as ``like a UFO landing on the White House lawn''[Gri00].

Therefore, if you wish to argue that parallel programming will remain as difficult as it is currently perceived by many to be, it is you who bears the burden of proof, keeping in mind the many centuries of counter-examples in a variety of fields of endeavor.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node178.html0000644000175000017500000000500311672746162015650 0ustar paulmckpaulmck 12.6 Differential Profiling


12.6 Differential Profiling

@@@ pull in concepts and methods from http://www.rdrop.com/users/paulmck/scalability/paper/profiling.2002.06.04.pdf. Also need tools work.



Paul E. McKenney 2011-12-16
perfbook_html/node481.html0000644000175000017500000002146511672746164015661 0ustar paulmckpaulmck H.2 Reviewers

H.2 Reviewers

  • Alan Stern (Section [*]).
  • Andi Kleen (Section [*]).
  • Andrew Morton (Section [*]).
  • Andy Whitcroft (Section [*], Section [*], Section [*], Section [*])).
  • Artem Bityutskiy (Section [*], Appendix [*]).
  • Dave Keck (Chapter [*]).
  • David S. Horner (Section [*], Section [*]).
  • Gautham Shenoy (Section [*], Section [*]), Section [*]).
  • Ingo Molnar (Section [*]).
  • ``jarkao2'', AKA LWN guest #41960 (Section [*]).
  • Jonathan Walpole (Section [*]).
  • Josh Triplett (Section [*], Section [*], Section [*], Section [*]).
  • Lai Jiangshan (Section [*]).
  • Manfred Spraul (Section [*]).
  • Mathieu Desnoyers (Section [*]).
  • Michael Factor (Section [*]).
  • Mike Fulton (Section [*]).
  • Nivedita Singhvi (Section [*]).
  • Oleg Nesterov (Section [*]).
  • Peter Zijlstra (Section [*], Section [*]).
  • Richard Woodruff (Section [*]).
  • Robert Bauer (Section [*]).
  • Steve Rostedt (Section [*]).
  • Suparna Bhattacharya (Section [*]).
  • Vara Prasad (Section [*]).

Reviewers whose feedback took the extremely welcome form of a patch are credited in the git logs.



Paul E. McKenney 2011-12-16
perfbook_html/img143.png0000644000175000017500000001213211672746032015304 0ustar paulmckpaulmckPNG  IHDRӳBPLTEb``URSMJK# hffvstmkkXUV856C@@wuv.*+b~)9tRNS@fIDATx]*qq +KPl~9!$! Ji: WxYgQrZOe2u֪ڪGj֍MJ<܎ vot (c{vV#F>nV$?7ڡd%Gn[}?ʭ @-~kJ @E"x?ƚ8t]5ۧ/czGHfyii\(oibS/wj%*伓yZ~=EJ9·?| qv ՑJX&;NqzZi~jZ3㩛 #_A}O#.MU<]</UӪ⏣[ 3WEI/JNy & M|sD}M\kDَ2~36kb\u^\-xm$5Fju@*HO Mz mm{]\o+)j"?_ū j7? MP&kqj|kL2#X8C&2n{] cnU` R $]c:"[xHP=Z4,Qjp JoŸze%8C`E }6F* akL!Vb{}b~iB}["v78JIA32"qY5n^\|[GBx&*5黍]BdaϝMׁ"f'a} VLi%1T:)A%f~ {70y54cQv;{:E ɀJߐ !jhi1 *dRҦ[D-Ua~IgbHkx%4jk%]xv=)}n~Ȳ=_U / k*z 5-}wۨfa0+?_gc79Xӑ 9[f7le;"eXCDHMP-;Z;1Hf^o5jW^ɱS{z(4B6G1 mf!hUO0Ak:~n$L5!4! * J<8vn7 G[SNLǯ12ٙ\Z8J-~eҩx%̢t5VwHSm)ռs3x:GwEs|+Z97J쀝: :d ^ ް F {dӛG6dE6:S 2+Qēy[Cxj/o+4߷5mI.xXڸቄhv_WPqb{ qƼ鮋kEĐf %u 6V@ 05J.CC?a] `%ONe in[F^:r]!selS_U5a|S%(%AT;7M+Wb1R 'KIazhIffqKa:g c1 c*{08l.þlyKuTtw|jN6c -A'_;cNMCB$Ī#6jhR<֎vobv@l>'}o&iW{jz|OҷMP-3ߢ:qnHጆ򢺱 Oe*.1}O>]O5-]b%ISۂ2ĠknR<]ՄL̇^ؘH"_TWp 'h~(¸C}P abio𾅦d{of,"f&)rb?V ľ<9Kqӻ2gm'.а1D2;=fo;DlY׆ĞB@h Rz &ljOfFu;D6;Y4ʑ5ɠO 6cx1وenBit(f~\:vN,P̕Wh%v ş`0X;5[Җ_zX{k-x;G3 ~aބSq<s3\wstF' ]OC< 1.~' ]OnZ"&O܌} L ]oILC _hYލe!.e/ Grք8#ʩq;:/8`i]ػ ‰/l8.D (k)Xch_5}HNKeG}%EָMDv͚ģ-1[%(&h~!nj"k+r+ck֯2|*)IiY Xϣko֕2nbw;4!/|bewߧf|BfVIѸMOEVԸaU*]O2;cZAQg ?!77Y[hnV)ݒxqQfssфcl -#&qg>E-O,4UoW[]5qCׅԄP6!2n`Ri%3ae4">o),lЇ3 x/?(,U P\؆X &'M y(P{^T+vÛX)u*c'ͦ nH p)5/U-`E9d 5<& epR>li&TMzaCLRA;Ñ<'!EO4&ύZ;{ĉ%*g<}i9q&> 9fȇv7ݠA^oɾtm[{HB|o"fgGLӃ@]R(R3n|xr$4 % Bх)$qE>Ksˇ _gEU_&gƍgXrVxB'mvJapı0ivX7͜k`EHĉošz7}U~q%ZjvxU5\̒c%ۯIdFtKOupIhݽ@Zo,IUtUkSS٤[\nӵi⺮mEAkhsp#鏧eaijrK^#& "MM/zG[WQFٸ]8 %YODzq"6ns6n'nc[M{kܴ]ᓊE4`@*x$ڡvjnGA/ tteJ΄}xd:*ujw:Ԯ C41j3G]/ւ(Ϩ_ו'qS$֡vjn~bzv+il7ڶ4?ubٹlQ@@ Z[ ŨNv@o0$iJNL(U FKA' |KwgɻcaooqN){)܇B}ªN}{c,M)HS[J4C'ʼnPmy 2$cwIS )Nq[qp_(kUh´0A,Wha NTeq|?X=;?鲾O,ڒ,6;IH 7.3.1 Sequential Program


7.3.1 Sequential Program

If the program runs fast enough on a single processor, and has no interactions with other processes, threads, or interrupt handlers, you should remove the synchronization primitives and spare yourself their overhead and complexity. Some years back, there were those who would argue that Moore's Law would eventually force all programs into this category. However, given the cessation in rate of CPU MIPS and clock-frequency growth in Intel CPUs since the year 2003, as can be seen in Figure [*] increasing performance will increasingly require parallelism.7.4The debate as to whether this new trend will result in single chips with thousands of CPUs will not be settled soon, but given that Paul is typing this sentence on a dual-core laptop, the age of SMP does seem to be upon us. It is also important to note that Ethernet bandwidth is continuing to grow, as shown in Figure [*]. This growth will motivate multithreaded servers in order to handle the communications load.

Figure: MIPS/Clock-Frequency Trend for Intel CPUs
\resizebox{3in}{!}{\includegraphics{SMPdesign/clockfreq}}

Figure: Ethernet Bandwidth vs. Intel x86 CPU Performance
\resizebox{3in}{!}{\includegraphics{SMPdesign/CPUvsEnet}}

Please note that this does not mean that you should code each and every program in a multi-threaded manner. Again, if a program runs quickly enough on a single processor, spare yourself the overhead and complexity of SMP synchronization primitives. The simplicity of the hash-table lookup code in Figure [*] underscores this point.7.5

Figure: Sequential-Program Hash Table Search
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...0 }
21 cur = cur->next;
22 }
23 return 0;
24 }\end{verbatim}
}\end{figure}

On the other hand, if you are not in this happy situation, read on!

Paul E. McKenney 2011-12-16
perfbook_html/img277.png0000644000175000017500000000645111672746132015324 0ustar paulmckpaulmckPNG  IHDRYbPLTEU~tRNS@f IDATxp&rb\?475,` s TOG7ɝn"KS2`i+ISf4j`#Sp Zݽ_{$ ~}}wAaTl^?]qDS%Z:q%˻F3aLMpFu0'Am8YQHf*&O tܞ$\ҡ+.!({ Kh2>)HR"b4M0U73!Fct`)MEzlT6 vn.cgb~0J4עP /5_mGJ_: ɒ +=Іߛ`W^vn#,> ' x8Z1g^baKA}]F`/@WƢs͘R.v6hMMS>N4[}N49cNSjSy|jA_&>cxu!![ :s֣kE9|wlttMcdPɐiOe %,o{D TQ -(CV PTF&}|q kwqt|s5x-uEyZ۝v'8kgeZQiƇĩW]%s#޾d䠨4Nˣơr6gJC bu2%XXh 52!p$ޖJFrdޭRtʅ:gz5mi4\d͙Hǟ4H"hL ?Ĩjp>kOs!T(&Ha_ k&C*zC XƗ Om* `M^z_-14.ߵj!%ign%]^n[q&h$/-G9ES"onҔ(f\f- k;Io!, \8bkۅOK N -FpF0ԇQGKTY;@$^)K`ڇk8k#2뺐V^KcǏ줜NNr"[rՙ$ư.oEeK/Eo܉ W #Zm8Klq~2\ȒA %`g h7(<{Le@nM&0Sa;w{q¹3}_5K\!J[xS|W0l?$ö0tAW 9F;p4ſϊ˪Yfi |urQnMnN$%hjomU/N?kNJ}cç X(M4v:ZnՌ Ȑ3MroMnhXZɳzʢV(EDآQ'1/c M^Rz&eaj=Ny0G-yQn68LRKq$_0鮽f5Ks7GMx3`V;c}S84j]<ޜ63'Yؤ(MY3ؿ^y;k|Z7߁R']6%Ƹgfͷ^h,v|zx??izM&7D&T37I3/ yv SQ6plL7rY"3XAbBh?^O3Y1 T8``:8Dpnh W|$yY:sGAw}/Uÿhu`\q^ !?즲60ZFYx X4:% hݒ1+6Q8'LoΘqt8u!nbq^[9g:zjÝަN _5Ϸ]mV*'L|kBu jgwIENDB`perfbook_html/img159.png0000644000175000017500000000357011672746011015316 0ustar paulmckpaulmckPNG  IHDR$֟U9PLTEMJK# b``vstmkkXUV856C@@wuv.*+ܵwtRNS@fIDAThY(EÂWTRTz{όNjW;wI=$:8hoPq.:\z'Tes.q8) k.Ƹ8Gq5|Eʅur1-<+D#*S ء˕8֡~B_D@ayQtxC"wwu7νS@RpLctΟncmH q~ |N,z!!<)jZ#ixSsk/<,d gF|lDgJ[aو2= RK2E<@b EzqPӇ>___8D:B(C@VTb% *eRZ]v+RG{>3 W|JHAd'J _G1 ]?m5Tuj`?xD v fs6zYCIy|.9(؀_21, ];5cMMݩd)MVS˳SX#Zk 'ujR&Ӣj%TTVELqsT⫋Z Z\d|,[us25բN6 7,NrE:U4]QTRGiYIP6n9^1[Pi9隫-2l(_սd.5-ZoeXjB 䏂AʆEWT!- Y* |}ሥg-PK1f%K2Ijq М^,WOl#*)6I#*r)2%I7_H ^\]y2Ž]?$iʾ .?ҪfƑ9edDnANCA <6GdK5B8Yd(ٶD$:^Z M6Lr+Wu?6+ZgV(2)+nC8 r :('&7ɓ%HB$mQ1n*/\)[J $6Z$ha/r?_Sɂ1FZęznT]3)S]r'9Ξqˁk@t5 -iqdJӎeG-r_bKħ$-3٩ط]1[#|9n7}aXv7,aFqXHu= bFͦIjS2q #?: 3&&A#C~2o.YSJcgЉsLa߁uA ;mGoEN<6m$POyuTh07>~N!6*.xAyb-߁ɓ5so+~9_mlrxn3E(ti> ~=/?'v,M ,hHsvH\ *20䓤̢ۖ,(Y~,Y`vJ.%E:_WaU" õ5´cNRZ3;x9sn Y&l SOfP(̤>_}g nxZm_BNuSӪ|]'ū~-W9t*c~n9j֗$;)QE!no>TpAq+IENDB`perfbook_html/node466.html0000644000175000017500000002256411672746163015664 0ustar paulmckpaulmck F.6 Chapter 

F.6 Chapter [*]

Quick Quiz [*].1: 
But the definition of deadlock only said that each thread was holding at least one lock and waiting on another lock that was held by some thread. How do you know that there is a cycle?
 
Answer:
Suppose that there is not cycle in the graph. We would then have a directed acyclic graph (DAG), which would have at least one leaf node.

If this leaf node was a lock, then we would have a thread that was waiting on a lock that wasn't held by any thread, which violates the definition. (And in this case the thread would immediately acquire the lock.)

On the other hand, if this leaf node was a thread, then we would have a thread that was not waiting on any lock, again violating the definition. (And in this case, the thread would either be running or blocked on something that is not a lock.)

Therefore, given this definition of deadlock, there must be a cycle in the corresponding graph.

Quick Quiz [*].2: 
Can the transformation from Figure [*] to Figure [*] be applied universally?
 
Answer:
Absolutely not!

This transformation assumes that the layer_2_processing() function is idempotent, given that it might be executed multiple times on the same packet when the layer_1() routing decision changes. Therefore, in real life, this transformation can become arbitrarily complex.

Quick Quiz [*].3: 
But the complexity in Figure [*] is well worthwhile given that it avoids deadlock, right?
 
Answer:
Maybe.

If the routing decision in layer_1() changes often enough, the code will always retry, never making forward progress. This is termed ``livelock'' (Section [*]) if no thread makes any forward progress or ``starvation'' (Section [*]) if some threads make forward progress but other do not.

Quick Quiz [*].4: 
How can the livelock shown in Figure [*] be avoided?
 
Answer:
This is left as an exercise to the reader. Figure [*] provides some good hints. In many cases, livelocks are a hint that you should revisit your locking design. Or visit it in the first place if your locking design ``just grew''.

Quick Quiz [*].5: 
What if the element we need to delete is not the first element of the list on line 8 of Figure [*]?
 
Answer:
This is a very simple hash table with no chaining, so the only element in a given bucket is the first element. The reader is invited to adapt this example to a hash table with full chaining.

Quick Quiz [*].6: 
What race condition can occur in Figure [*]?
 
Answer:
Consider the following sequence of events:

  1. Thread 0 invokes delete(0), and reaches line 10 of the figure, acquiring the lock.
  2. Thread 1 concurrently invokes delete(0), and reaches line 10, but spins on the lock because Thread 1 holds it.
  3. Thread 0 executes lines 11-14, removing the element from the hashtable, releasing the lock, and then freeing the element.
  4. Thread 0 continues execution, and allocates memory, getting the exact block of memory that it just freed.
  5. Thread 0 then initializes this block of memory as some other type of structure.
  6. Thread 1's spin_lock() operation fails due to the fact that what it believes to be p->lock is no longer a spinlock.
Because there is no existence guarantee, the identity of the data element can change while a thread is attempting to acquire that element's lock on line 10!

Paul E. McKenney 2011-12-16
perfbook_html/node266.html0000644000175000017500000000611411672746162015652 0ustar paulmckpaulmck A. Important Questions


A. Important Questions

The following sections discuss some important questions relating to SMP programming. Each section also shows how to avoid having to worry about the corresponding question, which can be extremely important if your goal is to simply get your SMP code working as quickly and painlessly as possible -- which is an excellent goal, by the way!

Although the answers to these questions are often quite a bit less intuitive than they would be in a single-threaded setting, with a bit of work, they are not that difficult to understand. If you managed to master recursion, there is nothing in here that should pose an overwhelming challenge.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node42.html0000644000175000017500000001370111672746161015561 0ustar paulmckpaulmck 5.1 Scripting Languages


5.1 Scripting Languages

The Linux shell scripting languages provide simple but effective ways of managing parallelism. For example, suppose that you had a program compute_it that you needed to run twice with two different sets of arguments. This can be accomplished as follows:



  1 compute_it 1 > compute_it.1.out &
  2 compute_it 2 > compute_it.2.out &
  3 wait
  4 cat compute_it.1.out
  5 cat compute_it.2.out


Figure: Execution Diagram for Parallel Shell Execution
\resizebox{3in}{!}{\includegraphics{toolsoftrade/shellparallel}}

Lines 1 and 2 launch two instances of this program, redirecting their output to two separate files, with the & character directing the shell to run the two instances of the program in the background. Line 3 waits for both instances to complete, and lines 4 and 5 display their output. The resulting execution is as shown in Figure [*]: the two instances of compute_it execute in parallel, wait completes after both of them do, and then the two instances of cat execute sequentially.

Quick Quiz 5.1: But this silly shell script isn't a real parallel program! Why bother with such trivia??? End Quick Quiz

Quick Quiz 5.2: Is there a simpler way to create a parallel shell script? If so, how? If not, why not? End Quick Quiz

For another example, the make software-build scripting language provides a -j option that specifies how much parallelism should be introduced into the build process. For example, typing make -j4 when building a Linux kernel specifies that up to four parallel compiles be carried out concurrently.

It is hoped that these simple examples convince you that parallel programming need not always be complex or difficult.

Quick Quiz 5.3: But if script-based parallel programming is so easy, why bother with anything else? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node141.html0000644000175000017500000001110511672746162015636 0ustar paulmckpaulmck 10.3.2.1.7 Comparison of Reader-Writer Locking and RCU Code

10.3.2.1.7 Comparison of Reader-Writer Locking and RCU Code

In the best case, the conversion from reader-writer locking to RCU is quite simple, as shown in Figures [*], [*], and [*], all taken from Wikipedia [MPA+06].

Figure: Converting Reader-Writer Locking to RCU: Data
\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 struct el { 1 struct...
...istmutex);
9 LIST_HEAD(head); 9 LIST_HEAD(head);\end{verbatim}
}\end{figure*}

Figure: Converting Reader-Writer Locking to RCU: Search
\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 int search(long key,...
...ead_unlock();
14 return 0; 14 return 0;
15 } 15 }\end{verbatim}
}\end{figure*}

Figure: Converting Reader-Writer Locking to RCU: Deletion
\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 int delete(long key)...
...(&listmutex);
15 return 0; 16 return 0;
16 } 17 }\end{verbatim}
}\end{figure*}

More-elaborate cases of replacing reader-writer locking with RCU are beyond the scope of this document.



Paul E. McKenney 2011-12-16
perfbook_html/img68.png0000644000175000017500000000364311672746072015245 0ustar paulmckpaulmckPNG  IHDRVZ!nκAmDwPtKYo L{(.7뺾T5"sco:E;r6x,THtIC] P =t A>s~53.](K+bAn]=z:6(Ua6J Ej*]w) ?=SqVwzʉNR04}$}Ѩs1 K&a/jv)0v5>%TdiIb6=ŵf\ S>}YXs/%̗&!24i!;aiyyvE! e[WΫCP@`[:=* hlz`G~upT>S,H>F"k[: O8+Vx2.Gds`m 5$@ATJZ~Dt9v-(95XGCDz9I+ $)}J!!3dž}4uP05`..X. 嬡˒:[u),e[^Vu<)&mٓ@q*hEMP{]U ] 3i)^a,%S -/|fc @ƌЌEfN6.8]OCVpefqHW)k h]R̔D|[5}!Q= ^)`yv ֩gJÝi9>)\a_tbgFw}_*[]#Ӈ.JQUI槡tu'+AL5JpL.1{ԍ2C!x).أub 4( o]+zP}.3U71MjpKA.=Ҁ~'ha$ޢ m4ֵrqvOӎօzP9hKtE8߃t(3Yl=L?u {J->\ú3z54-H\jji#x#~-}~-=}Sb~l2ץ5+y̽(Z9fR96Ubk h zB3bcp oH`+QYݷɥ(Ub4BY(d ɓXrxAm=q)*p-pU46Tc.ioky]), PMOZ3IS)UT.pY'~T8Z7 ?C"nƺZ;^)$0(eZ9205GL!`QZO@{2C@iT>l`.DnhR7TFҚ k8ymΦ,^VA ZhiH'+":_ƯPfFIJ?T,"w7[+9 G❱%iayӇ`{'m[1PF:^) e tJ4WrjOzYgy2>GY.+)rk:qea=( v :5nZI 5|_X#M.m:R;A-DǿC #jB+iQꃴ"h枨Uj#|xPjҳUbgYjӖtkF DK5da7BtwOvyIq˔[X箫X'UZ=ǏxJRFhJj~L|RR+:M%,i)6Vx$^N!wSKw;U.C5y?hRe6}4plqxUH56&Mx;&pdrkbT#7`mjitxA8g4ZR\. :VڹMG3w"WdWc> nYgk,Ql6M53{W:e]BLf&C*Dg)\jm \GQˋ 5%tt:0q?g@ oR L v9,Vjz(&5yʣWˎF&JTZԨ_lB˳jMևܺ_u M&>-5;^AD^Z*G*QNhJ7"'. C`YRһy+MȰ,#|$_6#$(-˜-&UBYYTDGZ+@Yxc2ro̰fjޯÌE+O <ڷu+dM,ѕ2 Cק{)ܦщkc\jn2˴C~CA@8 s27v֟Y:o =ψ]47K\-x+@cfJaw (m܀w d,<񢍌TG b=(u*_4e;Qo|MŖm5 hӵRMĚrῨ?$; grPeP|%'6LfviŬ)(YP )?(i ޥHtRDZ&2tiem崏 wͧ!@M !n݇{t@_6:"&Uٚ*"oc'0NfϿW6xp71?.DٷcAq,/E-F~' K)ic!;?r v|'*}H,VuhXfQ-ⰠJ*KQ]{lou%sݜw=mƆs)tȚ!1Xw60ۛ#?8E~lw^(*I% #Z#9}mZd/DBbM :9ׇ{,Qo oMֆo[HJS uG?` _e+S^' 74o TdHbk:X/n8l(aB,2[Ʒ˹J3r$,DŽe  Ӛ:\t|!xTźDkl2Ol3HWTZ8շ Wo+V᥁>%.׺'ň!3Ffps,#b]9hy3p34`&o6@k,IM>=etĈj} L`fG.=v oBfUsJG`D#Me[/qB7䚓]&`%!m lYY7sGIYI^Ɇ6VyؽU3 39tkρ*[tfJ 9C=oBn8VF;밃5W͐`,sưDX@@~lmjka.,Qvy_# l! ЁU UٲyKmRVQJ 4$G΅@3{`6\] ;UD^ZMݻӇ9[ ŅMDឋ;uY>X<9@J-ngi[\F& !U\d&%z8@gg )l>Zx:VOp3@ggn3Eeor^۰aֶx #j/9U]:HiS^}29:#CR@wm4lZv' ˨!lsÞRC ܀7!YHU{?̛l55\:) bag`>qoA7&6m[K ސg` P1v3yY3v>i79Y]6wz+>V%Ɣ@zFJ}h*7M[;4_g̤m8/JrkaE=ƇMBZ̚:7UHv3{r:2n| )#K\>ö~_%%r(r>'"Oc9MӺ8;{V #Jׇ0u}xܭk+p|rZZL4pSIWQ/|Q&y?98&n2:*&{t+Hb (s[V]\=}xp=˃:2|ѳ})JTP9J>d$L^-G.<b~m;bo |)Lr.۟J~1J]]_uS@(h+7mwI !W߀`[sߏŵhnſDԹF\#Itc.)Wn+9q¢V,"tgh"|oB;ǸU\2:O߁o"7{چh@ QXaZ,_[*e.|Mq0)l +owDL-۵H_}&}o'E|MG̫m1 ~{01[i*6B `,zoGRn^MϚ:{D[͆/voĔe y>l^2;ş.ZAV;k IOV{%>#=Zh` ZM#L |e?8s +p];+R  HO.VӳϋvdKJ?6yVSo^2N(( ?n"v?`oj<(5 e:M[~N:۾你:g2u6b0> iY bK}\2hU҇%EdzIBbB|dڣeA8#`VJgACw=f5G0XDlt=܉GCpYZ*?*=DB".kRҘz=~BƬl'/"Kю3IHJek!H* e'x1xu-AXӔ+}ȾF3I B8@RY.O%p]OXB/"Kϊv6 X!ZAAQS $8)>u/cƁqa˴*>8 Z_r.c> & {?eDUp<%H"DNc[~X^dK@فu\˂!Ԡg0Htl"F$3ſ1(?hW8(OժgLbc-DGP! Lz{*Rt2vFBh1Cey1Lso;b`bx][Ͼt NF$sTP󶪔h-: {_@_+K n3p~^_K8T;~CBSC02ą4M<G]X6&4= /5hh ۃVJ>Դ|Z >ۇVD @fnk(^*ss`dbkģN9 4$3InHGE8H.UٚRҰIa`X؊S@c n7ᜡGVٻ-J^tzO :@vyp]V!|>VF@s/ᜡG*F}y-lR Wۛ"jfr]\.EG-7lUOg^ܕzAai[.bN✰s}{)9b`p#ׁS 1?C 16 f.o%؃Gp9NOc0E(?\ iL\G&z!&Џ8%zCgHb_.2(s/grbHi91 rv墧|8k2>$摽cowk|TYbLX1:k$@c:/DVxg;^.l%GwMzG ܇3"8|/ H^ $|D?w-Úe=ke⧓g!r/TN0i.rl^ ̻ Je}:R!ŽB^ ̸ꩈ t<K!A+fiO/|sPezÀw18;;T۸~4[q4G$E^ԇ+IDÛTH}h|RDb~/B+He!nb.$GlPVIrc 0Q<-}'g!ؒp `4->)p88 [ q@$qc*pq&uIol0 hI<^ĨK.8)p8|i}\ŝآgX;^xCAh@mgZqF]:/+>gD><Q&j'?T9_%4yiLZS<]<|X!ᢞ!O]FTz>g?8eܬg?Qa&v=C:h£g؍m Rz.t=^m3ãg؋Jp/lIENDB`perfbook_html/node48.html0000644000175000017500000001733011672746161015571 0ustar paulmckpaulmck 5.3 Atomic Operations


5.3 Atomic Operations

Given that Figure [*] shows that the overhead of reader-writer locking is most severe for the smallest critical sections, it would be nice to have some other way to protect the tiniest of critical sections. One such way are atomic operations. We have seen one atomic operations already, in the form of the __sync_fetch_and_add() primitive on line 18 of Figure [*]. This primitive atomically adds the value of its second argument to the value referenced by its first argument, returning the old value (which was ignored in this case). If a pair of threads concurrently execute __sync_fetch_and_add() on the same variable, the resulting value of the variable will include the result of both additions.

The gcc compiler offers a number of additional atomic operations, including __sync_fetch_and_sub(), __sync_fetch_and_or(), __sync_fetch_and_and(), __sync_fetch_and_xor(), and __sync_fetch_and_nand(), all of which return the old value. If you instead need the new value, you can instead use the __sync_add_and_fetch(), __sync_sub_and_fetch(), __sync_or_and_fetch(), __sync_and_and_fetch(), __sync_xor_and_fetch(), and __sync_nand_and_fetch() primitives.

Quick Quiz 5.19: Is it really necessary to have both sets of primitives? End Quick Quiz

The classic compare-and-swap operation is provided by a pair of primitives, __sync_bool_compare_and_swap() and __sync_val_compare_and_swap(). Both of these primitive atomically update a location to a new value, but only if its prior value was equal to the specified old value. The first variant returns 1 if the operation succeeded and 0 if it failed, for example, if the prior value was not equal to the specified old value. The second variant returns the prior value of the location, which, if equal to the specified old value, indicates that the operation succeeded. Either of the compare-and-swap operation is ``universal'' in the sense that any atomic operation on a single location can be implemented in terms of compare-and-swap, though the earlier operations are often more efficient where they apply. The compare-and-swap operation is also capable of serving as the basis for a wider set of atomic operations, though the more elaborate of these often suffer from complexity, scalability, and performance problems [Her90].

The __sync_synchronize() primitive issues a ``memory barrier'', which constrains both the compiler's and the CPU's ability to reorder operations, as discussed in Section [*]. In some cases, it is sufficient to constrain the compiler's ability to reorder operations, while allowing the CPU free rein, in which case the barrier() primitive may be used, as it in fact was on line 28 of Figure [*]. In some cases, it is only necessary to ensure that the compiler avoids optimizing away a given memory access, in which case the ACCESS_ONCE() primitive may be used, as it was on line 17 of Figure [*]. These last two primitives are not provided directly by gcc, but may be implemented straightforwardly as follows:



#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
#define barrier() __asm__ __volatile__("": : :"memory")


Quick Quiz 5.20: Given that these atomic operations will often be able to generate single atomic instructions that are directly supported by the underlying instruction set, shouldn't they be the fastest possible way to get things done? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img119.png0000644000175000017500000000610511672746153015316 0ustar paulmckpaulmckPNG  IHDR_BPLTE^\\\ZZMJKPMM# b``mkkiggXUV<9:856C@@wuv.*+Ft<tRNS@f IDATx] fLaL&[xǐ* RV)ؔsvݯpu 1s*Z UFiG ؾo¹;, R+75Jՠa;Ze~"쿭2MCS8*~3/HSbjrwx}`v{dyW@4V|nh&Gjj 1l/ [k]ۚ= |mBMf'qǽqCLM< FF!f{ K 5jOumn*%+2~=\+kO`$5FhgS3v˥ڎخ32CO?k( X qq7xt92LQ52@غ6嬣dE)HbjDfygrVm4;kpl Ƕ]pݨ[͵c2pȰ FDv]sU&C_0-A^'+kf:DSv9;_x_^PFS* fn7_Cj' );a芁[x>P^GF6 ^8߈Pyr8ew(AG_\]Lx<ifݜ<-Ȋ55v`X|(0HK}bP؁ҟ0?D},RՉ ^xb Bwp m|w ѭVkzW]Fk''4(t&PbvfKֶz*Efv겸Xg5:'YϔX6 Qe-^$‰m部Te[j~&twO$de+ *liL.~)q`ŒӰQim/ٔ\Yehi4K*ݶ:Ako^w3JoSh^0dgPEL}u,B#O[ )UTwcP?Qo-Jl;x0!*԰[hľ'6EmZWkI]QYr`9Ul` ONbӷn YCC `B4 ݈ʂQ⧉}#O UV911d/Y8=9 C7/Vd`B|{Nn['Ŭ5 Dh.e&G:{3|NNu<*zh4, ].o]C ٯAԕdHFħF=TG^RX_&b*)ѳ6P)-h< Ba*4ʻ\N˪`Fwp4ۭJOd}dDW] JTcL.}gK/{$'p zg뮖Xiކv<qeG"YA=%磟u7?v"T^Qx'@r $#ib3Z%Lpc#T zr+b iWX D)5SRzݔ,3 iezST]0E'-lhq2-.t WtF5F]t;dtvI=?dWr_It|04d|U5j-tFę$K@5zW`euK= x!;;SUsw J8,d~} tI3Mm-r _;;zi :xVs\֍B{wҋ[8e'+>)J'ζxn֞tfCGP K:[B&;]l񬀮*6-!zG'hri> _-X Si r)}V qSfr&}X0z7`Z=AR Ov1M3l Ivm=9^oyP&xd][ %}l'wII>EyΗF$=^9\;<Β %7T Lˎ4`<jx{6ֺ? }COXB;COfq/8c4!\ZǖGzCtF@]jq_& }"ÆBo ;i,xI8U`c5k4ou:i 9xkvZm^+\1]34[5(wGq3)^ZpXa r<; {/rH^!BrbAOzһw~ꘐGc&@a-0Q')͝)=uy* P&K'SL*ȏo)2-ţ_IȎ AA_R@Wƒ2]ϊ973EO~hId_ :>,t#iȞ3I{~ _~ۚ0+ޏwYȧ~tXAD2ZƺL벙%e&r8J$qR.ۓUKL%r1vjI?ɣ~Ւ~Dwij=IENDB`perfbook_html/node184.html0000644000175000017500000000434111672746162015651 0ustar paulmckpaulmck 13.4 Protection


13.4 Protection

Compiler (e.g., const) and hardware.



Paul E. McKenney 2011-12-16
perfbook_html/node304.html0000644000175000017500000000723611672746163015652 0ustar paulmckpaulmck C.4 Store Sequences Result in Unnecessary Stalls


C.4 Store Sequences Result in Unnecessary Stalls

Unfortunately, each store buffer must be relatively small, which means that a CPU executing a modest sequence of stores can fill its store buffer (for example, if all of them result in cache misses). At that point, the CPU must once again wait for invalidations to complete in order to drain its store buffer before it can continue executing. This same situation can arise immediately after a memory barrier, when all subsequent store instructions must wait for invalidations to complete, regardless of whether or not these stores result in cache misses.

This situation can be improved by making invalidate acknowledge messages arrive more quickly. One way of accomplishing this is to use per-CPU queues of invalidate messages, or ``invalidate queues''.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img212.png0000644000175000017500000001470311672745755015322 0ustar paulmckpaulmckPNG  IHDRIetWPLTEb``MJKKHIPMM=9:# hffywwmkkiggZWXXUVVST856C@@744wuv.*+[YZmjk:_tRNS@fIDATx]Ff9?$"*Zmo"DKRƔb%tB˄k=3ej0 gW.*tPbJ+,aH+}[y MP-)vN7=4)d ¬Ծ.k&6SE}vj*7/$Lek߅~U wg~E(K"ft;nzrPdZcV(-_hޯg9kb+|kz|~pxYُ*,@E)ˁ ^A VkwhI =f^|TCʶ.Y>r8&l42;^f}L5K a&PBklR5qky'w-x4PW-,΃PԡKVA0]LVǫE2VGJR<Bnje5^X:^gM?E4^ᔄDDJ!# g,' fr,F1X~{ԏc-.uz Tn2]îՂq;`-D᮫X"&ImY!bs[xo,9Q^:_+i֛MK *6ߗ29P 7ozj/08}86ޜA4ݬbvrR: ]L|Q GFĔ k"9.%PqUSJv>aY,fcAU}QD8MF& -=}JaDR9M)K[dE2u2/N3|R%5j)s{0bJLx^J1M)%^0+ZxAWš0003mup-Bӕro `3k5g RX ZU+TEuc;zj众lm|M7/oQp ~\8[7Xr6 :'p:N|a0dI-!VQƃA.]!*x=@jU%,lr~{>Gۀ4Ro)- fhC yU BY) ]pav1&䐧6v3y,YKeg3o#D|#7vQtoN*‹eMҶL7}g$ B]$1b! _&ti|,TmP"#7;=˩Z g7/{<\y-}(3D !; גuOL5 gr^9r٥e\q^b}g fçUѯʭ'Xa5-aMk?i)BC-q3ߒ|$ H|#պ$܏R`T!g5~z.Fz}d;͌^u_&~rƖ%fY`5@ʱk0#B?[` c)]e9>9 (5 xiOHB=.qrmoaFSdUTAe494>9zX2lo QDDOz*¦=ؘl=()\=$i es& :,ڋk3n8K 9-moVA7h Rpծݤ/juJ~E I>v_{}]~DZ 㯲U}4伱\G\ZtII;r <3 df}\ڟtêƕ^07w虙L0iVW:I{C`@-݊ f ِH |;pQ̠./53W=)xK.G_B;ّ))])eBljtE_Uq桐4UKW^uIZ"* 9]/P."I~ ƍ7. kdi^re5oWna9>;&5#K[b yhc74MTg!Y`a$m;h^4#j-_I@ۤ6K%Xȳ}JC7nԁ/aVM8e4Cn9.uc W/C>:sߌJ%MFg@s<[%@~N$!bH{4kȳMƍ_42X&&?ͳ]C( # )O$|ƍOG/|X2$p+Ӽ{~"s-YfObaGn w#!s{|p|ڒgkՆ̵mI-dXvmek#Nixe5Ђ?FN~[|֨_!OL&yFˆau-9,MLpОT*"2}rH v<65:AGy=)~N)ʑq+LY}H&];kM`a w h t l(*W. Aݻ5rL9("BFHT3Y&rD&̂! iYd .%7 #F!˹2ӭ9ru>Ӎ/3p3" -sd9INeŰC$ɳ8,[d"2O5U2Ebqe2 SL'ܟ$),B 0T?CU2HQ3kLPoܸqƍpPӂGjg>$TSqq.~G7 ޣT_8 ,].miN''B+^mS؟95{GJBLs:c" dgE8d]ҧL:9:o5 LqT~32 2dV$'_"s<+2Ypp<^d*ɬyIaFxWd{h ץL%:9t0uwp|XE.)yg.~qq.7^WY q`S8E\\_V [{v/~sQvc {q ;0h> lS;1.&*Ll21اihծMRFvCabO^}J  Ka.GxO;4\}$Uy]*hd3PqOX!X1$y,>슶bom5b1 |*C8}7Qf: s>^3qq.~qq.~L;:w$Od*IIR|hmg0 l-k[c$FC@s5xK8'pѡZ,}!m^,kC#Ms7\HمLCwC|j8h(?E}~0F,$J,s|§r\\_e8E\\_e8E\\/bgZvuIENDB`perfbook_html/node402.html0000644000175000017500000001537211672746163015651 0ustar paulmckpaulmck D.4.1 Conceptual RCU


D.4.1 Conceptual RCU

Understanding and validating an RCU implementation is much easier given a view of RCU at the lowest possible level. This section gives a very brief overview of the most basic concurrency requirements that an RCU implementation must support. For more detail, please see Section [*].

RCU implementations must obey the following rule: if any statement in a given RCU read-side critical section precedes a grace period, then all statements in that RCU read-side critical section must complete before that grace period ends.

Figure: Buggy Grace Period From Broken RCU
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodBad}}

This is illustrated by Figure [*], where time advances from left to right. The red "Removal" box represents the update-side critical section that modifies the RCU-protected data structure, for example, via list_del_rcu(); the large yellow "Grace Period" box represents a grace period (surprise!) which might be invoked via synchronize_rcu(), and the green "Reclamation" box represents freeing the affected data element, perhaps via kfree(). The blue "Reader" boxes each represent an RCU read-side critical section, for example, beginning with rcu_read_lock() and ending with rcu_read_unlock(). The red-rimmed "Reader" box is an example of an illegal situation: any so-called RCU implementation that permits a read-side critical section to completely overlap a grace period is buggy, since the updater might free up memory that this reader is still using.

So, what is the poor RCU implementation to do in this situation?

Figure: Good Grace Period From Correct RCU
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodGood}}

It must extend the grace period, perhaps as shown in Figure [*]. In short, the RCU implementation must ensure that any RCU read-side critical sections in progress at the start of a given grace period have completely finished, memory operations and all, before that grace period is permitted to complete. This fact allows RCU validation to be extremely focused: simply demonstrate that any RCU read-side critical section in progress at the beginning of a grace period must terminate before that grace period ends, along with sufficient barriers to prevent either the compiler or the CPU from undoing the RCU implementation's work.

Paul E. McKenney 2011-12-16
perfbook_html/node98.html0000644000175000017500000000657111672746162015604 0ustar paulmckpaulmck 7.4.3.5 Free Function

7.4.3.5 Free Function

Figure [*] shows the memory-block free function. Line 6 gets a pointer to this thread's pool, and line 7 checks to see if this per-thread pool is full.

If so, lines 8-15 empty half of the per-thread pool into the global pool, with lines 8 and 14 acquiring and releasing the spinlock. Lines 9-12 implement the loop moving blocks from the local to the global pool, and line 13 sets the per-thread pool's count to the proper value.

In either case, line 16 then places the newly freed block into the per-thread pool.

Figure: Allocator-Cache Free Function
\begin{figure}{ \scriptsize
\begin{verbatim}1 void memblock_free(struct membl...
...tex);
15 }
16 pcpp->pool[++pcpp->cur] = p;
17 }\end{verbatim}
}\end{figure}



Paul E. McKenney 2011-12-16
perfbook_html/img18.png0000644000175000017500000016315011672746022015233 0ustar paulmckpaulmckPNG  IHDRYnkTjPLTE͚ǔ|}g]^ˬbWYTIKΩōʞȧϾmncZ\ͺȤrcdrtklxdfˡβFBEppp`a̴vviXZ]UXhjyz~fgj[]нŐЗиZQSXOQm^_YSUtab˶̯^TVWLOSbtRNS@f IDATx콍{y/h z͠x4=\L^yMZ9ctX6gcy < V:BGv .i~,50TV`yN֕ K#K^u:cO*G#)~J?ܻOE^{~wn'M6Iq Ă[P%]! ==mmm/x^7toa 3Xab,b,;F1`G0.clOBqFᚃ8:_uǂ2'[_صH64!iF Ocľ%/-8ŝ/Bʔ'S ̵ߊ57C$E!lQb/ (iF|o"h!eg!~ )h`\M\.7jtӇV:ANcAZT+i':ݺu@T`B1T"!^j<}x->t$+&>5z[5B=tJT8˧eEʃΝHWthӄϯ'{FF{ rØ%J a_ssG:}E,>IKnE ۶yW?Rܒ[B&ܒ6t%: nWhny^a\/lBMN{g!2V 0tfx1b̲#ⷢNtqR*jn9<@q)EQlHvFHuSюe|FYb@kĨ!Q\pJ.%%b=cNXKdm&!]=دmBTpWu7K #C=``o= E=@:d8nh-h!" tV_xufkίTA.. Q_}knuGu]:˴$}p5ʽ ԯ4 *_ Z-;\J0CD ]8BK&RߛVI4VjyFKmsoC5!Ũ|) 9ȡoU{;-( R+#)hp 3S~6!/UZd*ۓWF G_?N.>@q5-vC~F(p`CzȴhG֘Sv<~ tGiP@hD8H#Oz)ٜW T;*ښtύa |?.<5*UU=6iԍW'KZ] bvq8VGzwy[gf9cm SF>O}ѩL#P)VojOدV驗g+N?@dIb@0@rhU|o !χd'Fiz[ׯׯC!Ь /8#' 8yi;i'7^'qvG;l4 I[꒖'>2{MKn2uq3I>v&7䶚o{5{Ukz'Q -es7`㔿G< i|mhVQcm9'ٟ4?#sঊX +o3,RHݙ7{Ѳ|?;ol,S\)if\Y%h (^~O|S&X0HN;O DGMO+#5?IGiH*t|A1ŗ$$^( ߰ZK2('cR1+=q w8%$o-wSm8`mG3Ta\aEQG|m dD2/=Jg8|󳊊v)t&J/O)?y[Hh'nL+2 nSG I|bC"O4NNO>ϿQa4AUt5hT&eI$L9pY\1z龢N- T&JN^k"=X C.ǹt3Iz _OB@CFP4!,{ U%2u˰MyS+v#Tqr5xWE dH71PR`'pNա]}lh!# CJxHWƷx\c`xaYpF\kQ_ц:ba%QO.RuyloY2ӕT"+!@v?%,?mķc|9MI8 y4}MJ6d $- Rэ=#本qQМuI%u $H;A5|HT)nzۈhhZcWԦݻx]/oB*yh=sDDOu$ᦪ؜M`:糜^9ako#+gY0p; _ @H^ސ(_k٦Ppv*]mRD, R+@y_6|(B%KuzM\U&hDzT|i/>/bb3PjGQ7jC칅pUZ.3U7KЁGUDnxP}pGI)=y4|`NYW-БB~&6UBQ^OU)8!x oMH|֊GD CY8_gL@ag'Oੑ-Y$UF&+7`АOglj TZBޏźV c{>h ).guA0]yc[q,3Z74"~(HqQHZ'*n2Z|d*`kBo B̿ l * @%)i(~&#kf3qAL` :KB'}j}SLrƮS=wYmOA)csi5AdnvZ~0@L.{3-M)/<`WMXs{)|ۭx@gOѬxAX^cQW,)57V&j2)vs}1D>ǝ ! !r!|ۮW.s1gұ!f E±Kgomh&iH*얟܊MmX! V? [߷m˵ *p륁.u]>ela> u{ь@t]o!QcKdUj睋Ķ]X Dh+D,<R!( l/V7e9ehe}'Ҏ)<+0d$H-ekD:0;I*+&ƶ'f43RjcY,Va(5HrTz:cd> mR_6Lcb2ɤ)XNPr?[wv9B[?s1\cEFfط{ 9T7{}I=w$jRYԷq+>}f_񘴵eٟc]wѱqB 7# xsp͞YDj`p1x.8TPlv~;չ(fc3LB&Uv<ME [.ܧ;I8| `/$WC!DHFf 5-%Qi76KV7^ ^C!))[ΤA#CmyǓYr/ PlBtT0`{PdyOHDtW\~ס.7dL(Pqm  Dekz ΃4kGfӊЈ6)µKS3P,);32@$"Rd~ؐuQ4SU9xYXB!UPE 4D*U(@?"tCȯ7 bUY9'rjk XA?' @zVl^}t 7!po`usء1Zws%I5 Q0L=*:6Xm%̄PfG+f{ySU E ,^@-JkCy`ŚX8B}|MMDbMn$Om\[QP`E^nxlvf-4}S O84HV Tv0UY NmzEqL %)oHq(P*mvЛ;hqejpXr0ZʿMkHs)(@)qF!q*(EbK!;q5 akT .,o?!yhEa̳!]]BP5M" eQtw]:vFʇ}aڑv{n+S +hbȻB &OvAJ LT7MJY>[^\@{mЉ"M*nU`LW)25;yܱ_a7ngذ,͍e rʣe\5jc{qJ*?u(D?X9Jmnc-3WwBMjHBb4H)_mb$!_ \ʢVTK.ъ4!(=YmB?(Jy$4 BG0$qiY٩U,:6a|_r'^LCHh>F{O.NzV/6\6 } @NM3 eF1aQGzvs>WVnp6w_3#A^VTR D% aO׏W^\zu<~{\Jt,i{zQ &{mڼ-bĤI2;$1~hT*ࡖ uQj 2( ǵWiUlbءAC!ȆωA"ltwjoZb WUwl5iz+A%N3T+qiԸ $7;pޯ1U?]׎Y,|*&P{Hf`*H RhVO̕/)bKZ;EQU LFE\0^{zhڙ/``I? ޳IyX4hCYݘk1-~\:3 ?vS?ڃ_-\GC%?WgiL!ІF0 )ܞ Wsu/OˆA>6'cAwE$*:=MWP f6;0Z#K|ȗNhpo]}zѩO_5:! /vFѱ#hVǡ3y(zaM>, =V8E44Mys&>ٺ&bG8յ+aF(2_I^Ӊ!Ygƣ$@nj~ͫ%W~SӉ,d{! al}tm5[Lz Q$DyiMmGj4DWEY䢁=<'ѮvCo_5( }٨Cຉr:/w1*n!dW0([y/k~,뼏lx忯U_QwZ!8=iJc[Vոg n^<6hV [},X! IDATaO)S#Lfcl*ϴK!l!7(ZbJjW`"$a@բx/{Z`}i^ADŽL6MXH!? 'OxmBM4Gۚ|qxr]8P!YY*vs!,3kd 9`baɾm lwVhY{߫hUKu~Qgw6"-i p&tbۏko-׍ =ܥk/X+%z931o:Zƃ.mWW_BB!-U?((n2ֹn+߼ev mڬ]{iL 1$[JJ(01t n#:1I,q,b$I4Eir$+dIHHf4 +)yV%4̺Eز5Ǩf|$@J c总v^Xbںq^r[@n&MWv~ Fz^5MozFtܛI,RE* 'D~=$}>Ygĭi>XNИѷJ:oo.&$cPvg[ RaN&l@Լ7Ҝ`&EԬ_ Jdnnb1BEVnlta }6-<R1WEmY5OF^T ~{;i_4 8 wD`O,56Y mś%ݛjOι?t1"KcTQ&LoSމsV_[V{q>J97 +{T̶KBO'Y_9K_{];x_x3)#=^ya󣙭6mg)MԗNPIu\]^Ač,e^B&S LFϪwrʣ]J'EءY|Ln6MTcQ64 @ZOgV7j4@CI͕E>,K1ۍԈ54UG(Hf܀+'g,ldPZBi yzctxՎ|fV~m *5+<B%r ֝\zOoz!?pL&CvdsT564YJ@mߝҐEUE*[q OmѱyfXt:dX-ZUi_,!'@&H cJQ @m-(f"/Ä 4S'$gj7|@ BA(3Wu[]꿸cK5k1rK*dAlOW`CB 7҆70-9ۋ3AMHQ]]]ai )Ў2w镩87]Մ9mQ:|[l*M{_o(ЪDu^׍]&A#[͡.Hs7w9܎[$zlw06o0RfSӮh0bU4 @4NUy8EΊxF2Htn[hM\=4";8fOK]6wn{G%d}b٠;xuZUHXRHA?Q_̯TTlc9r&PC)8jj4љ3pf+#φ9^G_Ä*N̂wdO!Y7M HL wYMCK ?budIBёm$R^=qN+Vd"cِ$&pjAoͲӒMOD\YZ =D4uh(~|^պ@Ihյ*D*BuER РO)qek=1ӌG8DP\ek-~ O~5OS] v)f{vLeаaaԄM M0+6OXLFF-s<#rM^8SC(5 KeVXF^»("6N!;8P%@>DG4V iH3"n'ƿe" Kӗu6/3YH[eFmrX}4gg_O547'kg_Q!gCdVhhB~URX@h)zk=ZS~2ҀVYsٹ-y9P[=(xLV _{dXy+'Ƌ_x^Be(  @y6M{%>P3_,pڒGQ. ~/˖iA A3Z`_ǥSISW4[eB -ž/0Te[rT5! g“)ݱ 4V#+5Hc>I2&y+;+ysQ:xS S%O.>?I-aQץ*0lRMHs + 0<@ ({CTN6JBp"N?:q%/\ky)dhƮyi/Yݝχ!{aGthHlаVS>ue2ᮮc΁/]>wyta? u{8Kl kOY%!NIǩq' J[7{P%1zHZe-7vOT^Os\zH G畛4 )r%]#2F`cA~{h5d)>{f'P;w)bj`QXL!*`}2wOjm=8M9*VE]:؁Jիr:~PȿUs%ê[%_f%Vp^wbZb$*vu REl6mya湅-,\ζֆ-{/Ӏ|Gz?T?+ (.SӼ%` 4@хXN\h6|QU⽹@χPP.UֆU~4[}WvB;4TV.R TA$IXβ43sV ZS)@ŦIŁ1}"*UKCD':1]"֦RM 8"Ў?v)UIZJO(Eގv\jàZK;$ѯ6E,طq?~V1xۑT!B T4wf<ۧ wC$PO OD@Eh& J8`w+GE˔ZobtC0w$Ӑiץy4;oqc7;ўd'HMb6өӀ#q4h*kmR0B2}QŅW.Cl81$<t4UPuELEH(:TPT 5F[=8lӖOd RSV"G Wr>-G345b B*^eQf I**MmohR{5\=6{¼kZN^ʞP! ;)fUXD%SpU`WH?bi ~! H$ٟ~h|}Kդr^1>xR.o%I"%~萧1t|VD9 & 0DG Q\Rv%:|עefkOWmvJk/ȏ>}0Pm@':0ä|\)!iQ#SݢӇK 31bϣUzwoCWZ8 /d+-?CbS?I|*2 [a.c.ώjwĐX 2sV1bBE֬s6僾u8(q98_<$.zzW뀜 _WY &^i/&dA ڧj/oA~hQJ?7V~2䶖סleTJ.p|Wa\/jt{|{;  +w&O>kLم;+* _X[/58 0t5Dp[kJu1 1&K{eܛ/NGHS/w^pKqj#W~i,p ]Ш3a41rcAKꆦ%*蠞â-^v3:?=LkI*q^:W:^#/O">jW^^{y; "͆`z0UU5j 4~Άœ[M|7@5EX2!y }޻MZ"/j:oz^.}wꕒ[W:AT%o\B3X4>0.i~bwŸWHc5Pv]'ja[Elr/'$X~>߿||>. x ,b鸨u]9*D4>>{Z5T{+:!HoMA_)lrCMQ8yj_|} "&Hul.?žxz۟chͰпps´O 歎#o2?kx~ԁvcZ&iQ Uh b)/r&,RUCڅ;w?S&ELq_S+N-}‰xkUr^|H{7bR84 qSE}~[ +lپNh̋8wycNt8>)RV~ˌDZ5"eD}v/@/*%b]/ƫR<l2UMf5+,e~m_;ocznBqI ϺxCB^Ŋ_ hTcQ[ݹl=.P-m_=~m{rb*8~o6/ yV{ڪӀt~6`%4$UʪA~PkۚiUn8/h)JaWk4'{h?gPx]tcܬf f,ͷR?1VzILBظtgN7{iiߠ &EjQ]CCۿUj?+I_#m `iVM%[| `cK^w]*wjǎՆ>âݴ&R&2Wp88G]:qD9J\w0u^vOɉ9v'L` \Y~,6]50|Lt.8׸0uk`ᩨߺw) 9r8-H vv":*Q?( Ydh!:<.?1 F /G& T$YSH 8#5_( 0ٹh71"d؟tu}TQ``8X-dP_#L3Q>䭹'N/=I& iI' jwR Q,HdMѲDo%[OPiNɤL>] jg͎(Ɔ{jW9qg?͏j ۩MU/x꺴2/*CuGՏC̪!.9 X]KDijݐj ɞ*ES$MOwV IDATOUrjOKT:j67`/S$mGβ5vS{/_mDsvIf+_KVE4$l>\HY^o.[Y6Qf-#^rLv>絪&烵rS4yNFij*}ħ`{ؽ>E([$dBL&SM0@x3>s7Hmz+](iKmm=˗˶13]LRG4#IcrTWocgWJ*ѱoS3r[[Mǖ@ Ɗ:R0/n([]oV-'(}9wdE ߒR*;j}XC(0T2ajemڃHMq;{]sd=ou8I,$m<2=-;-ټ4c1S@*3le5Zo/fgґI}pqg+Z`j+L_婗8Ղ>K ]##^aE'IM93)̒m3b%3i[; kj2eqbY)Rںفǿ`7C[#iRF\6˾"ۍ4Wvv K#[uFrc%6Wd[KϥK09vK7`pXJ& /Ea.F +rl@7J{vw8wC]Ԩ^V42Xѩ;$+NXD6Gl\d+|l݋3j3l$| ly9Sc:<-e\8V+tRTV%Hst1!{ѱC#ꍌr/PL8}&{4@.HBIS!`VH^؈ 1 fb@>DvppO l[s`Kg6ڂ/tMPU[dTIb1@(fa_4͆2 l8Ie|\ި*\`eZ7 O4WUnu:Zd0Rȓl6qۼq|LgyQ0-׮ ζq2%*~Mn8,VIKȔᒹD]'<8Hli,r3)>3Mm7o"j=/()+ ;9X$eoT$^nhdk\ZDGK{xcpUVAUwr)Dž'\ܬBiK{FF:"%BAʟŒK-Y"W2}%|'e޾r|Fm{YΓ 4PadlnSe%ծ~#oV2imZʥJ3LO[W??.%.fSQDsI\.'$Qu-҆i*C+EwD5b'G } v^ 'ȷf2^}dgf{鉓4 &0ln$@:c(Cjcy򎰞7"mMOU`~5;r%1wd&*p(c{1|^{䒛EsKR<3{7KAnm+CRZYMv&5"v]v:}tYIL!;p.|QN8U#n!^үPxe7\ !^֪ҏ6vq%;rӕUWDzbuNs/v-u0A֨jsсOUb|iT1U_E8ϬJ!MZܫbFM[v]\Xp\zxne7azjzQd4mi18qZ0~JXǞX]kf,ϢvOT8iW z("#+qy(1zs|#alVz u7Q"2Eaw+]\霆NܜP]{k6-#fYw}OEn-I)dSrcUT"1o*IUDhv2!ysBU8#nd}s﬎[uPq-8& Etzx.@i؊V- O/. [!=̍& >9_nS!;ꍓKt< >x)cQCYWEB]NTVfPJa_euZžU9iWI@jzOcj$1M# Q c)!;XHq[+éLQߊ =,Rf=@Oߋ\ Yh>&E CZ -MĒ(`LdrhD1칕je_#RA.Dlg*`lXJɃ˭4f4aK/<2c~@%eƉƄ8R%JU\-aa3:#ޥ%;#o=/jp߸PYF3wx~Cd%DL+("/GLZN0e9LTO;򷵄9N [otv-/t9I^uDKQf%q4Fwn:~=l ;ZiJIpyyqE:k%O ϙψC핃,2`9: (q$juD%]]%twσ þLz-YoҋQO}}(ĸD\UPIiBEF`_+nS2Qʃv8ZyCp>ә"CfRa8 }U6IQMAٙ"abMP D>l&JxDsW>^Mv{hCFFUk x@4*2a/EUAgOTojG'Haߟr:VLZsi6&]$0&=Ŧ5ÂKשRA ;a״((] W;Bu,)p(hXC'ILQ)5}:jh ]s<V_Z'#`1!بf4ݸSzHkqj%gRXfb_*a/ԫ3OmS@Ѧ#tZ]i|2rtyIeTiNl:DEE@ G4*-uJM[*}KV\D;Fv> JHmVg/rX>8-tF35`$TT"g<4^*Ua;;{ 7$Oدwwa7t`"[6W&F\)&UtF,x i(/ Z ,우NP/f Ne[y*8iulA'TGlp@.R EYS5 Ag"'P-Ěl^gM*3QF‰FW#ޞ@G#Օmg$ Z]Pb(%jHYCf "UTI(l CLIH7j 桁2,T {j8nEE 謥&'D֐hE&̵P|g>!bgX+zvԎCqe=h.[s#V5d/xcea,v9 "Cd\~ jtжb/V}@}&;gYݙO{mEs"+wShHy|D@]ՔI*QL2AؠN0_ynjd+& Bw -@`{&؝д"̺+A?ooQ |1(fiO-rph  @uUK<4~'ҍxt}uxe9HÉܶAupî9.O++[W#?I{<ڒ U88ӚҖl1AWl*M]߁%IgnKT:#aN4V<45Eg5(BQY&f4Hᢳ$mF֯g +VkH@ӜnavʎA휝̦Tn]"CxY)P05 hn A[i?zaG:-&mHaGʢ~nSYFS\SyQG8pBf"D Q4.`9sʕ7'mw c6mTw.΂3;oZ/j_Js:oם8 0yxL7MS ۹I¶o7NYJuml] λֻ8hFpؘp*B+1`ù@&=H+R'Yzʖ+:@ +n 8x 8k{ )!i;E^áTa0bXŠբ:x6Xe 4 Z=Hbwl9{6h#j0gV4 GM0QLHdJ37[;vLhLFFubuZw+&ZJ*uijtJdT[h7cդFE`ĖW`hDZ6B#J5=逋Fi[n_07 Вqg0p{3`WljQ*o W~e$?KT mM3%N8$7Y.E!>DLKtA:^;՝kڴ ) %ۙŐxa2c=}Fo1};竡_ۨJ882_sE{zaGIp 3m6P]Y I &QFCv qbL:!@2?ʉG$UXhQ l5zZ"ӐrhՖFb dR˲ă{ C,{Q LϼdDpLQ5X7_DX 3E*GI%'[@=8ko-FZYyUR3}Mm=C|Hԟݟܥb/puELp{Cڙ"# laou]WXk*{Ŀ!sV[QG?$`4"?oxPf)o[XaTQ 2b;&PL-v0:JϺRΑVd,Juj05;֏ǟxD(զreG2qͷEYQ&} VpV#U+^r*CaW:롰:E YqK[S&?8FȄ^&{TJϰ A 5lF 1oT8*d#՝t)~+#*̚aϳ۫z戉)pS/ 8k%E,>+I|%U}6[&lZmheqdw:TYvKpKwX5aLnf'f{eJ[7ϻtfAuԜi`*Bt0[ +\ ܌}T=H.d\{PKR:~A?.6D{^8:Qi6bz5A?PvrgES-yBG9=*n^m7ѱdڍ-IUgN۸!Qt˄owuMn~v^=8Vƿ<{s8:bTȑ _r4`?FՂ֣++u:Xgmƒ#"|eH묮TZ֦bo̍nA /؁g446䂫QaP(6><[3iN?K0",;WO .6G gB1mTXỻV:#Žn[/]/P+ |䈜oYɥWn]Lmi ,pbnV{HXF' i1c :򘞮}w^86]Ofw|C!Žq}hʖeUUGh҂KVve4&~3ž\4ˬ`4kgn$rƶ>9ϭA~TR, 5=Ʋ32̌ZPbvoqzGIt+%:?cG ֭nF_xN H}6ZBî<8]AF,-ǛadP{~j Ak^5Sohݷ&F O/Jk[uUXaJ-xR|G ~Od7+׌Ю?hbϹ7rC>+<;bdhn!g^CN-k[H9[ޯ7"ZGY!EFq^w}W#g{8&$(+l<"5o׫+wg+5ФfckC.? !Z"TTCǥ#E>ffj !L{FrP%_E[t8jsg 8ؚ5cϾ dEp\62JT1y >Y*#Q%Ɖ>yG#p:zL'i" S*Ј .,_w6#[{퐞+{B?I>OH,E(r٬_3$"C To*zΪTI+WUF*HD22Fw@ކ?8;Mo!r|㗅B-Yn/ JK‹-3Ҹ%+ʺ{]nnc1 p؂p(N,5 quӚ!V\ 6*<3rwh}žwzi?Һ=Xrs]! ha«1w7K?1$,9#iUUt4LHg[\Kgii3@m'[m zrRiY߳h?Pf-6i|"/7iLJ *̠9d̋JU@"j}|t <3 `6WߒPxh3M/e=tEj]Mw{ Ld lM^% >$2%XKCPxxrJԾ< & s2<)k3ñ9YcCMFihXtք<-ofߌ[i_KipW˺;z^=vUbƁD,Dl7@ñX᲍VMYzL(Moh^L0>Cd1nTnC\0u~/h%YDvN08Q }[E J;mM M12,=7kћE|F^M/G-,]3 U:5)%:A eتoÓ|w_!)3{qBD* b;QA<&tF.ID (L!T3M;qr1}UŖn d]5bGH"-ġXg&sD D"@rF |dJ<zzuO>p!KKoZs`&a.Nh K(6\Aj 0qqӸ 8C&ff + ݦ>tGz>)Z ] ^FN+|pZ7.ƷUY!S(eYUr٭LXA텘bc/}>SÅ6wDэ_1~[dedBnsq34!`dYU&48𔁬L՞[Ll?͔8{-O/BOc_,.FVa"U b ""t*$d#)"5zreߺHsϻŀu6e27Sy ߣ/N؂Z (ր$SnNdiiʱA-옹<ԍ OpCWCt{'UU"oC*F0D%4B &cC >+ Q- x:7Z(%a.k}:a͵=kGM1|-.6PEU5:Sz&V'%c]-!'JD/~/BRVZ.˯3NpI^I6t^L>4t,LYHVPr〉#M͠tM=9<\hnvyҼof!j ݤ-^tBiRhs!'^h$"balXm+*CKWq:]ϣq@Vc5dt2lFj3a=^ ?srHK)N0r%}c=q T*4A|L!SI &XEhqmx[R\w+d1ɳexĬX=nSw@H\1;W {o \}wq\Tڼ?"YUELw$* -*-Qvk#=5QW(x.wBHPLrGj&.d``cE9MD*U7-=8)1 :Ӱ6YD.GL0/(,=BHcb _1(AZ Y&C&߬EE4E la=;bVUfL+p_ޢ1T;s+4k3=jd V]UP?,9&s]K& =$ԣ Kє\RxIѦ5\+l|,6{ tg6bh0-.뻌n4v/03j1$Q8ePL6ؙ衋Ñv0A@aCyL+p;ֆlm]+OwnEb',o졲~1c~ I<e̯?dEގUZN&evEP/=2VkܹM̔>}]YcsTZЋMQdž[8 DrgŶ@-G]H90y+*<{F QZ@槹ȩʴt;tque)!{ J$yTȋa(d&qprwt- W " ,܃--ǚM r4 m(hsW/mdlj9ě'nK]jCrg0t 2 1ʼi0S51swFEByV;6=S1j|͖XYֲESIZ9ԖCB鞽gug*rHݗ.' PTa&Oq"CrHJVXwź|?0yI4eӏ7gbl#7k=Y4kj]xlIVnɸfA-="^sfw j*(|UHe W=j{]?N=bZ9÷{WߚԽ j)IZMr"{kAr),;l^',[ 4%:FFP^n@_Fם.g>u Wc;^qCHLג)B4ɏ8_cǁ^(ּt{Kjq[/IFt:aGQ+YQ3&k9q.b*fQ|[8&G3M0U{ݜs*r@U3@İz\u1U~xe;nBfI-x̂4>&tY#{eT(6v>hk/>I AiTҷu*M i烜FbF(]'DF\x3>b/q`gjE0 <8rX79Yv鿞K|;{S8^3)tO{U:j* =} 9:bhxyJ] ̓k5ov t0{v'loZF/v~|~L{I7O^BT8P;(汩rW!'vs+s. R(Md Qn5g^RLdI\$#APuprڃ tsMYWv![8r['? 7Km}LV@v YZZD>T^^'g|/3d(ĺ7sbu-1TPJP.X'P/b򺩰sĨa݂X쿶sB/RPkk{]T~nuIJ227&C6EpmX&漷{N 1Wfcn xŀi]pN1g9Wk om=ViǺ"i@hL,_|RXGԦuf=uQÜuFn "\X9Ax8_PbWkCnlO! gj>kA۫mJ|IAY#oMka6SkwdsaGFu^-O{ 'Ÿ$ܯ1`bZM/L+=@ MR`r& Lyzs`OѪmՠ_r1 nKq]nXʕ"/J[w4ۈItFdL!:Cv" uPXѪB6V*l!M%74ܵ)+H?]Dpq1YԲ6M/TJ}A>MD}Y C7 y"A |;Mz,m埠={Xm'B?q7bdj}-Xv:kkُ;Wwd?g}/咡-eң|g)%%^*;׶-!{:1F^:qx##O4hf?VnM$" G#zgR?bGNTFdWDa7]8~ 0ۿv=dF ;+iY4J}?xȮJ#Th"xx+U9^fvAK Wc6`Z~VJ\۾}x/Ͽ޶Hd68XHi'_v { ՝;I3#*311!bU$PIu֟+|>Q6RV]#j=t&Ƙ"4 DeȈ f1G{ڂكt~דu_Jgv)kD*fi GoYFA6NG՝KæHNԌJ>fVE )4xֈe!dI8jbUX?Y9p`C?;>~b#s/Czw7&MŬ𢎏 `GFT3 d-K~Z ޱ;LweBȞj5[Oy "5_)Y5@YV̓_SYx_ ?7G7cnqglnwuguYi0~5[g TeAKyN Y'M/INh00K8{mkΟJҪBTa(Ay28lxIG[]7CIO7;`Km)?5Vy#ўzϊ #Z0)ۢfN$ Ė:'?&p,2Lo\b4'$xE1߮Q5d;__/SX2z+]>Vhһm{>W沬aآް?*-@=t-ewW=@Rzd?Lf և)_aZìFfL(Ý>SY8Q->I'^+Pq}h(YJ,m랁mb$:CYnLL- }k;w֫; +jB?TW:Wݿ};lTW:땕i8|TN:x?c|FY7G3}퓼}Bab ӟNtU Zgڹ}vh+;W#J+x=|Pٲj$Rװi.#s d/9TMo){l8k'd"3>$ Claz _gg=LR]`VhFg=R s;S `Yw`T-\mJRAK~g`iȿ|d|@g#z%0 E#u Jo*1@^:AM+|Hgu5iZuņ*պ +xǬ%$TL[{98Li0 ḴǥyTG\ϒ2izSR;jQ.DѨ@ @IsQԴ_s Tmx>;2;Yߧ8}i-bnF&R:KHL(CzQ%@5b",\`>8/>vnGB3P9®]_G"Ց|&ܳ#_\4>>WwOvןurUP RT*㿳z7ʵF7 FI`Rž9TxeT=j9M* n병|RF|m@o tZ^z_}ϬG\KSRBB#ްe:R> gx΃\dz}S2lqaL/!e(#t4"|\w2GWza:r2=[ozQ:n_ &3_,?l7DP8scj[}k]5$\\ȬxDgφp9YRl!W'dX{'_{ 'eچx! Q (|C?,םY#`}TYA>gC"'D`^?5s[cT IDAT#=mGzo?!HiA~@w^Ncl%2(wݓG۷'#+;iXy hf0CU9kT$O-ťQ yo|ee= i<9r9U )@dCDP< a+uՍR[Js3G9LX <9wǮ (iݾ6!h[pP/U# c;Gٕld__k_*fYus7ZH N 4،azC4GW Vbn6. VOI_D vV6PqǯA6\ Qe Կꬷh/Śƾra`cY|YP"xGgg9Ha< 9?rhk_4l'FڒTtl~pO6_x&k(-}-wqey3yf}66`U:D*}D* jlTg,fmNN/H(*&Y34~R{e>vnqulw'Mv4/gq5D]`~&km$a -zk$"VaۮTFFHe F.68edYc07oz ReJ%:9g nߵxbމ?~T yGb[aԮ{_HX1<*1pJz#n"J[4gѓqiNOChSo]TEMcX^m K}Pp},ku*3b'O)JqL$ưT\W=<=zHia\ZD +Q zf{'=d\.% jp 9N%+QDHRzqj:֤挍cy7*zKp^OY15I$ e9uU-&J t":o2rκ\FN.ÎRoftG)#ڭ#!"dW[qYcɰz9 Yv]PfqCP&6-ZL)}`BUd=Of[@܇5gFpj#hL%0g:>;XXm(%h*7 c ȑ;ЏADR^2>(/m0O  IMfnpF*&Rt@>"dx0_ʮC]Nuv#gGGAC\GX?}:iOd4%ҙc WV듌xHJd4y(nFyכbؼ|09R:ІM"Ia< 7v`~jW cqOg4#pL"wΦʎT7>{Q=aYex&e9|QHa{g5߿kdJ_d D3wT2&=ݔRIL>FTaxĚxBO3?ʣQ)a{ ,,\s"#@#aD3Uբtc.{Y:wWW.\c:R? gG'|!"$:{= lTHjp`ϭ$2Q>kwgt?N``14Ukb'5*o@`lp;X/c K 2td [ߤ5Վ EXc|va!Dfs.۵ = ˥\6 Ԫl0oR @7yV0Y:D'-Q5j(Zֆ}h +-l)C_ul{2s#sskrd`5$*sO'C LpKpL=`GFxtKkŐ%^'l^c>[밡bUu=CTU/=-045h-fp&m:tJ#Du2p{#S"`7 IG iդ9 j]AlpJ?E5~5Y^Nvvb}[ubd^ċx\I zS=tRa{z-*g٫I~D5ufl1Hӽv$#~JJ"iu>'Jw˩EM5-2h<] o}yKEDUʃs'? %~6 gf++Tg#龴PeF匔`h`>\ u)1QCY k2/95'2 ^DUqTljR * ϰ7 }Nw,i) io<>T h-fр¨8'(%M䑑H[{tJ}eOdaWC%B?v*A"mb\iB%d^ê(E#>sgغ7R&p :@e^#Z5!5^^ʯԫyBgc.+]ƻ rܑјeN]lJ#7mŊ*seL"T%OӥBZN%Sj-zIiHfRi}@ʣHE/-'ǎN,?LNb[L%r>ůcIPS[UBkÆ].wd{Mjh/Vٶrg)pVrBnGf+-iSZJ67+`]+p„1b0>IADx,`X !n/#-Fz 9UDU9EOٝqφE<>ucˠu[g9ع^y(=QwiCbwfuv\E"E.FɛEp[ᅑR[癕խAꓭ@׈153 {\pk^T#慞 2R3`31>ΫAD#5QʉA<B{^w˕ÆiШōP S}oby)Ru rN\ |2V ;^s?Bӻ?ؒ0b a "A =Koz f _)I=2'\/}~t͎t~ށ~@6<ƝMbzk԰ 9Xh?¿=Ze^)|k[ލu[AI\-*LcN=&6X,4 K@0K йhLF"i5,D8Rg{j?w(?VrU.V6T6,t`r`n~ R}nJ[h/0#S/xgێ,s*#5)gx0nzX&H$ n}1v&ݘ*E.jѴ}&Nķ]ر="cvZ^b[i*įv:Z[+>CxdۣM7F:9ws?} &۲mѢ@vEn*NjZmxyEk/͖g[&[nb^+JcK]7[QMۅ`>o َ4lR]\#1oV'U=(n0Y;1 H!hDjC0D'a/Z$J߾V٬ųX]3\Ƒei x1#;\ d#JXi~6|\Uڽȃ#O+֚$``Z`1 S|DpWM 8Ta1 K$bke_=MUeam#.=+][zt?Њ{Lk]B{^sL/M"|?wl7Yi5PƘI,7c86\jk $DW6`DרKޯ*ʠLhm{cZ`vȨ oW\ᾠtkG, W9G{;U/Z{~%9nj/5 DZȝ&xM73Xh:X?ZybK ڲ^Q, G:_^S <_Tv[.F OrM #KΑk:˵#Ho0Kׯ_05J嶩ȩ5b]"k@MNy " ħnfypR]C:bX-HOA a˶jV iÞx }_S j-Fy9˟yO{Ku^^YXV.s֝Hv@ ֚pZ%gO *]}d^Td#ٰ=$ pq8&14;|m^On(IZ*dٺtۛF6ns@am{:w^wϦ.:i}5R Ȯ]R6Vk9kd etuE, 2QBǙr$N)P61uxa!F٩F" >Zikx L`)A{\t=ؤZE5zF }DxP'bF MF5uH;6hcBdL5OO`5 Ѯ 7õ7yT*#kZk;QYp]#o%6@ܚ:2D9b IC4Bl` {)yrty[0t4:GQnIhvǢ TNc9# _7)綎T6̖R^sl{iy #mʣxQI:_!] A^-[{*;zֶZ"z̭fyӸZ%Y*`Ԥ&PZz)QPCIvLSn=3\ . 1Kρ)b[kY>iWd S޸5T1ϧ;GVKy&J=zrsV)r@b9rZ'd҃x3t:D-|`SP5!64 =UhR.>q : FQOs  VC] 1KCzX5EO_RYXhZ^o|ɮz `g|[ns0~X+~vv^~ D)>S;ׯIje- t>n 6Xhg n*`zYK"10Q~u9jx t2—6L>ɐW{-^PlT*Z#ßm!2QTyif;K;KݥZ%rAlOϼb"S*MlBU(֢X)*UE0ԝ'( =VOnEALO}k5Z#,W{5oG껮o ެk8ފ`-2\Ȗ2iާrk vmFs $NML m[\g@ ^x vja(< j}6Өd š" ˟Vۧ`ܠ rS):KtBdMtd9m^u;]{f9|<3{ӽ'rqڹCE67"D*8ƅj@i-W30p Ә+\_fEYÚE/N\އk5]S@c? ΠtqalWO,%Vlo*,a|TyG\Yjm>Y+|SiX<Gdz@T*7X; VTL49э"Bw8\mkTT6)Ցz KwPk6Fo'GZC2KaiK%~T_y -25;hlߨwΎV@RdAHT$yɐj׫4S+m-Rx9wꘪ:HU]*_jW{t\]RWV! ##YIrl҈%Sդ/UզxZ0ܐ=r ՛phR՘j6MY;w]ε>HWe~hkζʍpH6 IDAT@Vvmmzi$r4Hyj\^mdA6`5`FA,NȰXLTƛ UPp˛a7b;LLu&S]LaBhL OnjXJ\b|"U>GW{Sܑer%"g~}u#Hm8Zz'6KwzӚvEºUvU5COpI,#SkF]+0 ^\;`T(BVRa uVJCx4}VeײϩlsBdwr9\)n P#7ɦחڢ3Fu3 CEs ץD 5Q Ƅd f&@5U E5D;j~LԂ9] v.H]\aGWh,1 "wKfЕ|l@ӆxl}AUIH:co1DtuAouJ?ґSo˽l(p!RnkV5G]PY/"1`H؜{rϺ |&[">AyA";S{"#z+u^6[/|掏8|iǫi8?5q'Z4tH >CՏTPZL&MRL:QK8Xٟ6Cb}cE0Z%b&?bdyGڔQUDpSkg5 K]6'z{R{vlyй 2J^TNfvG4ZΘLǑG/3\]B_bh;5ޞXaLف5j;Q At'h`;8kkrfz7RçG8<;<;]YGG |j_低OKā߳2NooN4S*fIu7/w M0eb'e\űD/O/Xm-b B\wI!7-BC'BG&IdnH$a^RCdQ`S$5HWe]yE2B?.}F<22Uڗ.ⴰ:q)O-pu`YҞ~7VpҬ>4VbaZCWG3!b}oZ0JR,XH%qRv<&Nz|5Z^~˵HEbD/R4>'9Ȟ+hry_A__VC=ڀNu :*[{N>zi9ȪR27g) j2D2xd~z+Ѐ>S Pw2%6*.:+5enAQ)іwX e QիZwRI1^GPF! K6 ?va2trb?]j5{2rm>@݂F샻U*l}/6+t WY1LÚԫnμx#w8% 꺎Ń|fElI?R,?yJ-,!K ).[L_޵*0ʒ-dc^mkP=& 0g*=%"Gt51[ċOb aX,Rʥ``i'1=ޖkϫnwFuVMAkrU %t+6/ 8dBV9Z$%O>TbdgQu*00BxaᅞԵ jP'{ X!]kmʣ-0o -6r]y<ܧe|Uo ź/fIԵrZhAOL׭db%.˜ 76v}qzr|= ։gNqE't$%y32{_R0WOyHT5븂,y>u:dFr&hJk7=ikkw̿15Ybrn۰n_][~M:IPyI#T{P&1y\ :& &ؼju%N c {ſ8RFtv^3фo5/'|)H> wH?:9!S Rxhɤ9#,7뉀З~A$8f?oꍍ3_፷(T,N [C$V-O-%U:~h bkj5ybuvϮ=qBͳZ*VjA  Hy>Ow[me>=ԶZk {5x)0BY߽E^-Ù0Tß+/N'6͛sЄJ8oj`xi{*G׈Upv{^,9R.;6;;VorR^a2|sJWR_W%N=4q4Г(XJ}aN;ha"͂3XUo䜁@#Eng)FM>]Y21fݣFL l**9g٣pE)Zs#<5|Rywx;yEB%9XL/,&H/ ^t'w]ʾHW%2[Nug#} ù41CQ K~K~=ӗt sg#s笂31dbLZz, mhќBL$iUFYUS Q XeHlnC jԩAQS3Tkr-ջ[/k"!gGZH6tOSTZIM OVʑuξsrfqy zmFvayb($uX oE p3ؘ 3ND('DHg'@{+Fgقk&\Թgyul;wLlݼ r_P5NtGZJnsYp?\- L, 'Q ~bti?GUعĩSum@;GQ$,I&:aU^׬nˏKP+aۼ e)V%$Ӧ%X3y6 XIvLgn ߝ P8pMB\VtkiPh/liZ(`v 3@ʻbHZ& n-yKrVB1EPMaāggSNvqlu#/iOU5d"U4TME\ҫg [cp,!J3.v6P@! ~inJx'|-D`Q"Q_ALᶗd>!S,3 CY! R AT] ;K̏dzH4oTy*33Fht,Y 'DC;h`־/+DX [-Up6a.// y#~?Id4$<:t9& Ϥ>Z3dToT'u IDATBSi[!8=Еp_5FK7E5{ҋ bUPyZmUO,<`fr5Qƫe i2ՌE0[m ? S-dFZ+0Z+d,gF[:(ϙ{MqcH1¥Eg VinD˸;8?sBg1!`S Yjz)0u W XG҉z8C9/E5홽,1f X7•%߿ܫDŽ:0MCt:vD1F}c)POԦZ@{$Cڛo&/Ẇ86?6涻b5Tci5B C1`l},fy1T9aK1 d5C EH!?v?~ 69!gШ:3o6aᛙ=RQsOhuo{ТN2HHu42 QlUA^# ~`x2>!gQk,$"b Ȱb -&uIe R PQBᇣ >>j͜>\B [Y?qf/eG0y͠/{7&Ըb)3&nd* LMm& '2CD`ϼ?%`0cOtqOnB_6ĴȻBV2v?YZ>v |UE? gL~%,+ Ył՚v`*3*&}^Iưjr20-ZH*Ce2SL0 SQq.!(p#$K~GI-l" D{?(,(ɯWQ2 !A jn@NX_e:`!ld7Cs0r(VH5l|xj%{ya-qC}/"顟a,jCm1 B<5~H5[w{ nm7+3 iHBw]WEVM0䴢repzQmiP`Au5+H{,+#M3 FBU_oΰg{]~j&ӓNAy\J_$kL,d3@FaH'5$Z"j"-ԊҺĉjL%1><,MiͶf/]7]ĪnU ܟWP;4ut8 ?'?0Wc'Cc'-'~lNl>  3b_3/4vd,ςNWd%~7Q#ǽ ]4fYK 冀S2)V 50Z]!pzhQ穊H-zyR[(IZsn%^:?9n*K>M/0)vS)dh ™%h/?wCO@>o@w@I.,ԗ/+ ^Gy"Cy,# pB{oX~Cus&5<Ù(:WYLr `uu1ڝD) e[ONPx=[pBU;6ym fZVsF^g3alRn'Ԃ!CBJq%JJWQ%疂$lN9 >;p;%8-W(~P/"eAi!务 I"z3 4Azrⷍ„Aē9)\}XOGa7p5O IujQQC$&QzD5fum1154&euYw֌.d%42o7tHA29؏r?fiG4V2رG /f ^6sʐ̙ >w_%xCm<|LI>ڨp2nNf1c4-ΠqxW[tX<ʙmvpR6i~ PC=[P%(NU)撉UIrY8Oޛ0gt̒3p 6ZP{ FeAg2ʼn;d|# 翏bf$|WY]~k'&p6%$BWY>z![ɭ,M𖮪iä7?'۶4=4=Oa85q8߷-U$䰟 CT;rCaQ{a!d1YX4\P\1S=;T=09Zq86;df(RE~ur ޵:m) DӲ$@/抍}ePdaB}oߌ܁;.ܑ%DvlT=p *Y{sOtw;-40 3czI"a?3 Oɧt&A;Q,pOݼU]OiP!oR/ ;Lg&:M1B|bpqY*Gچp &=tt9S pFq |f#/) MtFev.q67Fe=[/bC Z傅pPӜĉY.wlI3_fի>իW&T CiY V/ 4b`tC}g‹ZYJSJ' {tX5үfj,&*Nn 5Ԉ>OQL2R0LHRzZ$k;+W3{3;յ3L+_ƺc#o9Jڸ|ӝ\4n~b u&\ ӗ,ÿ+gс?')kQ0(T6ǓP6 Q?v.  aN5xcSV^= x4Ulcهs<!|6 8HijbQijSg莔2{H^VұLO' 0*~1l0ueQf ԋ65q1DWk.(u/Z/wؚe7e8! p+y,ʼHHcGh2ȖR}.&oqxj̽RW|&{_j  tGR$Vw I1渐vli0rFXz̘S+E32R52?.y}VNfbf})ɳgb̂+:ZUX~'53W?82k^r=6et9(c1֗Jk9Em5tՋe^Di.=Z {]ɮsO@ʭ77~vzl& 7ܯAi8+ H+&xeR9AY!xwQVv݌QTܵz=n&vB0t6%vVt;Nk ětLg%فB[L+)1PUg/+lDր#78W?!p(,W)u5u!;gk|).]2%-?~Nq0ژ4tqIᕹd slKn%v=<Ԃ2L}\u(7XJ])#D誥gٞc"HPP. VY; Fa!Ȭ:๿r,cKrHKJww[_pe#G$LLk_@r`oU/b@1e!/ VĨR9:cKZ]a_*/P!iF̝2vmߚqz'vRB#7o6u:\?3: >>@ճ<4CEA#&Rlnp~z+IAڟ3=%R)VzVAZ:,O&JveJʹ^:%sơj[G'j۽V]9*)W-rWJd\y:۰<6]QlD7*nT~ҍ3JUΉi=sj}*lf.;b[ܘ1T^%д k8MeAzn$zc2*p[iD+;_Z+TG7OD eA/{`6ӕa/Λ,f4ޣ?b^,-!yԖtJa$\u9彰\zm Vn q6c#Hݚ*zaӠ54Kڱ!)wN޴'R-lZ HF W_ 6T)'^1h$e2mf>a!Hr)IW8nF"܄QHdv{}<;[l(?љCziwe{0\<ҙҠq?x2etXA33+Ϗ j:IQy]ĵ'}7&oY {.k#k)咁\Cca2vf԰B[ 4y.< nL֑2\Twv$X0\LDj7srP_ɱz9d|eu;J! 5/tqZ`wcBL~#sD\XNɝx'< 8o#YQ镮 o`x o<*=N>ߥ`'8Et $ZRC"]rhmF }^&S.KIo^:0ع!^(^mE"˜\n4Ș97g?ϖuŒe1el0{^Hr`\] 0Oυ޶?gn߾zrB : t,bi@LmH&bmF[tICοRq‡97m|d~g-')W,\U?YJa fG973g{5ذ-3vӡGv]^P*?-5;̡]-7޲J$=1(~J*0>oA]f&$D;BPճ)!c:9/:Ttnb)"EKu监2[.Rqǻo$]z~넇dMu˕F FX5ЯEc` q v?6Y `ĕR!%&;4 pP%:[=iRA]c'Cwj&qW& oL2*X"~TuX]#ucF ElÑ=(.f7/aZ/"=S#g=zw֟; u^o|/thJym( u 8K&-4m?6#%$@S:=#K5ERy+\5:fj"}8.E t9(˘IQ̊OLEuQRgDo@ QK %8OʓU5uT<妹lqM% qf-䦃q9j ljW2w(|pGj7WE>j@tYVfwLL]pC0Df ϊhYϤpz'[c' -09b襌BGtC1D`^x3]`KaHxiM-[" SS(1,x؉9!G(;2/⺭GgQg[G'O}1om*]z2'kArNBL)9 Cn@ MrFv=Um2X\U2.zAtz#A7g?O\RVHJ{ؿ! BWGKȀ Hk>'<ݚ,O(V^2OrTa޺ꎎEPvt|9q_)/c$#@ԳzC39=K}ۇ Tn{Mq'3@=; 'd6м 򏸠kSDtq~b}Z m?('ʴ1՛]Dž?1>24y`-+:^\|q96H--CfD؝ .󿏳&T|"wOy07| JևIENDB`perfbook_html/img311.png0000644000175000017500000001553011672746025015310 0ustar paulmckpaulmckPNG  IHDRV.!+bndT(^oc4M'V?Cvڗ؀%S,v$<!Z2^L0-6mEYW\ ݓ³{vwhONcyC?%/% خGAXT){"@BrNGZHĮ/5 Ԩؔ_i|A79<%9#_!=g(7>XaL,u& #uKk\ot{AjkY $ZͲ/FцSH }j)jԤ|Y 2H+h[ޗ$jw.[ܔ7au썀.>F#݈'enlyVX dS(%ubDӮܳ8CL,dA3TEPY+cGq槃+*pBJ QGzP ;1 JGO(+x]oXYW0XшO@ftTd9d'SbC5b+/;Tf"1vCO4] z>5 [i7wWQ[u8$Z sr tu à..,/WS50W4p WrгuQ7qWe5?'N1# 5Z$bOb Phf3\hLT2g/K,宧< w֕ h6qV\ЭML?}_Va4`' p\T {IycOk鯫43$?y1mOj~qK2e=D, xqE#ܒDб:c꫼A Z`džO:K #AH 4!piE8q ? `c̓ 2PH:KC(7#E.\*jXR+ (2ኇO B tLOR4[ i%$K *IPM O+`-%WRmp\$/?}co;wZU/9Cac~ O s@m4v2}/[/TL" A#&9 (vBBuEE8ՍWSP6_/i~Mn/:+-nШhaDTLwO⪠ϑ67(ӨՉYG}){ ꐀoEWҰ(mC;~Pa8 # סXiD,n ˆ$)#>~% =z\('cxPL rl9VLW P:z:!A^Fsm0")b?tk%Q>^nQa>q$eq&zޯ1hh\ݟIk d @}Z0EeHxh<žr&UiՌkb:'y\ TU %C*R.+~ Gďho0[=]jW?'~D ~# $hkF#\''pLpBsR[cYp$Ac!5L%Τ<޼6bH#ʦiNg%42Xa\97Р*>C)hӷ_+WlfOAjk(G2uֲO~yal;Lh b'XW%DupTfY8 i;twdTMM<=ڕa_3A1^0L:fƛ~p_ T ~hp\b>#ֶ(z⤱:^+s n%DzuG)c{":zN#b@YE2=Q\X&;h/- vC|&G)n~A}uO Ǎ &U[ ƈBpT*eŲBߔ :.sFƿ4Nglѩ G/:ܬANVCoB ###v5ODL0Ir P͈[.7rnRhv*U\#O_7t +* B0slzċ@h”&즎c< cpD]O_O&:ީwEZ6Ox&~{3O|Y>$8jUauܬ:Y뺈ry>ȸqzot}Ewr2p(C4{=Hw ׺5n:eUTwY#Ť ӊFv 7f'pf9*,  W:WMyA2$0,Xnp gx/܁GiקbƜ̸yr;UYt 8p~~9 36htxޏ9v0\H Zޤcx~~nI`6łЋT-\=ZnI V܂b^Y#0e^K|nBPBo5/[ҹ:]nI ,Ь^-ϋ 1-?vifꌋ h7¼'` Ǭp Xl8ņ-@^?(]aͬx Tt1exaho7h3'ʸ :ms3ϩw2va3%o<˪?o%UNMJešk%iXNR*+k,nƫ~N%S*Y϶S.loR' trtO#^MωEXe"ON`F%wEJEIMZ&k *FةK1Qp;Ogڥ ;BSꎔϪGRRt"`|.*&$g 3>DP,O\Z/ynh表ЦO;I }ea.$zGI4k;OLi&OJJRLN~͘IHR O)EXLYMLxmBe o*>//%Hx .|Uie8ǶJ(pт9Y$Vٛ>nmyb2ЄЕs->i״Gq>*S&cT9c2tlZE?RovffA"h2:LN;Dtw1 e<%w Ҏĺ'㸰󔽌I;{s==9GCPQ/Sw^'k#C@:~Ire7+M -[/Ir]И[3Q$EN{0go1?Q-&19 e5 sYŠq/Nx #A@-!###{XM}хU/84ҝ Bj)1%/OپF+RCL/fIӃftCR/\na`l_K1X$Po[_N K+/#Zfs0\򐌌dI ؟9 4!Ly/cAT2[aFFFƇ`e1+!o>(tu!k4o7Zߚ7ͻy#oq HPAu(x&]ܬU(###HHuD_)s>J56_{,v&k]˙G_Mю꬧!AW҈1$3NpYfi4#O=Ӌ}9ITd1B/j> ^+~̐1DC݆TciFӋ%lzf""Vʹ+AaHÉTB$iCuD1Hj9sz1Rzg"YJ.mżɛ͔35M6m6uɛ)XiG4o'YCɖi޷7yy3k48ȖyӼD6o͛mGL'!k4wTFƙvx:8imտX,4+X&(rKvCz/-4+XtyE@$n^{/>wuv.*+|zzrppIVtRNS@f IDATx]³,rfRVkWjhB̀1&Qyy coBdŘG1w{LYƹrq:|fR2ְ[="jTZ'~d׽1V0SrRyd;D]eZLq7qƳq5ʘuU<ڰԽ\5E-|or" dzJ0 29۰'}Y| 7擃 (,{ 7| }aQxV/{KURD݋~`CI/n_:> &.f%s2^7eR,I8kא 9C94陠{:zwR;WVyaGhIvX2T<b b—QiTćBpRBgsJtū2 @~#ՉXKqT22#ْQdB-~sjK{z3ŋ؆ó_#+YSN%BI`iҴKXH}*}Ћ[# F2W2c^w1܅Q,xX7~=vrӨ zao2V1e/1-^pg ׵qW)zUw_ xm% ?,_σt܏5.d/Dt۰xɬAO KER>Xm&:~q|N+fY-qVFR7͆[)Goc]Gқ1x~k2HNW}e.9,T_nlEVtvq?U T2U%)jl(HO csXV7pŬ)F1O ,5ʖZ-nQa~__>nfr&.6vS i.v|6;8X\-q:v/t~ܫ gմӚC]Bs8~iUg>2>0 Җn+V䂆WHd@͸-ѤI7vDgrK}䃮o0?ԋuMZꩱ@QT`,N~ZbQ^mN1^z{/3o}e;-[Fc~`:MNGzF!֯=&N^\E(=C[}DnqQg11KLrxvԥ_*5ڨx Ҋ]ZQYַK/عIQW5eᾗ2sH`xw0DF}hKaic=R^ƙލ"@Ӽ k tY$H; mc/Bs1XcC ,X~XɿRrвG43zaQ 1uL9N掘g?RܥBܫ`Mٙ@}J Mh]b)z7avҠ940!A,| _I窨%f,+]1g9gR^h*W8LoSX?W0!oY%c!"!ZFx;\=w,wL@syY>?sfQU N/$0 y;߶4ѳqZIQτ6A*P)&|⺭\L*Z^j"ᾳv-LpuCS;^18 9;"c9l5k!c#5?0k2Q=.:/t( o o$+ߔ^V`pKŧ!3?Rr5Q-ɿiP<2|8]\$UC[R\jֲ4~ZN|W J#6}Wp9x@_uo1MOT&﻾BI<sKZ*JD6T@aK~ݵkWffWuAX d X!kqB9\!KC kQiMGR?ޟĽ'2JDG+WZf64 8H ")vK^rRՂ"![ـN%$Q ЊQn];y"ŃU Nf1j/ r2ͅτe+3ec[0]enipfh(.m2zA~p^ c)׋S(Ien-lYT@526BZD,R\qrr1Uh+QjASYPcޒ͓hϓdOLR0 h0Hd66Aـ˿}{gxPԸJ+ 7(hr1eL0'~GYo2뮁SQODxFn.DBLFxp&8PkJB1 mb2?1Qź@[͐ypkŸtFjQkBLfȎu'JeQÕv/M:Z2!Y ;7zr>@U󫢶̔AaU0 s^Q/ 6eeQ1O/zF#Ұ0/ ǃBŨ-ƫ(^G&x}hzn^vU{<#j-AaLH%:8DM>fUL{i$ʵŽ|%VrgPj^nɔp}/g. )`/xOJo3lgva4%pkdouK귄Q" X(-@{%Kt&ZPμqg o6ח#!v kxHmo8>e pqhh)5``:E7"_P‚OjoŻxp}wkc`«L񌿇o !^*vym wQ_pCi| 7L#!J'hqdsD$0` FajA:hx,|X/?k~$G!P x0l(XǐcPse2 Q5x3:iR9|/J5r&o/)mW"ż 0G|[w!YA}^B>6MI<}FCPhB5ZfUwn%A\;a3tNU+PhMH=ΆDޡ]M`Qޕ`J$b nyRpTaq!_i)ce|Sac_i>Q& ۓ*CCcYb\FvWB0>Uzz}6EHWvQ+mc{S>.27ܫ7݌T=3lE{h*PEa-vyz r 6%ŝ¥`.!"`Q!:7hg3\D~Mىɾyw5q絙b7vs$lJ; 5J'koYyWEǝѴ k.QƴM F={Rgvy+/;pgi@Rsr*g\@v-fl#G|L7N2ʼNo׮q7j6k3n {QVL+.>J{VcmJڛg^Gq^w)Pa*t\bnnrI⏛66AuI͖dXh>CU5r!%+zh h-hA Ke.ňԃ4f' @ 620'"d.q= Q.|LW&rV^ĹUUqrnFjI뵠YL\WNk+ nIrs,p'c m /]EAh}w w a!B 5>Fĕz7H(Ьn\/ bo.RLId=1dCgp 2;AD%TQmbyG8JzXhK n隫UWRl;wR(.VA˻~h;jl^oKuaQ m\7GV𻕞&nFT6S g1;I&xU%o4,Ro8i2`V3‚[0Z n߮jP. #L:\쌸ϲre@wI20 cV:v;=)[*Wۊ+ӲeC8揼> gvaP)Rg^wgY\(JXko0jAd 5{/d~fd\)n%r(j*)mI \Ú+ p]ʸ“¯ Dh{B*<)@7݀dSb4_s~r 6F#O$ǐ s7='̕NVG1W^MVGn~ejW=40M8߽GsAɴ2|+HTp@cxu_vs֠%Ʊh 9| Kœ DǐZs2/6 eZzB]+ޣw;D8x ['gI"hMm`Xs&C'ߝyQV`<~Kwt n!|5(F0BuR#ƿ ] P'uE@2B`3TpZzʎ9`h>Iπ۹eP:J)rKylT+Z.P*+W+fTX# NE|ܢ1V^?ɧtSun!N'6ƨ2g߅zc]tb !&6wZZ3 J.fO ~wOmE4~w1C@C9 fw/RtMDWL r*з`6ޣw#=h.̨u,Îp%\wW]" HO2?ժ[~ft*8RT_㨾0W0$ݰ`e`ofᘷ´|ğ5 z>SU%n7 L*u:^RFۣ( %|ug݇:5"-:O}]g^p/KlN>p%&p*ށ{h:nV8Wt{ Lp3d֟_]+v(Ի\p7߄,,7H6[nFÕ}j)7,nˠ6< t|l$dalg,{QԜ)[5Ÿݖ5rZ]CPz<睲@Ťؿ`c/A%߻5~][?LJb!MRy/v&!64"à<w\e|q.Xkp %u3 D IoZC.:[)4;NjwOUgx;i3_#?s8iZ=]L) {hap.X}U+݌c1XLG.}8"Cߍ9jȤyؼfdd,ZϷDBVOk׶xub>$ NMRv6 1LJO}))' DžuޥLh8(GE)y (:e byC8Y=?С@QRNi6AJ<- 6d NL/K! uKI9i0 B^M)'ehYjCI@c»/C̏s_z5QZ9q"k»bqu7##m; 3vG[{ (˳Mb5l)1l"g"e3 .ykz!c(yeΓS&.DB{r]wT%LhM HJe@5qGOfGcwD*+ROK?Y.KO@&d́[ sc/eO fل䞜Ys(rfMF/8,(٦yd`j&88[w#o s)IpRFRGIpȨ%Ζ7M5d,BnϮMht*:=s@5lPiyy:)ZlIwSp ၡ8Q!f7sѮ3D‡(6wTD;R8[|5]:2E']N ;?v] <- //~7IV2Q̯9,7c7}?֩ϛz޻3x,D` 罻 gd^8홀D: g U-팠'>ƟޗS[׮Ōk Ri29tD͙5k?Ӳex_D] pS_4Ux]t?u*vMϦNyy)7 I/o5nX/foN.X.O8) ]O)'TKwa_`{Ndb,ӱ73,Xt❚uR*u.k?EgvcOOΤt{zIuɍ3tβSeػ^ 3.Vgڍ=? I537No?f,Vk2d>& кrtfP'gy-eO=) J?qRߍiXݵ.GL:z~9]8 W? q vcPlߝaKLѽo;[t9c]`ɖ[M%YhR;J\ *qkF;]`S { WwgGͳ% [Ȗ W~_IN*tOb\I\j[Зw'KlJxa8~+K|t#4HYCt:g@p UUCJ{Dn6_*yE^OO`x=YvARgIc* ,'qzO51!zπ?Gq{q-4[@VEݷ@y{y'o7 bZh x~^m!'Npߠuπ?Flٺ% 7Xϧ F{K;d~zH"G0?Î^2CĿ;DDɡ] ?5c/4凗$9菌@=4/nBv}zF^oF~SD~Wu"GzX'xoHпpKFF\ry'MϞWG^oyx? 3lf-3rK0Qm*_B2CHm*]:8 %e5s0w +|rEg /Īnѫl}Y#N= h+`߮tW3|OϿ04L2 mǓe5nЦ57VBN`Λlr+7ʃ 8J!4ѡ ib<,%c`\;qyy>CS ml8N=(@A{ Z1EvSdř ?5ZwƇ#6l5fÚG),G6ba0D "?Rq$3$i1 L;&zgxZkfڱ.i!bG!=؆iW~В+!;7zl}rMUFx-^VZ  p~lq~īH|}|Ǘػ0FJWuJ`e%YNEj_G5C$UI(^j wjjIpNe ԌuuҔcaVUcm_QPJYDDE.ro.F%q7_lӧ:…0FO3;}}@RP۰I!T4+ðӒ08v$nvޚFG , uTJH ˖$w%9˽]F]mpd)]kstS@ uam=PHPAngKz:Ͳ,i .e)[$X$TH]09J׭CKR( ' BP|Pp Vz N'tk[1HG|paˬcN {*, (S(`5`^9&*"EDPD 38/VPF!B+.^-_ T^ESX='&XosCWTC!n%4[A>72gjwDHi[Y${YhAfH]٦B?k3,Iv^ĒI1,gb(c/ Jv=h7kKPJݠ>TF@RS P .rCP }z23zPh 5MyE-JQG7nh[R:-@K.S+a ƌ2v;+ +ʙf~f=(;EQمu%˳TxRd ~" =UwzmU( ?^BeułRȼp5i\|Ab5%vY; ( ;!UH[9K^}EY*g\%~.~{̬jX5mRC]-][3t~뻽rY|2+8wW k&Jn9-|$lA.*ݬm 1ԴI1褻i9| &ze'A:"5>tI͇B{EVSir6NVs]L棃 LQR^E(ot(RI( z"΋+g C@ sPV6!9n*JH ebDU DBkKQّe 4+x9҃z@p -Y~fNxDzl=-Y=ˣ P  ʏUM-YT޴Te.alpq^S)]Bsm65E7n 5giUGhM骵l-uiSoT%j7eS÷!}jO[+H0Ύ]`\qGB_T?^)4ˡ\\E~x#aXL..hwKo? o=w?w/FIWw^uU(P<*~*Yj{4Û9xcsKA57R'o栞t:j zRO(/K47>d=}P.U0O[%aF Rξ;Ai TȞ@ ^Rjq9~(WPo'k^q "u``Cbp-tSש.S*K>:;zB','$ӛB.q_j_YQUE8?)#W!(\im D!(5 TL.‰[_Mh8,i`ʍ PjCŇP{3s'^f<$T*RT*+JaRTJF>`mG8RU!I)okތeRj#@ vTre"%K$ \ڱjK`&73I6GB@)"Zg(dZɇGCj'-Jm%y*^|\e*J6S H:@qpU}ZK;DӰ>mH]e. ;G YAQE_Pc>USd`Jx!kV \;LHHLaqj+D'6,&] 9n%6N 9AbړSfsЌr؃>ؽhJbf,RAߵ;Rl{7ACfdwRfbUc*;y۲Xz%W2Ԏf9 xdHrlr)< HrINYy[X۪O~0Jvygs6,}t@1&'Yζ5KO`†XTuо L^gSg*^K/\jjEOҠn!s^Se`}RR7 Ijǡ*VPUKJt]eyV!Le5>ELJBb]vW 'і"RKQ/`1u{22ߘ֨N_S C<OA͏fXu3WͽzsZ=+RPuW%{;o[óv`[-fۚ| B@x(z.{4:LۚW.3@Ŭbt(do zYzoƔzIy[4JxԥUں/m4Yy [k9~"5sl}sދǟxgoZtm߃L㉉9z{9ҫ\4|&g"rGO>u}/g[ї~B9][}y]}kV؂6zJrsik5!vB{~"T꒳ֵW<) Fc$ oC8Tju}SK^ csJے޺RUWLdO }k~bfԫMVf<1fE+x¥k؛՗LYrAӞiXqlk2{d:]ZΨ 543|_vAƭ4+v.:)z"LiՊ`j_5 qXUvQQDXΘ]CG[22">*R_Pe!sAz̐!d@,~8g7zO ΍3;7()Ć6n;_!y"o ZeT ^B!W1XGYG]`]gסxX>(՛MZ1 ΢n 2^NqqfلWHr!c;̇c(KAY*˿:Oqvp$tv0^l9;8ҿuyTqZӵ Q6CMam32;{mfޥEkqx\zZwYD̈I)ݸ)&M1xRDL ?p+ lKI${ˬ5,}MKz/sxoVGڷoӵ(K -05BIӝIqkuj$&װӌ_z;XmŔJm_- 5_׷x?+tn€]b3- j+fCM[%O&:#)8egA~P/r|ݏ1搮6jLYkf@+!Ր9j !l'iDDΪOC:T3MupVxqtge X{mfZLjM,;qYX]nhq>Ä̈Q1i)&"$-0R$2"3(&Mɴ(ђe>xw`$q0Yxi{jCrxr>&WWT/ä.[-Lr!Gfb$GeND$)B$IkK=Ie!a9=g_X0xzĈ8@, sw<.OWJHTIz4I`nOQr& NG窂:||IDATԅ(saBcPx $L iSW)h´4RnRk^ښ28^ZF]ĐPa,VX1dz Ӑ c 9Yn-,Ǟ[9L{Z .E]!OIOڔ"T FiQ7E!ϭǘlv~G!@$"McI%"IӘL 3aNJkݼCπ2x&LN # drheXevN%O va pHD60qmӄqT܍S о REme5njwqZ*ٓFirl)z`qTɞǭ!3KuCNޮjOTP/'WDSTw0S)? _Zr'pxNc=Ch9"k|F`UtVu>)7/S4/Ҡ:N?Ogewiz\XG?M-.h8)pH"W)#p3>FxH!l$ٰ^@u40`; b [޹XCKK1<%{I(q Z+֥@j1N {f#tDv럞6[ ޱixv@kyh]XXX58%䎻\A2GWS!UG=۳Ok?鷝`ka4Y w*n3JWqsjJ{X\ޘǶX&څ"ySLpm 3[N~éhLgonGK2\@E{հo|g8VC=Ê[w;!Y``2ʢ*սdu_NYH3w˛ Fڑi1%5lz%n8 ΰ| +Y5Jvy%;}S 2w z6faxCH&΂ _v똲qQL! WUD].;™h3pX &84TT}tbq }w4QI<1ul x+f7;Hj8VGM/,LMxhQwJXzpu ?rD<@-ͤxét5nJV5``ĹOc^+hWXI{{i'oB6J=fFirQ; xkVud?Gc )X<(ћ9GUG'Z>)i(/6'KNcwA8>}R6 !]w vG>?m~)v-G=EiϘC]}i@[ɻV؝uV}Yy_^DW{/%3Yul}^"[bcaQz`Z(HKd_`w8BFܝ>ȅdVS| {"XߒO}{!|JlQ_Soɧ~!{Jo;XdSvgLbaӃ@Ʃ#/^>7ŏJ |' |*~OjQ~˧?vo8y_TcaW] ?}~,>^(~𴾂*#{NvLl'}4hE(Lݘn>:tQT͖~TK=|SPz<tEyt$<`;,f褿x(~!(yoWzH-LYS}z:,K몾~{u-uك`ykrK7{u dOjQ5wK00u7 Q]q.hIAS5{7Àd1&8كÕ+\0:V_ ]~_{eR܆ lXi{}b&+p}Q)U%ECP?:'x{05tdC4nVh &uuչρ#+$İ厊TC +ϧ΄ dž7?ae }zUrHՊfbL8hùGSWnm.Uv^KƄC[dZ/Y[0Rz Qpy[ :K&Ʌ6NO['8at~aPA0)EڸUX>? o6^x{Z'Y6;jDuJ>z,5Kpkq~G: }diLN&Zc#˭7.= ՛GX#''Tf{߰:~|B])7ݐ}HCG>z|'Ŋ7=妦ԪGTo:N TM4~:::9MN=v7g,? ]r'ɞ%?y' N@="y7ǩ؋x Xqx?)O$8Vp'ɊoyP.88?8)]cݳ9Ez;ʕV]/{AJ_J9]⠧tO]=h٩8O":+Z$ վD? kS)]ãvZ[݀٢dtH%,4K @YL<)]OU!l$ %PcB t~dQ)vl =(F0YT1y@6,Y?=(? H d!ULޭ뤓BAO"_݀`' 8jpS]&#u |H=pSvg&NԈw+Ctjl*M"oitLe!x㠧"cYe3SQ QO]$o]űŭc|O=8)uYF/nHB~*,MAOM,Ys~\G45NNˎaf[ $oq y;K>]nGcJpJI{>D>cq0t )X<+wJ=?w<7oKOYXә*iK9[L_(  V緃Am(+n|'޻e2.!ʼnL, Dka ύl6gͩTJn)D@aFf0V%$j"b|uS!E\Z%9EZKjl+qo| }M-KǵZb6Ba[юߐNA8, q`6ớI"ptM2$Ȑ($lH3$o5D$5,-3F !ǓȜ 2(9j ˿[j\-JCaoϯ۰}^`v2\nlbC@tDԍeJOREm=Br "Յ"JӮ2;Tlfg9u _O]+~Z.SSpul/_S?@WGkOm>S6#CC$m>4)ZH$&[VfZ}虳Bn32$ln󹐩 qӃ>@F#P+ pGşj(#R(Nu>hU،1!b%ĔνGƹwr=/GƋd|l{WՇɟy{'ד?]yO}ޞ_xr㢧6uڙz =@u4uQ枋Q=t|Zqz/ws$lIc6)K@d!A؜o8n޿ж-v&7PzcWd`i⎋ՖBIl[!{r cx:I4; (K5!)3s0 aS!G&j>$(qVY_yҴl{kgCNM$Ulj(T/FӶn[1o$6ʪG{.ߘ`S|NA-=In32K%QZv×`'hL'd9 7dcژUF-v8Y;_UR&SuXgW^!'z&N{Yn!5ƇxM"^)F5}iow"[#a,oU/78p%m)KgCqή敡8ye!ʈ5!j59I7!FT3DxHa"1g^$y%IM,-€O {O0/a]Nĵc\ wH &Մq7ǵP#Dj7|4lƀK{7Qd6+Ǝ]ZàaIZmEKdf&F<ʵpd|+^L!F\Qe 2dbLx&!N磧Q#?eN鴱.iW*XRwE-,o3 17.1.7 Locking


17.1.7 Locking

It is commonplace to acquire locks while holding other locks, which works quite well, at least as long as the usual well-known software-engineering techniques are employed to avoid deadlock. It is not unusual to acquire locks from within RCU read-side critical sections, which eases deadlock concerns because RCU read-side primitives cannot participated in lock-based deadlock cycles. But happens when you attempt to acquire a lock from within a transaction?

In theory, the answer is trivial: simply manipulate the data structure representing the lock as part of the transaction, and everything works out perfectly. In practice, a number of non-obvious complications [VGS08] can arise, depending on implementation details of the TM system. These complications can be resolved, but at the cost of a 45% increase in overhead for locks acquired outside of transactions and a 300% increase in overhead for locks acquired within transactions. Although these overheads might be acceptable for transactional programs containing small amounts of locking, they are often completely unacceptable for production-quality lock-based programs wishing to use the occasional transaction.

  1. Use only locking-friendly TM implementations. Unfortunately, the locking-unfriendly implementations have some attractive properties, including low overhead for successful transactions and the ability to accommodate extremely large transactions.
  2. Use TM only ``in the small'' when introducing TM to lock-based programs, thereby accommodating the limitations of locking-friendly TM implementations.
  3. Set aside locking-based legacy systems entirely, re-implementing everything in terms of transactions. This approach has no shortage of advocates, but this requires that all the issues described in this series be resolved. During the time it takes to resolve these issues, competing synchronization mechanisms will of course also have the opportunity to improve.
  4. Use TM strictly as an optimization in lock-based systems, as was done by the TxLinux [RHP+07] group. This approach seems sound, but leaves the locking design constraints (such as the need to avoid deadlock) firmly in place.
  5. Strive to reduce the overhead imposed on locking primitives.

The fact that there could possibly a problem interfacing TM and locking came as a surprise to many, which underscores the need to try out new mechanisms and primitives in real-world production software. Fortunately, the advent of open source means that a huge quantity of such software is now freely available to everyone, including researchers.

Paul E. McKenney 2011-12-16
perfbook_html/img284.png0000644000175000017500000001621311672746034015320 0ustar paulmckpaulmckPNG  IHDR+!/BPLTEb``MJKZWWPMM# hffommmkkXUV856KHHC@@wuv.*+vtt]tRNS@fIDATx] D\E]1 (ݓ39)  kn2[2lZZ!wGgM;9 ; il{3:;VƬl닶bk[6)cl?z6;f=` ⼼~"83 (RƎx^by.2<+Gr3^׽0Om]iaU Vc K,IhD:LgQ{;-AXt[ Ƅdm;Z9=M=egtcZ7*W;Y#|g⟚NRl [J"=B% ص tmaXm:X vp#c< b2ŷ+e"CJlVzDGV-<1}-⾊l{iJ"\aȉhfŒ 6$N;aRqӬBl: gVc9} ůHo>B5r`TAxېFyE߂<k/,g"sNQw*Ҋܵcc%)Wm}lO&xs7M}=#yنbXmq *(RPK7i>4 2ӏfRsL_mbZR0x3vƫ<hٟ$UN9Z-ZD-srt"VKoH^9L P^vᭃ b-xtL.UqVj!:+ ʢ"82yxiᦫaɌpDA&8w Y7/xe N)ӈiL)}+emm&lH-z:oLW7}Xv,+>)5Zؘ#zƞ_8ZxgB÷Uaw'i@,zj>lk; 릝-TEѓ ? l:6'h~nbe X7КY~[RsrAǴ ̸6kiwběٸ]f{-]v>&;EHƒ8 u;% 5V#awbV)l|}EK qK<3-&I?_F,5l#_;`MF67]9Y}{S|z#ozE҄ ق[KHX`<*T;5t[BW4 k9p0F2sf&N9-y3 *t{% Cw@.+j΃[N6V R̻teՆ/m&1b)%=QHݑ#R[n0nSr@1#EH2 xSJOAG%``"3솵{ n6%b?fEWڥJE$LX諻ϙn!ǘdo$^ɦDe+ IASc 틳d3x YepK3b,-yF1.q%hKD+a[,!GjY+େ;tcV:={Ep#`kpyo摥J$W- CN&tp?nߙu'O{!&i;d'o䖶kYFݰ&8'O!vĈ%ʝǫg WcRnTTz( 3)&+9AkदzSFig}/ u]#-nN}ktr aw'S-$jH.'Og8,ohi:6 L萬kH?hlp2-euQ;PsѴQ[h@ mts߶{O)΢*Ί[,g1E:=)̨I1e)Ђ2?|Q14[1i[+g p#_(c(5@8+~ 9o`rAWX`]ctJVp* #]AM9/efM9 5ɉgVBEqwMB܈dw#)E~E02 (0HHgp٨{pCQ\FjVt%bނ˖p~oe.k.Z6 x󙮺[k/SVl )/K-tȿh}b=Si[Jl.-/R!qj9}ǁhђX8hQ`RS; ]REMH#7.u-I H}<ȋ4|14ퟤHQef_$oC!|/yLڠWd-;QbԜ2wڸ|@9`9$Ѫ (kԴY:PB } @;XtA=Z:;Iq bf|B,7m .#gƵ6`CyfCʕs,.SQ84EE gbsG;?>PAG{ĮSa5xT$g,oz%OS*/ lټw%v]77_t<$f.xEU븹KkﳷLYvmvC˴9w*c/+ -Y9+*koU+Yx8]u6,q>]K8 _qdClJtdGx6&/=ϊKSw$x<&yLH3MBzɶp6/*Z$;UU i6yv 2Fxդj<ˀM! zHIgB e`Q>\F anf7#Q5K :Hgۈ>Kt4l\.M>$E$|_L˲'&m|z5PVὗ%ZEʤ\S& 7I_z^PkG똻HqÁM9¤e: S4dͺ0mKdsS~&U]k$`L&G {4ț-.eO2Wc T2Ak3Wu96c+q #1wrXPoǴ]vcZ`7:l\sA u=Kx͍2km=6]XUvcKX[3ewg]/k8JF>~:8{LP_Tg__6%jRiO@dJѥ`0ȪsY!)8>?X^ltΝL!J(m g~$a#u2P_8:7V1| rԌle") EًA^=_$ tCQ t Sruܖ*-6lpY|}3i\LNWSp߃hJ(DCZ \7u/$b4I!VptE:%S=+P&Z&w6A.MX QNGC*A[a6~ ^6+ |MэW4W֥6W}*W:}krVa tk {F_0,G g )AH y5^e}ش}kyj{Sg#Y3۝!\5ջ|?ƨT)[D5bP9g;Z^Yb fvsykGim<"cqizls()|fj=Q2MqFHB]J=F:1ӐȩK~ʰ8炯mfV*b.žfCHیZ漚P|:ߙgf<3yĂ1;ܷ9UZ:K_fvs9kfm_m@wmO sxE>㾃J0 "GL'9٥21͜z/Yv2 =}_{mȧ}gp-Z5smqm$aRaaWR#~;>A^s襗fy__!s~.fo_eb קl=׾_`[s}kͷNlSxEe G}dpZmqG9ŀeEg;qy+H >M҇HD8a񾐝)3e6'ss&du`]b]Z(jKsU3P^-95&8r^ac^&3Yތ^ s4GX9s]̢}޸̕2 ,w3^^Eդ&l0DxDpN]gBL9+֙E͗ޗ]ؿF|kj]|!}Lu}kY4nF}^ӡk+?@9'BW!K"+9m0mCPП W++Z@9"G$]X8Vjm}l}"Ҵ|Qb.kү뷚u5mߧswamO6a"tkCkf.{*-wwgoބa~1ucWUd3ةWb4UxikfYm6\~IyuG6V*fm^Ίn{Z6vthP[Y|YW ;Ødc6B^ۃ~G}]8鯾g 6w]Sx ^O&tM׷'ooy5ՃkEl]b7eq^1sX:^l"v]}2#8b }Ve/l3i=6mwME[gqծ(Ns T?!y=NwQEo8Þre&7<VXTƠ({9Zv4!<{2oYɸ삖iHRk#hx^I:?ee•r3<B#0#[$e=.m&~C6v]R0^; yv-?WueRek_ =^4I.>ڦ|b2)^w0ϗ,WS0]پm4n1_L̽v~:/vf/X$~׾ IOO*I*&CѰZEF!IDT5rũD3Zp:h;MOڗhCFUg랟_~tw3dU\-׊9;˸SaAyE+,_5ϣLcJ)Qb}h) vgE!A_l-)yҬޝ ߮E F[IѮq,"v 8L uUY7\]4WT"MߞK_XHӂqm!sH7FcV9**$/`VbN-)yҜ_W9)pyR^|hX}WgK;Cg<~44Er&ey&߮VdkG |jT1Vܺm48WzAZk*x_I~ؚ|VXqWxW,E=6fo[+ed,O<*G&n†m"xj&&G\ў}s=kek_x~]{Qj,):|ziiaޫwrVcL|Xǯhד\cdJG8C{,VWZj!H?~B{}A{y%~Q2]W{Q :*;G 3 C:=N2?Jsx+XvRV8~+>>n_[66|ge "#hwFye^!ֺ^{@'ϬtIENDB`perfbook_html/img203.png0000644000175000017500000000025711672746143015311 0ustar paulmckpaulmckPNG  IHDRPLTEmkkXUV856C@@.*+~ctRNS@f?IDAT8c(`@ 3 @L}dk S v A]moC_&6zZ3IENDB`perfbook_html/img269.png0000644000175000017500000001361411672746136015330 0ustar paulmckpaulmckPNG  IHDR?/ɔTPLTETRRMJKZWWFCCrpq# b``ywwommmkkXUVJGH856C@@wuv.*+~~IvtRNS@fIDATx] ,rfqiCe&&1}7G<̠R"S;!ZKG@W6ښb?`;kU[ x);hzZWjIA2?kߍ\gTJzޣg؊HȹC *Kӥ gmd\zfe$ܔ(þ3h0XϠUuhzmIh4uq<Ej \[8-)N.4pك봹o.R꡿a ڕ+r F;E _)r;c?4J,9uoY~LS'eai:qp&q+J:yX9c&jsWW3<]b.# UM3苕r13z}OX5\I LjVAkhzj&0fտ8hp 2(;se|r;ۑLD_ɸ;@;qjC\f3eFa0]yUv2!Cz\K]0r0 'ݸEMX b4|پ⁍ @x4gwwӐ4Ɛ *jAAxD'ߥf{g8 ]LT<>#EYqE5ϰ{\D}N*$ ߊiCZmJ5pA% 9B͒^b0|Pnc{Y8%vV*^t+oxCf\rM`B/tގ όM5@ ' MTp<" 4-[7|?ldLUѪiONjxIg}qm]05@`Η_U<-5=xcpֿ,.t_UWՏK=~]]7`40_$<%l2Fe_[s:*mF@wA.eshK{'m[< .޹oĻ|v0D|ݱ# Kkt. [w|F5"F&*^-ZdVq}N?ztH4Ihv<#X$x+x t s/MMqdsVEy#V'Β 'LzB~Z Q\h.JSX9CUX )hRF-}Rq]+B'K>g,%_/ԃ*Yv1Vѧ1wx;X_H`ujyH,#KL9ڋO4q|+#8uutTSlO@B,e566ۚ[5˜j5}ŽK6*|)@@IWsE߁vO/W 'k}|fBdn读cO!'Y{lF2'wg7vZ<œ^Q9yjþ*rJ9zmUBٮ1Т($L\gKj75}`gP9ԪX͗xـ0]v屺rp֠?3+FRӐPZ6^^:u*R>iȊSa`d33[WlŃo<ִ/7X^ UJ{fl$Mx,K8c4Z( в>y- oe2@+HZ޾°W'ee q8T xOW'pܓ[rv2h_CAZ~q\Fg^?vou{7ZN,ГPaRkm_RO/ո70f#Zo(qQGA=?,_2E&zzS3 P}\dE4j5A YbfZg e;v[<0hf!(h҃} -z9LWh +m#dpNc bj9T=Zxbߊ}OAͪf,_Itqw2V< lP,y",Ͱ3!V(5"e/Q5c/dJmK7\:ǡh7!ؘTcPsV6ÌE\̒cWcIo?Z.Z?@g#gblgeq\!?RcIcU]j9+FJß'~?Ľ fRtemr[>d˨VHؚ|dy(\匮fHbd,IysohMt1?C05Z_AJ.e}:}HHX.1 Χ3@$FjeWWL#o, z47‡R|/SSAJ.eBa|/TVsX~O*_Dn,vٖ^9=}'j}jݻЁ hC:bЎh*Ŭ];n#+חwׇftO ~ mo H }o1H7&i`@+vOjtAu˧StUK&5y-8}:, JBUk҉ۨ19l󁨝_]Ue~+jvwN9p8yhnZu}n3!1H X8Ndb!||;O_Cvm5H>^e[k @ӶJ%{aU%K!"^N$)!ٞ_xsV8[Ewz{hvU$YO嵚0?MtS,--d{o'9|*ՔlO7Տp[AmL^ɣ֔PSt?Lĉ~k.g='N8v2MG\f[ҳ]ȸ(rE䔜M3eʯI0%G|Ev#X t5,4 E_2\㭼 '%qG.NX6e\[on&mi#vK~d(9EHq6fcV[RV)|z=<]v8'N*ǁRaqDHk(9c owAǎo?;ɘx+WŹHr~scʺ/yd3XZ}T-H\G5T50,Ys)y;T.F`O_lco ǺXdӏhqk܋KWHC&?+k\AHEɻ6\eIOkWKwwSXb'3 tڌ{]oVX'/.{`[|zVːU/_&^0`߿3~/PȿL' 0 ^x=޳ߧbs  N la'0_µ[+D [lfrXfh.k[6Jap>qohڃ G5Ka^0(be e(Tbr++bl[} ѰR@O|@FPz v^,e eЋ;_ ǐW^YSi6x xaMF\SǑ|I*jZ*yS!hԷAeWo9e:[srAyM ygOuk>wuv.*+vttrppptRNS@f IDATx} -jK\k52((ILbg|Ya2c( ɏ]TTТ(+Q^ղO@VM4) pݦ.ڲτ=]t{u7X]'`+[(-(e!5Hc*יe:D;Iu0PT[WB/n);/Ý]Յ֮Û_[ԮU;WJVM<4Ƴ++eNd387ͷ6zY@G|){`/K {Sj+d=r.[Uvi:j(7\ղa9//uZZk[~u˶•@J!UVDŽ7HE X>BZ|͉op‡JlhU4%gչp†pK13{R5wnh3y|q,s=#7Oιv%/39^Tn#лg26q׼wAI҉֪B1WwG3]YPѬ~WODn}.Cl([Vrf%({uN3-wcɱ-dYBxfYUb|n%4'[ti_=\g=COY%@10lgj+Vvw|o5 .^ ^lk @MMB=*&/ mUԡv}%@q2ЪDF;LP樼2EϖwϓqR_ljhHu/гZ Ӡj{7׫|7 nVuw Q]疅H}Mo%tqW 2v! )a؎k}TP+ܵiC]/E j] v}yӍNFfx¡e mIuEs_հnF ϡ M4Oea6'aYT/o[u!o|'C2$Q3 Cҵ؈z%Fg7~ʙ#Y_kX:=ERE;O;`hYHo;ܩ=`iz |w@}-)eeATI NR R'O n6Uhk] nmPG9Çe Ng٫gwY l$ `8QWiBxKTNVdG`bAR(HVL\Ey2 3J `5ݽpbʲZ*/) ;L<؏($xt7㞂4ܗnlM0smwAq$ƙݠ߻vh{Qį<`G!5\VHbtƭh*ExD9-h+Ƴ vR{hÅk%fcԚJw$q`FWSiΕ]σ_|ns}i@OfQm?{wR(IT V8D{Po[{q8ܽ$vyHE6cVXsaBl%L50G~&'2tr {Lz;ɵe [ߴx!Әk=.FDsCҩKQ;}OD8X[CtG5)ug% de%W eP܍uߖ$K/^s6k}x{]"PBΫRq&"$,]orZ!LI=4فˬ(ùsiS3, ,rNӈ3R zdDT[YaB|\뉅ȇ2-|xu힟e17E8&cWý]K$:vО _6-HΊ{5X.1N;Wwlw,8>!qqgDSu ,0nm\~ XgtJU _ŏ /Ʒ#xf:~~q$܎gd׫|u+մg6NlBFH[)f5 jGxʗ{Feh4=~:G؜[ (?q%rʹgğ NRPsM j>HQ \Fĭ%tA@iN"Ws5UYMzsUI\q|lkG 䲓VB 7xtC*-qneP!f/j|:7{]9? ٽ*xlQ3[n8.\MsF5ݱ>8/۰(,<*sg M{ث(w Ԑ]H;C3B5pYvSKN]ޓWFC<߈3v~,Dw8]O{T{k( qa,/ jYo ʹ:Ue^,_ YD_Ch@5tmWV^HQcsu"0kTN;t%J` m Ѱ B)i. TyƄ-}D314 $DSF5suDWn`$j%7ordQspV-M}d__ li\J Xjm3Nk Fg6_ C1)kn("{|ƞ0 96CՎTQ #}ݖ2R{FA~ٟ%.mEJ<{b>*PܴOm FE/Z9\b¸!)jPJ|lieWkrfh\t;N'7Ikm5"U$"Lٴ `zݺU}|s?)XCr&I=}ɂM9z,aqpd:&v2+'YX} â_D 0P)B-̀iLg%T}zͲdnO#trb+&|bM0Gun$OhO&xI8ޅpQk21}.B&,:`" g)YAq?ɀ9g؄c(>ջjXI&Կ4R{MIyho, j}X5HɃ*E|F;ӢjQ`-XGXWs$Fz'#7 [ٹbttGXmT<02lddToh#-W CqԸROK'bz'h9y,#+ǀq$’?&w3}+l"}*Ly0/6A<[}L%ȒQ:I6%v<ʖAMb ^UjvF>fG8s[ n mб PA:UcA?HIZt3q /sD8KQoQ@Z+JXԾD?pRг@> c'ƷQ3ЉT> Oa&'s1:r%WUjKwE&Б(,;0 d*Cک:0&1H)2 Mq\R n ,wŷU}2q@5&KkWi 2σz.FRx5(:ywp|Wcb܅+&ב lE݊= 5 ]h-I$˴Xa/:Hx \sRv'4>6E r-א+m._ L2nj>qV|vy'y' Yk-XՃZW\d$)D 8L[ %έ7={SYP/h!!.v;-[Fsէ{)Y"9ϋf}ÆZ7lCSm!JFM}%鵝 //3J< w)x:RʙIcoO7}Qs݈ה̪t/sxށN#1(|(!J@(nHPk9~Wҟ=BW(/Wx;;`bFq h'ڑBq|Xy@XaHw;et4*Z&ekmASݨj7`a[S,E|a:>/5/& Qׇ1`[K|DG7jd Pt`Ի ~'ei$E,0 l_֣ԋLrC௥ w9ֺxꑝ g ͌ѵ>kpaIuV(!Ζ]r=Y{ zVY;ZL4fN}H9੩ARTh:Yb4(_BBS z' Qʺ#Bkr'qξD V2K |)d:15>Ԙ17pR{VNzRz}1Gq1 xQK_{mL X%_kXX0R褈,#Pb@¹@&/5:μgFP\"/VoG. IKU6#*|*X5|)46\bBp 0I`uӠ;eQ+j+{H;e !bp{ A­K݋HZh s> @!VrGYp[!3)Zw ]WG)8cO&p[fH<~{N>z2Hd,yAg֭[B@T,qgVڠ}{9Oe8LT] M {ks!$hlE %F:*A0 .D:tG`WpdHԠc[aRE:O u =i} $bgYNAC*l/.' g f˾E\7(DzDz񃛌bN hRZ?H^^hy"PɵEvG߈0.ȯ$`Y kk3j#7͍ l`/,aOm5&97q[>:ujzSoDE~ /5zbVnw7ޝs/x񏻢rGʃ1TtMѺ DZcߒ1,%0cԎ@Ս:l+@6h$+ qbIE2W7˲c)tDqJ;J;IL:39TmT@v-gÌed̐K|7tD&Bqs3ŭ"1E3 t#V_#vHfsg3$:3@\w>x[ՂK)qThkr3k7.k'vBGoX8%M7SAR M$H=ȴ)Y#I JX.꒪X$nxAo;o)q׬ֻ5,y[smlG;o~H$c,lkl r|0?U$M:ǐ60T ЭˈA~xK&}tq[V쏈UMC 0d…ϐok&ؠ#g~]>q^;_UvE +ЃBtn$b5)"'aAcȂ!JZi5o`,l`F@O'- Xך4@7a:@[멭:euhJøP#[OH9EaփB26U!Jv7`4 dUf}ձfCźfs`qwgPȮ=Yw myԸeIu65;7o`ы=Gpq`|:"a~jGu\~jI,:ea&krqe1Wš/qQdg<> NeX%CJG JS;¯(v)Y%q9MлOM$Pu05D9(c DBw^Ng뢌4I؎I3YP*Y5%^Y E_$uLJٕU4^+T!?t=_?MVjP͡9IMfb"zRmh22LLDw@`WR^Ы}]$xa_ Ø@أGMA슬D-޽&RUvd)"g8TBVP ґ6>ZE^{2@?^},^NŔ[q$cXHgDPL$0ռ/7] j+0,v]gCx`\WC4.uIH!∽Hj~кG}Tj!, /q^$|^dُKdق,%v`J_D0O}؏Y(8F9og;p& w0dKKAMπn#+ݠFd  e?yw>ߖVIDAT^'Dg$L8ݙ:Wy \x |ɂ\NYUr=Lȩ!SznAy})urwHku{}J)!,DO!>z!^_bhʢHjA6.R3[y9pZOED^w 9U rQ.`S"OOH^Uo$R$;LɈв@|[?io&/fP1׼'bTL_$)/D𲫉q5r}İQ(N(k3*KC FP$,%D uЬ3w?ɩF@<(H,; Iѿ Qn^פ|T:JWbv- ,AM "d\$x4ׁѤ} kz v#|Z2}~lJ+?+[ilRIR&OI+?5dz.n'70;hwwM+OÁ 4V{T߭ \!fLj!ړ芥k\y&s װ..ť‚A e;WBʵwťw7IExuETqvpR/d΀WW! _~c597|"7 DpKĥxjab3_ HG&^<0ŰE⮋Y,Q TN(v[s1OHD/C6/LZ08ǣAFI? x׵lo Ӿ@i[r65S^ 9Uc_X!Imk+HamݬNֆh(&@ x ^LMt:i_}!ﲆ@qޛД ²QKߡd^_P}` ƀ%9k7L-qY&stF6wC}&ػzDs!`Cb39Tdq#_)uC긭ӭm.7 \>$O}1|`\^^{cKyh1jV4`> #ۺG!{E> | ٬[@'9M0.+ooIXE/u%luue|-0ݧ^`zj>t_i!S)2~jm(KFp)KP>7n7.*Aiݧk52)Ų dņZFpJ(:B_ *Q aO(10M6 bEte|$s^`K.4,?)^!&m?c%D]$8UVFh۰k"qcݣFitCktbMr/Б;e/Q+]ÊI]U(5ʸ:iEm^Bw_UOYLHbz2if\ͼ | ȳ0^at~5zNҷdnÜo+ǀ"-]ūI9 $.9mWUS&~ͶuU7OɹNݪ}rs<7/{s ,n!C;Z~j ]QQͬMT1WIY;^DLWk+`X *Pd0Բx524(ux~&_dի7o0BťT kzT5|B2}BWЃF Es: ш^W“Jk8um⊩Jھjx>NU&ǷЌ~ zs4 tW.m[:ܺѷv;,{B\OurkگdpW%vk+u̺-5c\Ƃ*w|v0xW?X>]j](Ru,hpLŭ8`XmBSo/b1ud9=|c2̠uE:ŠÒ,ydC bݻ;ӋOEK[GA߇4f"asزyA.W[;6)cn;r"dzfE֍*nM) w–- 2B ]g. ȓLBb!YbG?T{; %a5m1ʔI X'gi\:zUtL1_֗Z_rw/ sq }V\[тZ/\pPZk$k$ 0dXq*LZf ~.}s͉i*)H܏&NTi"Oo6@PHM,pd"]|XS٦huc Xj+߄̪3/.}"oeے;kvJr["d[C`_;+Wveny .s˅ _ '3eBÛ My90D[u' E) YʊA~4%DI7zTh#zTk5Z=l"Ҕw,GTx2c>Ԕx (:"BE ^rXOB C(/&Mɿ( qsH&M@EG VNnBkvCPno+0h/7 s)ixol(~X[ұ%NDd'ElAdGƢu_Э5m"ǖ`ڠ97bhQch'@b6Ɩ̑B(|Pʼnz?aǵ?Wt ~GEH"Dq$ʢ$%cJ!@ӏ-OB`Qa7e[ Ҍt/2)g*YBztSneLT$q+tMTY©M$4An}†ޭ81jtMfInEb E'Q,UX70 =&jZ0=:B}1uj ){ڇ>1C?_ lHý~W@]EGɩQd0ZkPVZLA F+)D/+XiҺ߽}Q/%|jlTN}U-1O֣d(+dp @)ebېM+h귃{PCpW?I@ΑУd(Y2V[U7ׅVUS6Va\{ԭoZb92z%Oݪorfp_//BWպm\j(2WF`CU@SA_/w49_|~еSXX^ ͥK%/sFSXؐօw[sLns2Xw!-l JL)+ ]NaaCZ*9K(/%5es0ҙW9rkD,ZB$GKɞLBlڍR[w\2kxY5\GBZ8oa+CCK,YB\D33D腝dG +VC-1 V [udlY$N8ަFod3 0iw&(zfl³ScqHI枈 ޱg^ 9&Pɒ=njzŒ`$GA6)aN~yv\ mhJ!aIfVaeʸNΝk#mϩ%DZbI0& 6(Y"k9A{&#qN%˅ hUZ " ;文T>^KeO>tNKU?b@ ;Fa'ե_~I5z?.'Փ`s>3@ITE tDJ kَ;"qwan<]jjߎl$hTqUh㜃BT$[?юl$hюQ cN^܎Ѣe?K;.ԷK/ >1E׶M@?L/!lQ ~L*'Ӌ@boK_g|c?A8F"F@x^,$_xC9X.±9["p=@U4.idw8]&4%YHG2|ϖIHQ 9 [yQ;/@I#iV<TGkd'%z t$[N$Jc2';4%Y(.\;`bG2Fu姘ܙXLmw+Ŝs␓(%OvVX9q {Dxb^%2_:{Ew*eV|&mը)Ƒpa'L0w}uB%tAR(_CG;uh|*]'5LiJ?yms@}CvbZ2Ðf ъ߹LiJ'y~5r~~*@z UK5RP# 3_绺#{5ƤA(PI5da ̷pߞ:' JNBZ"yfwuHՒo hP%@aƑ XBV 3w,.|^ɒo 1ݯ->F[C FBzg+Kx%}ݺ/^+/XA|vpH,-dV!U5 If>`'v.F [RKqo3'PC bk@I=&Eh%U|;} mAN|c~2\X]XK9kAFYwug1ݢE/#ʽ I@fؙ5<Lod?^$PEBtKQtP> hPql xEHiA|$0,*LǞo[e5ht~: &PEͼ)S tf3s NH]]tYh,!H|}7~N@F!K/΍q--"yn85m1ҥՃIMmܸyQH"~jnFq wdtQnLn\k!v_A G0ύԸRʍ{oeTT.NrB §:fĭ4g1If`_b|IK>G,Q;x/o$S/`.Լ*xp)-}w8Hۚy't"wb$C#$+xdt";[[S%jwBXiiskqk2!;7؛5J X\sZ5fn]'}20V(Fț5v_hiB0I_ fRZݸT0F$m:`CߓNIV,확=Eʞs1?'HV,} ?%HxUK{zeî}KxjeߏKp M/akӉv te/)TEg;z[ ]Ls"r{ 6PTV]?ׁެ0.,;DvUoB ;nnfp`3In%#bPY2!K޿uޭ !{DBg`WǤrƶ*m@4ynf(49m">V$^Jt2Uۥdz/Dna8J7|.\b%%\,G(!%d,V0/!O`A%.46W"sO 1U} ԁFsȤdߚ*=>wyn):uV#W+ȏѯ~{n3Gb/ /Kn;mK|~=/041 @ I3ԥ?r… htѵ5=L$==ܫ{ fbu.' o Hr7-%z1?-k/ l 02}bgM]^RJ( euX>\BrM^exC_ھn+#sz#2zl7$d,"OmcHՊo>(G ECӾnŞi V ZG+uw/k+9Rϰչyyo2 ?:͋0)n X,ݗ"_A}>svdIKE%Bӡ+%O% Zq:t"N3ŸJE* uvVvΡ !K}υ:Xm`rYm. ʛK'`!}y5hGoWo 3stCI2Bw,uE7mvCI8hU!;k+_Yx-kJ]i]XU-Y {H9_YEN3R&nd9D$ UK5TpA*[e&VMErCr/st NM82HFRAf3?PhF %ax:k=D"ԑ+P%X{~x$]CpqD]TFZ8}kP2o9QJЬu?H Pd[s!HA N Joe~Ya ZSlxqDa H)3L"lO/>XH9D>H$QF@,./JL2{(>",5@+r8Вxh0\rj'ѯϯد'~AAZ4q5e$>"+3VIwqIp;PKJ6*SȀxDIu  y&.0"j<)hЭnj`r[tWW$ﲆiM*-XuLK밾Y 0h%ܕFOrU͸b J;c._rŸӭ2x [u5Z_+yQ*QIENDB`perfbook_html/node469.html0000644000175000017500000003535211672746163015666 0ustar paulmckpaulmck F.9 Chapter 

F.9 Chapter [*]

Quick Quiz [*].1: 
How on earth could the assertion on line 21 of the code in Figure [*] on page [*] possibly fail?
 
Answer:
The key point is that the intuitive analysis missed is that there is nothing preventing the assignment to C from overtaking the assignment to A as both race to reach thread2(). This is explained in the remainder of this section.

Quick Quiz [*].2: 
Great... So how do I fix it?
 
Answer:
The easiest fix is to replace the barrier() on line 12 with an smp_mb().

Quick Quiz [*].3: 
What assumption is the code fragment in Figure [*] making that might not be valid on real hardware?
 
Answer:
The code assumes that as soon as a given CPU stops seeing its own value, it will immediately see the final agreed-upon value. On real hardware, some of the CPUs might well see several intermediate results before converging on the final value.

Quick Quiz [*].4: 
How could CPUs possibly have different views of the value of a single variable at the same time?
 
Answer:
Many CPUs have write buffers that record the values of recent writes, which are applied once the corresponding cache line makes its way to the CPU. Therefore, it is quite possible for each CPU to see a different value for a given variable at a single point in time -- and for main memory to hold yet another value. One of the reasons that memory barriers were invented was to allow software to deal gracefully with situations like this one.

Quick Quiz [*].5: 
Why do CPUs 2 and 3 come to agreement so quickly, when it takes so long for CPUs 1 and 4 to come to the party?
 
Answer:
CPUs 2 and 3 are a pair of hardware threads on the same core, sharing the same cache hierarchy, and therefore have very low communications latencies. This is a NUMA, or, more accurately, a NUCA effect.

This leads to the question of why CPUs 2 and 3 ever disagree at all. One possible reason is that they each might have a small amount of private cache in addition to a larger shared cache. Another possible reason is instruction reordering, given the short 10-nanosecond duration of the disagreement and the total lack of memory barriers in the code fragment.

Quick Quiz [*].6: 
But if the memory barriers do not unconditionally force ordering, how the heck can a device driver reliably execute sequences of loads and stores to MMIO registers?
 
Answer:
MMIO registers are special cases: because they appear in uncached regions of physical memory. Memory barriers do unconditionally force ordering of loads and stores to uncached memory. See Section @@@ for more information on memory barriers and MMIO regions.

Quick Quiz [*].7: 
How could the assertion b==2 on page [*] possibly fail?
 
Answer:
If the CPU is not required to see all of its loads and stores in order, then the b=1+a might well see an old version of the variable ``a''.

This is why it is so very important that each CPU or thread see all of its own loads and stores in program order.

Quick Quiz [*].8: 
How could the code on page [*] possibly leak memory?
 
Answer:
Only the first execution of the critical section should see p==NULL. However, if there is no global ordering of critical sections for mylock, then how can you say that a particular one was first? If several different executions of that critical section thought that they were first, they would all see p==NULL, and they would all allocate memory. All but one of those allocations would be leaked.

This is why it is so very important that all the critical sections for a given exclusive lock appear to execute in some well-defined order.

Quick Quiz [*].9: 
How could the code on page [*] possibly count backwards?
 
Answer:
Suppose that the counter started out with the value zero, and that three executions of the critical section had therefore brought its value to three. If the fourth execution of the critical section is not constrained to see the most recent store to this variable, it might well see the original value of zero, and therefore set the counter to one, which would be going backwards.

This is why it is so very important that loads from a given variable in a given critical section see the last store from the last prior critical section to store to that variable.

Quick Quiz [*].10: 
What effect does the following sequence have on the order of stores to variables ``a'' and ``b''?
    a = 1;
    b = 1;
    <write barrier>
 
Answer:
Absolutely none. This barrier would ensure that the assignments to ``a'' and ``b'' happened before any subsequent assignments, but it does nothing to enforce any order of assignments to ``a'' and ``b'' themselves.

Quick Quiz [*].11: 
What sequence of LOCK-UNLOCK operations would act as a full memory barrier?
 
Answer:
A series of two back-to-back LOCK-UNLOCK operations, or, somewhat less conventionally, an UNLOCK operations followed by a LOCK operation.

Quick Quiz [*].12: 
What (if any) CPUs have memory-barrier instructions from which these semi-permeable locking primitives might be constructed?
 
Answer:
Itanium is one example. The identification of any others is left as an exercise for the reader.

Quick Quiz [*].13: 
Given that operations grouped in curly braces are executed concurrently, which of the rows of Table [*] are legitimate reorderings of the assignments to variables ``A'' through ``F'' and the LOCK/UNLOCK operations? (The order in the code is A, B, LOCK, C, D, UNLOCK, E, F.) Why or why not?
 
Answer:

  1. Legitimate, executed in order.
  2. Legitimate, the lock acquisition was executed concurrently with the last assignment preceding the critical section.
  3. Illegitimate, the assignment to ``F'' must follow the LOCK operation.
  4. Illegitimate, the LOCK must complete before any operation in the critical section. However, the UNLOCK may legitimately be executed concurrently with subsequent operations.
  5. Legitimate, the assignment to ``A'' precedes the UNLOCK, as required, and all other operations are in order.
  6. Illegitimate, the assignment to ``C'' must follow the LOCK.
  7. Illegitimate, the assignment to ``D'' must precede the UNLOCK.
  8. Legitimate, all assignments are ordered with respect to the LOCK and UNLOCK operations.
  9. Illegitimate, the assignment to ``A'' must precede the UNLOCK.

Quick Quiz [*].14: 
What are the constraints for Table [*]?
 
Answer:
They are as follows:

  1. LOCK M must precede B, C, and D.
  2. UNLOCK M must follow A, B, and C.
  3. LOCK Q must precede F, G, and H.
  4. UNLOCK Q must follow E, F, and G.

Paul E. McKenney 2011-12-16
perfbook_html/img75.png0000644000175000017500000011504011672745761015242 0ustar paulmckpaulmckPNG  IHDRZ>PLTE/YOSTăZܪLQQFT/!֗r=CBphґn%%0HJי>15AMEק8=>1>Avhgxa_Śخ9ABɅR.,*4+&lf1'#099VZ[443XUS5?A).00(5ADJPR3?BENM2& F! ZϠ!čm@JK˫z[խ=FHə6KOO~nja\^3<>ڞALO|TAĈfuba9DG0,'EKLΥ1#<+69AGH*48>EE6DG,10,33RTU;CE6-)Ӥmٸa_`3=@y1;>.9;467/  ״wYuj6*%}_XWUWW.24-23†_8@Ay9YtRNS@f IDATxԽsם'ȊU8fEy@/ICɞ$&]\EY?NV cE]b9ޱ0:aj9:ьs"T 5feMb? %ٹ'O} ;]f5SYlTEfWmm xi+תO/LصЪb6/R4.[մ(&WLы嵦鞦n.GvzGffXt0|pSZfP5%QZ-"*XSLz6[~l\|.{PV=\lk1!MM0NO'-`3r̷M:vҶb;{Z^c(~m&&ȮjAsv.w&l,]I؊ט/rVдf]Y~E_m1p4@W1Ӛimn0G XO#q6^ [R'NL~m8i1(?B47aD3"ׄ_۶cϹi.s>jHq{?fFtM3LV#Mt/VPS~1xy OMgLTŶYL[)YZKVdj8v |N'5Cff*զ"u1d&R2\bOv >L YR, Ʉg~:\lMhA% xtSavHBA I3u/'65 U_ɬQ̚WI!h ﹿUYYYT6)?m`b)(!F2'{fggfg= wlROzD%Z5*p _CR)SB࿮$ȞgJ oniK΃K \&.NsZb pY$~>{zDL]琘0uL7C,M3rM"[|W(_=ݢI{W?T:%34_"Պ̚f[4Q>Wzf <\eS_ )(W4^4DzL{ÃB=G!Ƞǃ됟H !&)' Si-Q-Ȯ 5+9 ji}%\;-L49W^恢^ ۇ_Ů*Pdžk@ % [*g/UAZMutDsU7mj"'*##QETxLA1)lh~U46FP-$b/bՏTV~_`*;6FWAm?UqiA9Bqlc(7lUoT$W;Pf̸?> 'k,(Q=PPGpf+u$) kw`мMvtB!bZu}/NJds% Wz ?ղP.cJq׺fUجfn{La^(W\$fLʀ&hvL(}6|TUNkR3a EYEIDqꤜ*L9*1z2 "t\֫ƯUC 9E>}!1{GaL7KQU*po3L<E5(sPUΥVQg&=P٥Lµgq^B.]Xs#5ʕ92fAmw@5浅Lq}Gf@}=Vk23q]jvp|!ig>\1;26*S%ݒgCU;7Y%0-}E'׊t"wW_Yҋ,R@ewBS "x_ޒNyv+& 3${FZLi㔜$*YtVu\:V#*h9iŽs PiBUit"%&~u|Zj+Q=> Zr "I4*P]:F0%|pL {NR/\D1i2vKHC6 #i&H$L6qv&ozh$F'jY[z?yvҿjMM)Pyȃ*1UQL_ *!h;z 0_xAk] Yg#~/&A|C2|I}&f߆~SR`Ծ=*hqցM֏lR]ur}a0uB).MWk(Ondv֜<VoS1*tJHd#gLl๹#_|to`x&CK zn)Ut(%/uRsLdm挪w %rd~qQ jUNK]JDM,Tk:UX^tYP_O=n\Õ߈mfb$h&obYCTJQB~J Y]1sBȻG9IZ[SF {:S1x&pOƴm}R$U|=&gr2gC?,sL DХaP0#MA{l _`=+fOW`w8mKk7J s-x D\egk A!0fZbXK:b(P 0(#b`C,O25߄{/qYZv뒈HC#mV_p?58hQ΄s[yL\y[>9:8m[iNc2x"V+ypV< =hV21unmZ ]pJt;ߙGrbFzxZGhټ4w^?0%IsB& )dLx )oR'6 Ūͬy0LU%)hdT`PwE#x\w,>'"̠7:d [S1MDe x[3GRW1G߻4U󏆲4A;"ѽrvY$}=56-\thZE1[(r/ {(aHH"-[ _F dv}XQݴjn rjCkҝX ,쳨[*m' , Z/RǓr#);6@Šgm, ,5&72" HLÕVbF67,e0 &=W6 [@Zfx *™E3/=hH/%%#EӜHdIYZL.c͵hb,jfW񅁮fIB.㠆AA[#' vnr@ZMMal3Lsct(Tbb1ҴmhT+jB:Me\OQΌt׳>*92 * #&Ri"]!5pwz,2g0cg'!١<E'2lJ5RWxU-'À^(൒{^ֲÄ,|vA״7XHzfjmjʚXB]QS5%е| % -۳\'|RAթ6~fMdJsx@1 lh}O_Oq=Q>>JOmW*~G-$ /6܊?*:h۸SlM^s4y݊v\s|yL#+kܸag0yD=50 WsRer/f!m0+ۋ&Ju_U \dT%m̕O?핕` Sp֛ DDZ^wWXTXRY#Qz}a!YOu,o#h^ٟ>( oWNgoַdnvk} r|xvvva>PXSŊo1 M]}pjA`Q>БYs6E09͗ϸ&Idd"OFC/-,LK2胿2j5jl/Mikek۫@N1rr$P}C0U YY5y[ԟ:Kkkls4X!Փ>H, SBZz)9@HyP_`h<6&fq]U^b9 Z# 1FNt\K%iʤ禎1;V snu,:owlIEŠuts~xye & " # ЧU$gݫW2AޅN*L.e@떋VnS[׍go\Z^YD/yi/n|Wtܜ&7A)1hƲ'H,_ҩ³08j OŚV#щZ6|Z;{UXwOE===! ;N.w/M*蟛GqTux->T1!.e,KaQc:V <}N|)1G-VSZMj2|Z4EpCx?aup@mq^;6-D*._&"T4fٱu&b 4ĢbO[%DkW9i-l-~+gd ߎYg[u7l-BMd, '<| _& %4{?'6=M ԢiC=="ݟFDР/fG(c3=l q<ꌆ`GHQgi C^+bu }<6`ဍ5H&>pl} e:c|)\mv]2 o9z4:2]m3Y#rbh(ZM8UUFэfn1Y?J9mGk|FLD cu U2+N+%9* @,iI1NF!3lBO~N*H0]nYXnY,;f!C$>xƝl2ܩ6fS Ad`V LGl!80Ūɘt +~E+F3/7qL,x>_)B o!FFQUPE%0yFw"!TL4omb~ou'; 2CP4ga'2_,h-YN1tO|Ƨ*Gۙ|'gdz2&!>\ <3?B!ݢeB[PO|VƍO^ۣ 'jB厅'|[ _9P"׺͔dL<}4J&XSOkƐ̵F?%%D9 gv{˛ hϲVpi%o# LdS<7)BA&nRI?ADbiw6c6#x8l-2%7 ȇpS2/NBR/I>?5~ UAM7 58a6,sp'"xbdHxT$QX5C&Rzg<7L^/p }䪷Z HS\f6_!gyb*\PDjD6P|]׳lłV(SԼ@`N>( I0H[.+>ӯ3KgNnjJU_wDh=:#[ں`]e- u&LpZI}5[zG\@!*|VC=iSk__x^z/KsSkߚ/L<"v0f,srS#l'|CoW-9=* 7cbE0ڨ˂\Hm''\Bԟy<;<<W1aqO~Fa"#XM0b+Vhv-Vb3tE%[l>ZgvkەoVNZVBAז UqoeZn08l*ȔގlO>$U-wFʵ:e&ۃU|0K>#0' X a0 })TO|~r] ?UaQkŒOyU5cq:ڞV[(mQZCe3u? ZԠ`}3ė.n"􅅅d4X`g Wsܶ,Pz7aof]Φ״X$qlοl9h+gׯvaAϗABɺQct 09rs)8 T~bjܬ7k+dښ\l2;kJ㺞\ G/Rwdl-:-Ӭ\,ZP+s2|2;3wVKE+;NLFfNn3ș ޺r{>Xxpe_œyqw$Qz&Z\yR92eg m,3bw4eP W<.+[dNzica֝QJz_gg>WJFR'HCK`Pr9Ch16]0m6>!, Ⱥ _a'O^z ͩ~hvB ss}\|q 0gR(8(}qo JT_@􁺉l$&Z\1w8V\h^]}skK槳w:Z4s-p݀9sOfS0$oKK+6KIѰ~H}%??۰=-;sF9w_(L=ѴKxQ\V<0.O-Fpe±`X*j5ja6bF1OZIc4{b8]A۟~y,B䃙&~wk{Xci%R4jh1-)T%=y-y>?yMW~s[+ S,"6໖(N0nf[ލKz?@ӛNvZۖV[ B0t ʬ$?mз;|>y &qL&/| 3{?2yM "JՙZj`u\3 S FNH SVᗞ:ڎX XZqV3AX j2n0.zakAWʰ@)JbpDa* 9[3rAv+lE4>O&ڍʀNպR \yy.^jMEeJh@&pphl2BkCjb54ET\::TRjaiͣVK7 v񽋪W@mwm6;]_EmYG:SwݚK魒_/%7U/nR5(30=UJJ KDC#y/BH-=h 67"EVebN9@gϩgHxG6zsq_ z \dۃ/wJREVCŚgF&:9q[|` g7?_{Ntee,&F] x* ?|Hfhmn+fAi/u^i"tcqlfqj5JDRX$M3٠HZs dX/kit9ТPH`P靋W H  dƘs_,7|t .>tZ(WY%fh?M}2]3]AtLcッ i4@j.MfؒxoazfYCm|%( cl V(/o5Ԝ 6 o)2FN2ZZ2u<%`íq!bICXk C ;tV:w Cl2V,C+ń:6 '[Ӹ艊q}0~tQ RRF;@tV~Eܘ!7s ":hh5*}X6]Tv]@hyꐧ`a0W!ָܻ^ߺӅV r:R6vϐKI(q-ݺ9È=4߇nmn\MDlэCha)߂ +ps<%MYٽP @ !E3b> ]-m,r,05'LE -/ Fxdp8ZEmjHMUhb *GF)QݻQ8mP(jf}ɴNH lRo7ƢeT*q1:.6MO"Z'Dju\o"2(Z8+iEPXRMam,N1Ab/7-xz,ڻ~ A2r-BD;5 Brg*=R ;| Ļ.δLT,Pf‹O`m^TIObY%WpAd<tcڎEO OD [_eˆ[nRg|{Ea2 {F+=(a([pfh)aX${^U[bAP!DoiiƶH;MCjړص ^Yp[?_m}汉7:Q)FJ3PxpB" 4}/h>A}Va 2s_Y~Dxw*i@4ruƢsMC,L+̷DVWxB+XэFgP4#@x8,}UJ㧫;bŒL&|%n^6_'H*%GKܑ54BڎuFSV?\Y9^|۝2ulvn3.m:('h#ł49noL.>t{J>y 鮬\{_K82^RErr(;yCjCh=# lGI]| цubq~[VbhFyR@Շ~nHl6~N1Eψt>.HF:?R}v` MqYvM#Ӑ"E Šjj8t?kzI0cO|͟?U լ<% ,GL Q`g%Ѳ0Y1 ~v `8̼~j||gࣸ[U0r Z&gX`B0ўAkh)I[[O͗TYlKڱVǡe/%'1d?RfI%\COO|YRA@9u5Ch%NRhM̒^8߽%m5V+坣ơ9DϚYQ(YuӐM7>;|*"0x1hwƣU 4-.ؖ"9T0԰RC_ݜ26aU BL.箝) #/հ^6"%t,QfSe5SˌKXy@f@\jr+}:^z"2-UV$%k|Y +=OוHF[D: ȯ-\WtȌQtia)_$'7@6\f"0Z0 kQ1в)OMQ3:% ' ,mp<*9ˍEN'Ijt\8B :uX ЦZA7y^cxb3A%^ppq6WoNtVahy+pvV4oZxC9(a rԮA?8`L!,JZV8~] XV)n#*-^<2(p0Zz,W*|u"!UhyC Z Fx1Ve2z\2[͖EdfsxC![@*>r4EXKvKt_hÄSmJ IDATlGO@jAϻ=p˛jSR 7 kZ*ODhk,%[t?/j/4. v{*Sn ܺˈΫ43h 16uيn7jaX%ekX`ܘb zƘ >h]4𔢠lxecYل9f3XS pKuh-.!V,OfYVAM^#hAQx:i~>OjBE&abEHdiǣ-ih2u-VLkQZ+ߣUO3L[e}9X(Sv BR򷹳F+Gs3䖈Zps*vh{dX]?֬q=CHОjQ=eMdub5lSSSEIZSSkSJi0l`x5QұlDB a8=#h3 cWeqV>zt% غKwԱY)ԟ-W8m3Km~U籊Y0!*"+'QF BֺLJ{RU8]"^&N]XdQ/禦?S<~ZP),JPe,uњwCN.eL+|?nm?V*sMnp3=X|U*;A?X=x`l(q3DG r Y-|:*NWfy''zb|pzzn~#_lG3g_ZMboQXX4UAhmݓ!d^dc)ov({,bF>K5L]no?MUuj T>sb^+'Qc'O%ؠO@G̴vk/ܹ>Y.;ni{Zg-4 yfFІ{l֥P~M~+<3TZ n+'&{oNYOF/wzHK gBIY\lRc`iF6lrpQﭩ??=t+nn',}0d90I@V*fJF(#hZN !*"jH7>܍-~v0ݕvw7Pij&*!{.\&K(TS+"D% 51p6wWhw_OɺWG簪.0'&gn>lpfV.`mՇs72sOϠĭȱ'k:$Ɋ , L.[O鄡6s7òѢ 'l҈YxL=|k5*3Q#.z q@<~jvg9 غͧ#AY.#1W__|"IcmM #hߏ[Ǒv Z,#[r9y>ۣ7|jf7W+l(>bZVX-W/30f/F/㽡֬^̟:4Dut=;(XDNI] A[/4vyYV糕౗]װK'fR`.u1ĄJ_ɱkT)Y]oR6y^`k7.o7Kcc!G<=2{ܕ?EoT_ġ =Oh':z#y?zWʞL&yBX%}crw,J{ Vƛ-[6+0d|no״4F]=| ^}C[$_0R~ƊRZςl(+/?dj1Zƺ+[[RwV9ikw#N*@Q =S23`Ola#Py#w\ 11P}@ZFO춨>7[4^*T׳AS|215ʋ`V5*vխ׏Ŕq/9 f+ok*Xx~زG߾=ٙ?)kjU7'գ?ZGe٘o ţp{IO.IUm`drqqf8є a>(ڔBVSɍO&jV c`|t7 0`x x@B;Wvo/2׮]kUZ{dq<11@lgC M|k|PGڳ݋ Q }{5O+ eXmpj^$(]˰gt|RwHȲ vh;Sn婏oL[ B ՞LSGOӵH2Ck3Z tZAU׏eDЊ;Ha4-W /<BWXYlu5O`F[xNkiZThchMEztMnK+YgZH- "qIu^M&uMK N3_Dȃ@ChA=\>>6`Qpk.߮ Gjy;G{Ԡ|KOv/>;?H.RdY0I83.NN 5=]\sJtnVz#ja8%92#+q:a ڡN!Z1cFQCV6޽Z5`/#G4 d"M>4ENCapV@U]x:ht NۿsZi-`ahӱSCW\6Z9k|VǺaUp#&̂r'2[RD9 czMv:],=|!NFZHC&9ʱɎyQ<؂hަeڄ*gſ^;H; Hv#oy70!mu=V62JpFʂigz&q!hK.1ݍ>deޒX3kx¡n#XʄaCΥrmIiADvL.F'EF/MZXCqk3Vzi(1Rw3cWq"i:LvOI;Q*1]HZT#Ł4 riځgiqD@?ZnSHG~#sm#81e'4+s1Kvg4A(mG߉kP )s,iǓY lq5ffZ]I{?gI;|>uTF.GƉx i=IGQ1,{nH{b=4XwĞfV&'s2BYfM&/sDІ݃KZw/@w$! M_S OBKM%[=3Ʋ4Di xnG6f"Q4)ȕ^kscgױek2{9`Hc-& պT\Rb?|¯!xGI tu-2~-l۸biArBc6qz'6r]hׂ XQmk:BK E[Lb@b7sƊ(($q6H4`-mFm>f @'=}?w߽w_lh 6PUZ|,mjD6%`Ik9b a̢X#mY)45gyYiě5U,Ϸ̧XCy]:1'*5կUeEkBn~r odچ7-}*?MwXT,}ӭ*n\ro-6bug:В-ҽT5ld uMMժ3m` <*+(hQKOmqԒКXPftpH}Rܳ +"Tk) .3'>RvgQ6D$N0\vйb"z{MA %%&ˤ fV jotF}hN]lGkqh6-\fy$ ahTPӲv6Vx> mt>f>--n4WuG|:=?ƖAFe)ZnӚrKd!XFJAjkE 'zsw; O6儯<de}ŶJZMr.(AIYXEfiN~o -Y zo6Fփ;+y4n)d#r9/\͟ V𑯊?V˝'1cii\x^9>>晓3Lh!j![x6V.r0x*M5m֮ U"xmU3oh'$9: ;;w_ݱoϜ/]S;-Jc]% VGC c\P3kZGF} &Xc?Q'&Vz%EJsІ*y]ժ>^}S-W_c1ƿT22;3"x1`jp1P`C˺{\ai9NalZ;ڶܲB^Tגx'zf:sј`FkOL\^zwW<4W/?T0Z/m_5-` _9t@x j&!zaSZ9G on-;Hδ; nS#l2YCCi."QBI/kIzߌq#,z. E(>6丹'bliDVp*~'άn+wɔ1 ! P\_alA^Z >hlBKmӮ nEHv!QH?g3#uE\V]e3[fvvV"6ѺaezI)і֣|1f,1܇h4ABiYw6D+MLYt^׵O,DC>E̸lgp=hq]T{pr.~Kl;3-L|ԮRLjwAZzh%R xy3ILKkJ7ꮉߦPC\Ж2}pdEijYIlsX=k[5u;Rn&z6+\VkEg 3}yn~.fLu;'~FmcD҈:h١!&hNhY[q1 ߁,L՚)<3zleL`N&[[u?qՏꨳa׎;n w-;m†L^ ]ehGKZ=G;1#뱓UC7_N Ɣ4vh voϮb41Nr\ՒߺPO=տl#߿>PJԞE_ VoFjf0QHf;VeWŭȂm" ڼC8=,} {..΢ϖ;}w~o#'P a"6K] 4z&!킁lRzкmHmViUV%dȖ:H˟v럧jlP yr!h6*ZN leYR* nVmV9ti OXeK^fm5 I$FAZnyU8m:iΗ vhDB%hSO/Nh5-J˗繷?mym3ESh4w%_lmT7Mj.vl !w1AXdq;W-f˚S5Uhc}"]V܍ư[qch Fe|R׉vN~m;Zrm/0&V;[<ꆩDVy7m%S sjje kZSk~ n-k#Yr;׌/K>VqZ3T|~$f]+g4Υng͗ 톫68ybOpڒ,= D$гk%y,h}_H( 2 Jj> [k6SvT`Em X]腑mUU5aVUүa,eΆێ˯Fhnҹ:в%~E[.Ӏ%L0yBn< p R. wv FM馐Ct,.k,W|4`K8FdDM!EOY#9)$ d V. {Fn#xu ,̦vn@ˮX pR\d* +m'mt+7UMCtp&iE{c {Ocɐ JBgӧK|cO5H d9.4 &Q6]G)$%h^CZmYJ`bs \v'O87h<$l`$SnI1hA(>e$6ȶnl0bֹn'5Z!]I9KiqeC\翝ǥ5&L|]ݦ&Iʧ+jcٶm X@\@k e񨍦(xgvYY̔2 6@ Tp]u_ĺZvTVJMZ\LMカҭi_i-7pZrtF.[EIM:T:9 ѣ3Ǿk,J.R{chi>9qo8q*ɊlVPAߡi "btu<;>A 1MYT!-!uy8E^sRi;p8%ͩ|< ,Mt`irU]7D\ese7thKshU8V^sKtp{HIMpH#+^nQ ZHzF8lltq()ZKJ]2YWk;ښN \Sˣ0uMI?_RPÆQ-n܋TR둧#>y-J)C@Qpfvjׅ"tS0.EVR(Z3VA[鎂m~#'Yߛ<:_JG=$Cr+/6 Lh>j+ f6{K;}@;zuً+BH}ߛ,2Y.xk+2]l YJ1cuA9Z5Nm!5ҭ/??{U lěѶn͡ 8I/L(T}AY1Gҗu-5j"Q5p]#\f(aZ"R,25 dd6JdGb;tVQDiʟk(NJU eB58T0MV :VvВ!]E$e[Zlr#OF.v%a$_Uk JzUPi![Eh4|U^%@"v^sІTGM:Q#H,n(\g"-sJj*)TAgrڡ$E*W&\f+eVz*%p 8:uMq-P Y$'صhBivB+>JKT9K(W]VdEdT|ӖURiȪ(:!Dg2N{~,Ґ(i6laYn_;ыE=]kJ2PSh \KvΣzm91&@f[d=> dl4sӾL~Zеub [%[ɟq~C fZtͦm,{\~k0Wƥo+*<Ն_]r=Ѣ+x0c A+F/Zdm 8+0TnծF=3lA_Ϸ1f d) &֠Zk3h<,Ԉ'Ä\׿QG/XTwvQV2Zt7 gphɢQ,[`Fv*m6>+DJQf[2 9|YZQ`$l4VK蕞5ypp0F,i$u]׍zS:]5(5[E} WڳbU˯Jgr}> E_Ks8ڶe&Ձx ]@G1U09uB2:X\QJ3^ В6V_%8=RCGFu*Gw e!bZp0@[Kpif5]rq8$ AJsSrӲTyr8~%_%+ͪI maX"pS (Z@N&EԷ8/$ci\h%m a#h_K2 H\5͊XC[.Jd7JC3VKR+m<^Zŝ>N"A@o `߼҈yAMF"}0Q_G}YW4(uM^17,Qzf *L҈&zk)D<@JK6D͌l |W42Pdt,faUªoERӃٹz|S 3*hڦ8 \LWi0X-o )d*%P(dU?$)h>+r,R ]CiKH)b^#{/c0J/,sȘ",#vugк=׈yZ@ʄ*GU5qBK,DV@K|LMHJie/k4XR5kd1#0cD0"Ser&ZO-$;7BcYH% zkFT:WqGڳo?pKZ0,i˽?j+R1],HW@,/Sh|w'wqCSqYj&nx$Gd1?'/hjuh=TL23ډK-IU;]V'нbr8ϿI}D@T[~KG|B)}] ٵϺ;hFK;u=v=\5vZt,Mu#YO4Pp[G,7_6C-O򱓏ԆIVݻ7lDp6m;Z[]w{hXJ2w{lFMn b|?ݧ_ ?^1ֈ%/ZDtc.PjkdGUed,yȑa}udҿY!)^Kt;vG7sTU;{1/Yt[sn୕i/%ENDbWf,U`\2~jb+?^=3܆ֺXX`,8wzz#10?*^=1KZÈn܃.n?zcmfk6#ĊeaTC{7s*-'{'@Qb~i@ uȥn;ޕ%a5fm{m`3<5bzQfI>F=,ܻ^`)3JlmL DΐL}'\X>{lf,3F,`3ɀ_Wt@}SהOĹhH 7oYL,;;S^+p{v}A: d择a0/c #i/AMɽ{Kά\V2/XDv,e2EӅGF^խ{EKRCڿF ..|g_֓w/d;N.H7h/vw和x(3ҫcaGpL f=MU,k60bIDAT%$mi* kZMHGN߿D5S+Ro퇟DeǘƮalgaG#)YY9c\T?9^L>ٻY!X ގ& {FZZSLhDm] tz#F1^PrнW󨀧ۍK eumh7s $E}2> 3Fв։Rfk[_|Ŭ#IE2]:)$;<Ϛf)P0 ڨS hk@ 䤜FfI^c/&wO 5o8|9?hXWԬ;Q ( ٔY9 ֑-Qw,--.]6& 0AQ794hfCjI}o" vf)oϬXl\+ZhHw9+/KrSꙏ&03@ i {cɰw e l7ܛ%}eUN=>{ߋ, [*kLr%A?xv ڸלқх 9QfJ988Ds/I`['ɒ2=ssRʕ]d2DROdݸR~ȹ;d]qՎԆc1WCh c/a Y_yBǤ6lz3^m]o@6RZJ5&~W^52!Dw dP1a0Uvc5$eH{ΓP-[<=|n I9ՍɡzGι~f\S)C*qҊGu@2kƍx^I703A9`**Pu5қZaF3g^\0h\8AfF]3EP,gKE.Hն?=LՎ? KǾ5z8TɑJn H&ku#Ĉ<#sa 4̻WyaHmmKhs(\Jl"X,z2mB6~Ye9sm)sqGlǓFRD)p잻piM' =lV+nMIjq,R7t֍ca9T,jDt|. ̽0օ΂L& !8rmҵuT~9у7l0}r&;J5ض`>ry%X~ k(Iv&:Kݻ}?;"wuu'AW0 Vh%)J2'h]>jN>쫯3z$:-B[ 3khܕC~7rQjtٚBf=>K\NL]gZ.5-Nzy(\. @IGP:}d7]BWLq,gx#u+T=riF TR7"[m0i4"2n4bmZ4P\uÏfP0P8vQoD䋧t7u"'p9 ]oD5܅k;/=z3j,l$qQܻwi#I, ƢcV3ب_X jg $ZIx؊K@Qcx9U[Ǭ0z;ߒYВ` ,}js(ڼa\RۿJ$Q {螵'V=܆PŁmȂwݛwUޫh;="pmcWqRޟs> n>;ܧ[Yˉ%u6FQ lT*Vt;J]~އONL|zSshT AjR4IGKVX.Q,Cop}u(su;nҀ.^4@#EKu?(apH?/;uLuG=lF%u[K:Q.#5QjG&-ƒ1kďB2 =}XϤ2&03lQ":@hBV::.v/{JT陘w<qwM=ee8͹g w("d3+bnLN) y#➝eL\6m`*ii\) ;Gd8KF6Jq&="d~RRA+I{FvǒTD,Y@%˷>qnWjbY?3VM_Wn,[ڐ6qJ[ \?4%7Dk7,9 rNkֈދTycR$Ju< nB*R `&q!\i\>:NU\Gi-3Н{LvMb#%HTE3y^۴Ek,͗lKW)XӨ;r'Z^pl/X7ncFKϧGj{¯Ju bjw#N^鏢W! ,䍢 h)mDoW(jk퟿}`ꋒ:LdūyI3VwQ4Wk9!'DbqIͩDhU=\GèS#Fx{RLĞchWNnJmF.p%N$qQ W]ԋ K%8c<$}|~#r}b\$/ 1$ b_eZ-!.Utx(xZ}FHmbn ^:}|RUT\#T;4s` =p0j:|v@_Hdc}ؽZ68H7j( MbnLC`^hk(yjʫO2o;wTxڌKr,uMhEКR]ti/Y IՓ@1$I;t~3/(89E0ap&|HYEUrҝEZ$%XMIu]s~t\ןNd $Sڌ¹rԹd}nx_EQO۰~L+ Y#F 'GBvQ -++U5Aw׏ꊖ*`(ʷ&#E#5QQg\0#iĒuLOWa$|$I`˱XOr[RСYhԔ"XBp I u4KjQ}b(D.$zHvr^oQKl1⟝ǰՉ$<#w ,K"\*=ʸ۾ }uܶ h -N[ឳWqt"#Ҟ^#z@0i5CXy]rrFSybCj6CZ. ٦Fe ը8KŴiY-[]2khuZ$p"U,'^Ȕ̂{8p~d:]pݗ%,9"F2!I }c c|%W$+zD6 v-Z ׍!mGCKB6DES=-5-t"A*ʩ|n$U/(Wl(凌r@?`j~w%um s+gtܫu1=Lf ddRTs :IB1봓!&ydܫFR?@#aQz3uzUpϊqCIG˱؊$϶eJ9yd8@LWZO&ZOhrg7DK9vI‰1Yè~8udxI$ d_ \}5:fN]KmX3uT9BRtΐY3zXg_X]}mqQK A.1 What Does ``After'' Mean?


A.1 What Does ``After'' Mean?

``After'' is an intuitive, but surprisingly difficult concept. An important non-intuitive issue is that code can be delayed at any point for any amount of time. Consider a producing and a consuming thread that communicate using a global struct with a timestamp ``t'' and integer fields ``a'', ``b'', and ``c''. The producer loops recording the current time (in seconds since 1970 in decimal), then updating the values of ``a'', ``b'', and ``c'', as shown in Figure [*]. The consumer code loops, also recording the current time, but also copying the producer's timestamp along with the fields ``a'', ``b'', and ``c'', as shown in Figure [*]. At the end of the run, the consumer outputs a list of anomalous recordings, e.g., where time has appeared to go backwards.

Figure: ``After'' Producer Function
\begin{figure}{ \scriptsize
\begin{verbatim}1 /* WARNING: BUGGY CODE. */
2 v...
...);
17 producer_done = 1;
18 return (NULL);
19 }\end{verbatim}
}\end{figure}

Figure: ``After'' Consumer Function
\begin{figure}{ \scriptsize
\begin{verbatim}1 /* WARNING: BUGGY CODE. */
2 v...
...j].c - ssc[j - 1].c);
51 consumer_done = 1;
52 }\end{verbatim}
}\end{figure}

Quick Quiz A.1: What SMP coding errors can you see in these examples? See time.c for full code. End Quick Quiz

One might intuitively expect that the difference between the producer and consumer timestamps would be quite small, as it should not take much time for the producer to record the timestamps or the values. An excerpt of some sample output on a dual-core 1GHz x86 is shown in Table [*]. Here, the ``seq'' column is the number of times through the loop, the ``time'' column is the time of the anomaly in seconds, the ``delta'' column is the number of seconds the consumer's timestamp follows that of the producer (where a negative value indicates that the consumer has collected its timestamp before the producer did), and the columns labelled ``a'', ``b'', and ``c'' show the amount that these variables increased since the prior snapshot collected by the consumer.


Table: ``After'' Program Sample Output
seq time (seconds) delta  a b c
17563: 1152396.251585 (-16.928) 27 27 27
18004: 1152396.252581 (-12.875) 24 24 24
18163: 1152396.252955 (-19.073) 18 18 18
18765: 1152396.254449 (-148.773) 216 216 216
19863: 1152396.256960 (-6.914) 18 18 18
21644: 1152396.260959 (-5.960) 18 18 18
23408: 1152396.264957 (-20.027) 15 15 15


Why is time going backwards? The number in parentheses is the difference in microseconds, with a large number exceeding 10 microseconds, and one exceeding even 100 microseconds! Please note that this CPU can potentially execute about more than 100,000 instructions in that time.

One possible reason is given by the following sequence of events:

  1. Consumer obtains timestamp (Figure [*], line 13).
  2. Consumer is preempted.
  3. An arbitrary amount of time passes.
  4. Producer obtains timestamp (Figure [*], line 10).
  5. Consumer starts running again, and picks up the producer's timestamp (Figure [*], line 14).

In this scenario, the producer's timestamp might be an arbitrary amount of time after the consumer's timestamp.

How do you avoid agonizing over the meaning of ``after'' in your SMP code?

Simply use SMP primitives as designed.

In this example, the easiest fix is to use locking, for example, acquire a lock in the producer before line 10 in Figure [*] and in the consumer before line 13 in Figure [*]. This lock must also be released after line 13 in Figure [*] and after line 17 in Figure [*]. These locks cause the code segments in line 10-13 of Figure [*] and in line 13-17 of Figure [*] to exclude each other, in other words, to run atomically with respect to each other. This is represented in Figure [*]: the locking prevents any of the boxes of code from overlapping in time, so that the consumer's timestamp must be collected after the prior producer's timestamp. The segments of code in each box in this figure are termed ``critical sections''; only one such critical section may be executing at a given time.

Figure: Effect of Locking on Snapshot Collection
\includegraphics{appendix/questions/after}

This addition of locking results in output as shown in Figure [*]. Here there are no instances of time going backwards, instead, there are only cases with more than 1,000 counts different between consecutive reads by the consumer.


Table: Locked ``After'' Program Sample Output
seq time (seconds) delta  a b c
58597: 1156521.556296 (3.815) 1485 1485 1485
403927: 1156523.446636 (2.146) 2583 2583 2583


Quick Quiz A.2: How could there be such a large gap between successive consumer reads? See timelocked.c for full code. End Quick Quiz

In summary, if you acquire an exclusive lock, you know that anything you do while holding that lock will appear to happen after anything done by any prior holder of that lock. No need to worry about which CPU did or did not execute a memory barrier, no need to worry about the CPU or compiler reordering operations - life is simple. Of course, the fact that this locking prevents these two pieces of code from running concurrently might limit the program's ability to gain increased performance on multiprocessors, possibly resulting in a ``safe but slow'' situation. Chapter [*] describes ways of gaining performance and scalability in many situations.

However, in most cases, if you find yourself worrying about what happens before or after a given piece of code, you should take this as a hint to make better use of the standard primitives. Let these primitives do the worrying for you.

Paul E. McKenney 2011-12-16
perfbook_html/img115.png0000644000175000017500000001406611672745773015326 0ustar paulmckpaulmckPNG  IHDRJGn?PLTEb``MJK# hffmkkXUV856KHHC@@wuv.*+|zz] ktRNS@fIDATx](El@{0CU5ӷ}ƠA N,( Ť;Aʜ14 g-)?_3Jƅe,  V2]2|y#DʏkQ` \A[&tLL5`N-~~˻ZWgh 0គb TqZՎ~5ƳO$f'4 vo-9dKY5oq \5~?0Ibc`U4f9@ںL۳XgN i9)г7v÷Q9ׂkLs:jX)qngJ-WuE[7͐>/x~_}3a]w9֯-~]a9SB:? %ƭinPnZ7>ڶgP-)G 8o`-bp犛ACX-O& bW3VFFKѶD1:u'*ENre/3폾/ s^tF]>)M:/Khfkڞng0,E+JiM~F?r5RfdFw*P[dyj|WNx.yEo'x_#.Z `;w({|p}co\+9Ghk8r. MyA$g38QZ.!͚JAӛL^.LT~2x{џ'@\/`YN n'>0^ vÞ"д=+#iES'o6\m 9_B} Ws:o5/unX N}+S uIF\MȼQGЙsFl-/%*X49g@UFW^/w3zk7\mo{(Gю"x2yT"0xˢ?ZSB/)گ/D"v*1g=Y6'䤼rN79U9/"0c=Mj6ȩ۾-sOB|A յXT(ӤkjͫPAmT88G_I,4ݡkU(Vfgls8(á k)&s k폪'@k,wy! =C=v?dExP'@L*^ۘb2-ZT+"KU\fyO=ae^^N a(ku2_ IQFCdj8By 9!(X$;˄!4‹A3[ܞ8Q$j0L̵nF\r05{5^KoBxIe993An`DIe }|ǚw?;?t!~ɐj&ʝ>y2eX ;B3܁{b|D Ԓoo̳.rCemmRGL>csj˾u P:y]n>2WC2g.%am'^(sN Ygw_thQr>7:Ka > ^8yT#Ī[3d7ۥ̫1`mbPuyTі$`6lf_qڽ"9C > A?sA Y4oV0yHdLX+gnЖ cM??{q-'0c^15( C}lOޝ ʨ%BPVeqǨiu%~P m9)o>+ F*#|'h!~~ ?C!NGK@~C!ȹ-@~@ɠ35Y{0 < t#*&8z3"\܆:y3h5hy̎py+g5Dq+ؾ=k FyO8Oeu~x,zpؽI2]=l,I YBM9i)uxB@6I2Z~'^]^qw<"KrUsمEn(yTԔ[˴-޼6aUt=.EܱT|K)+8#(2*/"{!2%j*Q&sr$J~iTx$$$<:ڬTS|-MM,A(}-w!:gLprD ڛ|-)y{r\0CrLG~^."+6aʿ2a7ʄ_z&\4c6)< 4d 3cU>~TDWKh" y&{%|B;l&mzc~(@) jSʴE~A M٘ɜGcOhmM3+]7׃7emˉ2ȥIYcp1%0}D1I8׊7߼o@EvwY&(K9V#WnC]TU@܌aSQy eBWc_+@ul3+uN[hL3+Θ_yer< ɩ2ae֦ =61A4wG$ %k SO>4ɽ4JԔ H^ag\[ uNo3Nlэag5g<+{p^lJM"ĄmnzYzYʥ_3睾rzqbkrgk.1wjнn7Y#@lIL$nRI_yF);8IL;hWt֔3JMCSs*lňd&XpsD\:r|"5ewS 14.2.4.1 Self-References Are Ordered

14.2.4.1 Self-References Are Ordered

A given CPU will see its own accesses as occurring in ``program order'', as if the CPU was executing only one instruction at a time with no reordering or speculation. For older CPUs, this restriction is necessary for binary compatibility, and only secondarily for the sanity of us software types. There have been a few CPUs that violate this rule to a limited extent, but in those cases, the compiler has been responsible for ensuring that ordering is explicitly enforced as needed.

Either way, from the programmer's viewpoint, the CPU sees its own accesses in program order.



Paul E. McKenney 2011-12-16
perfbook_html/node238.html0000644000175000017500000001126011672746162015647 0ustar paulmckpaulmck 14.2.14 Where Are Memory Barriers Needed?


14.2.14 Where Are Memory Barriers Needed?

Memory barriers are only required where there's a possibility of interaction between two CPUs or between a CPU and a device. If it can be guaranteed that there won't be any such interaction in any particular piece of code, then memory barriers are unnecessary in that piece of code.

Note that these are the minimum guarantees. Different architectures may give more substantial guarantees, as discussed in Appendix [*], but they may not be relied upon outside of code specifically designed to run only on the corresponding architecture.

However, primitives that implement atomic operations, such as locking primitives and atomic data-structure manipulation and traversal primitives, will normally include any needed memory barriers in their definitions. However, there are some exceptions, such as atomic_inc() in the Linux kernel, so be sure to review the documentation, and, if possible, the actual implementations, for your software environment.

One final word of advice: use of raw memory-barrier primitives should be a last resort. It is almost always better to use an existing primitive that takes care of memory barriers.

Paul E. McKenney 2011-12-16
perfbook_html/node290.html0000644000175000017500000000443411672746162015652 0ustar paulmckpaulmck B.4.5 init_per_thread()

B.4.5 init_per_thread()

The init_per_thread() primitive sets all threads' instances of the specified variable to the specified value.



Paul E. McKenney 2011-12-16
perfbook_html/img51.png0000644000175000017500000004301111672746145015227 0ustar paulmckpaulmckPNG  IHDRUW fPLTEb``^\\\ZZTRRMJK956# hffmkkcaaXUVPMNNKL856iffKHHC@@A>>@<=744wuv.*+?tRNS@f IDATx} ó.zlWtOD'1 |^(gx1UkڵEݨ h'V?O8i[LɎ)HVgU'DB%mCo!k0M=o |Z>6p6&낐& Es#w^cK __s66b~|zaP$$5~ C+ӡutWt`iyE?B=ڡgB 칣ܘ>TR&GP޼ﱀuE*ꎍzǕ/u'b ~ 'Q ܮ&EdT3DxB!`Nrлv%L+Ì!nqQ9=xE(d^t] rrs<}"'P0x3wyp@!|Eő{wFݫ6?d sXSf$@5/?#JI}JwC(&?[ ,Y c⚴—RGħ'RGyLM{sS Lc`;y >݈2kކ 6ꀥ3󈀺Ae#?3G.JtL;$IA\IOՅ,=T).Bg3XLҗ=KΊL3vjKSV:T-ySe"_[zcqQ_MQ\Syy75L 2 s\1XN(lrdvdFZVVXpxO.u#^VxSTbİق:gڔ Y3O:{$ &+!IVC+ﭭH0{OD#!>e-%3!US»UxNOz;otI['UE'.*yx/;ƨr^ʶCf'Cm D'C,NhHvQ;WMV8g!M깑f9ldteY=hghg`/-ﱀ!Դ&Erqh8fyz\ˣVb-5*4C$ixJz{g' K S3B̽lKfm#~W Wdz2ӖR pVU8Uމ׾ގ=wWNɮmw:ެ5s?:wUAlcra RXk\#-8 [vrHU9fR QMܖC(Cƌ0*»n"i%sb.39T(!\q EE}\mZ}4_y[ڃsô&jYtF0dE=r )zhEK7eUM@ W\2[1`'XDf9m'Vi6NW̉M RGanhv9ycyoyrIH;8x&Q!Zj`+P(S˱KbD`jUp uTN9*J%9 0TIY <^ZR0TNg"ogxtǃs]ǀГEQ XGkZHJmEM!ghl;%r ynN+_!Y~~~]IoݰvV>m͝S>i] @`OsOv.ޒx?He;l|`>dBGBeTP.-g Xey {M UH7&$8T~N4.(ʭWBs{g0j$rJTQ+#n=3y~\bNc7=*gaD]ڪC~y 1,'}:ҹZhlpp׸P^iѨs<Ջ+U-By&>)?ad+e7[>.~OWG`bb Z>Z yc/DSǙaϊQp[~X8a#iE߲*C&-=oY9X1'2no!yZ//7y7x-Az0O Fyl0Q4V"(W$>f%X1$7Qf:ߌ9`UshL1zV$?w(r#ydQ4f2Xՙh:96d S2McWL5b,7`рl`g큗Eԙѡ\#.\-C6x.l 1amHDN6Q4H.%Q4o(1/GXH0 Ryhce.,Cʯw!q;0=@.&*z/jz6%*?QNϜ{&gjOvũs,Yd`EmE}U^"B9CJ7 I ؕ~{t^[z;W+{MpQ!P(`d gn%M (7~P%W#*͙'C@-9 oZBW*[= 9` "Ρ;S(h;gm&n%Li U s=C")1q7tT%N(k-KhXB3 6KJyz]#nXE-;)?L*fӛm KCB$bX DY>FBvU48"sf3)|ӏb\w F7QE#ZQg$k7 귚񝛆 Vceapc-uohsw´*ϖ LWJ7Oc=jp=YM{cZA=Nx!OOVy|G)?Z4e]q mUӋ}+b< k8lL狞 Pɀ{BϔNiƵgnCOx \\WȈyE9\.0%YM5Abr @C|o49`dRVF P}Cs]ژoꀦ,fBڎ[|#H- 7\mD_t<?jk;%kwGdnx@G٤Вޚ3CaGt?0 w⬷JRlvw\o eцBOBI6s ۞- _lY `XoydyBi9ǐ- rԔ|tW&1Eǿ6@HK.\4l f5nV9h YNb =G7d.?-UP\4 f.+;st`?w,X$J/c=kE(+Eqc."rhKhHq\4f'ysYF ̛{ 㚭К6ݏF]2+8Z s\4 EC;\4e-Mfa\hKk㓿W˯޲CR[ Mkfe ʄT^S<땅wE[.n!ٍ:9y[VR^D^E:jl&ߔ Zi\o_3͹DoEEs"mh@qEs _ࢡͩ+'Ghl xߺD3kk!/ TjMulkVO|D]ϳݘWʁfdsEhf*=JM'Kq @] 5 ?)s%7bg;,$ZͿl,%>9ayb#qcٝ!ez#ҋӼ'Ȁ&OA˯NM5W* JANQz뻕W(WnPr$$(H_g%뻖FV{+L% gT&M^מۅkʤyG}trO!/T 9(FFmL堠x򊠐P$Ibs 7h`5M+hLKqAy vIUN{v҅тa5H:ɧZn-tC PB|.Vi$ٕ(x7ǞU.Ofua`$tRU` 6&9./B&gqå@#Ћ 7fr ;~Ũ/WpøQߗlqF ny.Vn$y˿)\U5| o%tJa:US kT3.XyJ0{p5]q7ZW\n+C_<'u[a) Y E7Z}WL!@ҳ _$=繘q6k_;XprYp-(Rsˮt-K#rdWyllGIWݘղVR2*j_Q4  te!/xGh{ 5 ۦ }]WXUR` q\c&O# EO.A' 5VsBa!k+>/neFpDk{JXB UrF#Ady&̯@) <Y6%-JIw74a$8rLm?伐藱f܆dȇUbU}U"Rˆ7di8tS?djhLܰ(zQVR]Ât{yNUW,zk⅐_ B\SRNEG9Y wcZ[ț/B0H +ΚK)7Ⱦ`_JqH vAN?bߋ(3*[Ӣ/4))%fTڵ2K`䓽( iWj51eHtA*@{ (EV" >^떌|rnt8g0wLv/[% 8Gfb+yr?RS#C-u.j6R攽0\F"ҏ_eXHv՘ 4::{v]-d Tl4ipg?/o~JݩQ@>@;v I˕ %sh:{$=ZoOw]/Вtu:Km==s.k-12tvցdu&=Ҏ[HZPDOa[D\Kb4pEbT3WnWkaYQ ,(iWGN#lVZ\վԾX~'c%W{y' m2ű]LR\q7Y,HnѥZo1)Ho[!E5~\vT;r1e}'xURR2b2qjH[W|:^Ri,= 6MQ({x}Z*|3_Llp6*, z@#=* YzU|wַR! $WU,^/\s9>Rk"d9~hH, 7/*uqT2q*Tg(4@l_rG.zE\@?žBl/$ b?jp7  q?bO[Z[F4egeϚ_ù}4|žFq'9w%'Ҥih//F+ΧC@*&_0U,Ea!1ewʆ?&U$;\B,u(^,f2IOǹ( .t.WA!Svn`.-M8X nVys^㯠#ebvuR^ܢlZ*奼"+zHZj |MmID*VUaR[a|CmY}*#4'-UU5~BmY}YԼrT'jKZ7-{tK).YcYm9IV]&;TS+ jhUuP[c^*d-xM1پ슂GѾ4'5= r   ɠUHa4ĉh)3ci Вtu:KK k+/b ='Ĕ?٠w #eC Kepg}5se*KS;Z[ԌuW ů6U"rڑWBˠ@qʆ gj?Gw<䓕LU(9usw{Mrr9, uiPYᖭY.E01q'I@d7Cl{>9ΗΘwćAG (%)8՝Sn یB+,] zfn2\~X GPOٯc>*wddD+ͅnWՆjGIOQӋAl䪇lY|HC=0\N|F<0}T_nK| }܈+G+\_{DZj+n?l|mpq!:=0 0]nޫOQ'MAcԪ5ɡjL/z`*Q=U:◈_r= ᒷ Gr1|B>ho jg|߄|#Vk1_#<砪o繚W5Z $,r &ΨZƬliηqz^z)x(Hභ%c rD-Ui^I:+4*IWEV7;1*$YE-Ui`if~NIn%xѥqӺbwL/CFJ+g`TZ¨fK c ZW 퉛Q$j\li^5AI<GT<)TI2 V7 @'@;4h22@FBR6_-Е d/IFFF DZTBP OCPG JD,~'֡Bs tjFoA`ZC.9bع&B7"fv07?1,?d |jH!yeQpK"t~<̻aatϥhQ'7o5 ӏ8Jز6IC7Da\-j.ʋf 1t.G=эP0%(ME_Zt ;xoa)-H=?z$Bn=j!V7u-I@eh7v(lLp\Ht]\u![m1X/2b ?U z@rMeQ_40 n j%"=u8gdddlaha25UTJaV ~s-tX)yղFBZ:b2Q@` ku0p\Ŝ׺ӊʻ % I}%ǗC_ |"}خE,iQP9h]WÐ3W}om,V˜ \O ѦKu{r;av0eߊQ>g?y5vrpdg22AM :Yp(0ZQfO'@ϿFp1.p1AM3"Yp {،gq~y[Ӟܙ6}Y$w5Ryq=ePCR-9XG܏xRK.\,װ'SS(il`6oa; 0;;]RWv#.".'S;6~1 ,dN! 90%^'k2@ǝP ydt}' B&q7Ee8뻀 fvv<^ُxRXb  aW8tM "vdr2pSδbQfXKG'k !uep(]f1~|5Kb߱nQZjQ 8V.M Szc?Y"Ko; e$C1KnLa&q$.1-j$3r n$UkuqC_ܕt1=NOAW'D.RV7۽0Qó4>I枣jARWgD.̵܅tbfýw=<"ޙ#waR4g`__m)TS&GղKbwdq򰸾u|I`)sr fY* ' ֞tliOF n&'/dKyΖ0 )uڕq|rwҡؗW~M^Ζ'-uע]'V seoly۲*9- {[2DWqoˍ-zuz[mlyr+e_2uoFJ֕8.N-x[pDd<ζ)U^_]% {H >@8Aъ;Iîmc?89x7F ֮rlT7]~&eH2䐥fXNR(C$# FxGKd$9Gz]g6`5ϻC]ve9ƭ#i6`&j0B(J9#WAFfᛃ<,Uя/Fzˍm7_R|y[(y'WA֕8jFWju#/xXb@yR5y]a PX_ m= R!! ;F!otkb]YqG4n_ k2҄uefUlo;d>;qE9NIGa?F 1U: )_W1Ce: S[șw==ǂJ*;zsd/V0dWݥ|ըf 3]b;YXJ\;%Avfvʱ\h*TJv#'d$!6UC*$¿R{PüjqL.UsՃDF.m L@d\ ;!G-L\a9\a*H0,yxaOq_8 a)k†*cՍY /W Âa  1$OT k%$Ĭ ;9gt7~a70}MofnB[518)h缓ꞧfmogub\%-;ro,N!\u y:bXAJ̪s4_B0#\Zw(ѽӻ7k8ߞ3{Jk.]u]_-/*>jWk2MF߀#('o%G<ƑrK 8lC5,'9b]C"U EP Dl*OC\.xr52̥"s ;I`}~&&AϿ"1 9nYꒈl;Ѻ#y>L0,7|M3䆝v ;aQG [ rކ"1nr[jQi`-ĥr7L.q}P0%(ME_Zt ;xoa)-HU8{~ 坈Ia=j!V7u-I@֝< !e;H8LԆv6p$Zḿ<^Wx|\]_@y3q7`LS ]W 1V6߮u 2dnw$X.Q/h3<^?g k4oXyX%T8^ 넡ҸN[Jm-s2ȨRZxiT\ĸb}w kJWDBb|}%!v˳g{ ?(˳'oǯn'2 Ԍ;u = '+B f6e I+ǤsC di8 :| NkK<@wKtG!&H4 (% L 8q9ƽPzF0 &0 \|$asŒZ`Ԅ0a!~1 lHDBnc~ `W4Y~y9IDAT38j0gyB({EDFRPh&*XJ8s8sUB^Vxt˘R qXQhʚk Mb$w1$GW,+L !HV䓧iIAnlϺ,_Unl~+޾([b3RBQo0CٔXXW\NJN5q c ۻIqF49~ }I>jkS P*,} Jat#?HAj_ 2R5!$!6åhPM`TBRbS ~=\}MJyXo!4!$-6u0Q|*85;d2> YUUQtME=,T6ƿ c -%+كgzmuMA8b3r BsGL߀ղ8ӌ߀\M)[x\3c֕/1QU }1* Num)!nm)4>&S ϖ24 /\By\J4<FFu":YŵA﨨lYc\鼵tC(r5¿J$ `78ձA2{Փr̿1moA͛hR)Jɦls @r;rd %W}V(!*s@os5WƜF3IWx^yX}31<,~j#ǬbޟIENDB`perfbook_html/node251.html0000644000175000017500000001605511672746162015651 0ustar paulmckpaulmck 17.1.2 RPC Operations


17.1.2 RPC Operations

One can execute RPCs within a lock-based critical section, as well as from within an RCU read-side critical section. What happens when you attempt to execute an RPC from within a transaction?

If both the RPC request and its response are to be contained within the transaction, and if some part of the transaction depends on the result returned by the response, then it is not possible to use the memory-buffer tricks that can be used in the case of buffered I/O. Any attempt to take this buffering approach would deadlock the transaction, as the request could not be transmitted until the transaction was guaranteed to succeed, but the transaction's success might not be knowable until after the response is received, as is the case in the following example:



  1 begin_trans();
  2 rpc_request();
  3 i = rpc_response();
  4 a[i]++;
  5 end_trans();


The transaction's memory footprint cannot be determined until after the RPC response is received, and until the transaction's memory footprint can be determined, it is impossible to determine whether the transaction can be allowed to commit. The only action consistent with transactional semantics is therefore to unconditionally abort the transaction, which is, to say the least, unhelpful.

Here are some options available to TM:

  1. Prohibit RPC within transactions, so that any attempt to execute an RPC operation aborts the enclosing transaction (and perhaps multiple nested transactions). Alternatively, enlist the compiler to enforce RPC-free transactions. This approach does works, but will require TM to interact with other synchronization primitives.
  2. Permit only one special ``inevitable'' transaction [SMS08] to proceed at any given time, thus allowing inevitable transactions to contain RPC operations. This works in general, but severely limits the scalability and performance of RPC operations. Given that scalability and performance is a first-class goal of parallelism, this approach's generality seems a bit self-limiting. Furthermore, use of inevitable transactions to permit RPC operations rules out manual transaction-abort operations once the RPC operation has started.
  3. Identify special cases where the success of the transaction may be determined before the RPC response is received, and automatically convert these to inevitable transactions immediately before sending the RPC request. Of course, if several concurrent transactions attempt RPC calls in this manner, it might be necessary to roll all but one of them back, with consequent degradation of performance and scalability. This approach nevertheless might be valuable given long-running transactions ending with an RPC. This approach still has problems with manual transaction-abort operations.
  4. Identify special cases where the RPC response may be moved out of the transaction, and then proceed using techniques similar to those used for buffered I/O.
  5. Extend the transactional substrate to include the RPC server as well as its client. This is in theory possible, as has been demonstrated by distributed databases. However, it is unclear whether the requisite performance and scalability requirements can be met by distributed-database techniques, given that memory-based TM cannot hide such latencies behind those of slow disk drives. Of course, given the advent of solid-state disks, it is also unclear how much longer databases will be permitted to hide their latencies behind those of disks drives.

As noted in the prior section, I/O is a known weakness of TM, and RPC is simply an especially problematic case of I/O.

Paul E. McKenney 2011-12-16
perfbook_html/img199.png0000644000175000017500000000761011672746041015324 0ustar paulmckpaulmckPNG  IHDRW38/tRNSىHAIDATx1<3&I ,,MD/D;YD3I;p<6ML4 nK4eCz RUkYBH?PG>Qӏ>b6twS$10U7P]B7H{˅i°3ٱ %}FV%S$;dtakFp['I}fGs Ӛ?iEX{U v'j:><7}uR>Q 'K)B@ hT?9}ա,Ln,) Mcާ]BuYj x@qP{'GiH/y=;]3|}fT1QAW'֦Ƶ޷o? .,ҶaW'EK!Xpa_fdkA-B?c2^gfUsfdAՎ`)c{Ɔ޺Ӥ5c5"s@0za3c]?Pkhkx- єT[ˆ|ѮwPsLa$ .]т@E")L,Q%s_~V\3~9Gf{s-@fV/2vM?Ľ2ڨ2vnAdkxT01j Y'NPobsO 5xR;Ԅ/c3.k~W/6Z3̪l{ƶQyՎja8TȈ*ٍ",.ٍ"ʪXXdn3XV/ hI*\~5ۑY1{BY!CKZ@bftdN>bKY /^eki``U6(_[Uج6yc=X#aѢn"Xhe"Xu34=([K_ dǶ`gYa%ث+Pk_Uǖa4uu;8m L=2M f1cKPκɣ{4Mu"u D\G=6]~{gǢQFU"X]0تll ~ 3F{/Y"؁xXyXyXyXyXyXytT8'k9= >_]tm6gJw̧qNǪ0dʺ܃)dNJ|a 8:pE2Ga9Jg/Ds{lT*N'YVqVk=1svz4n .5=Οi&xW=N}KǣIZ'/ﱨy4xլKs(=NͣI>j@gٱXk_?|x,jM`usL{G8568j[mVS1zeᱣ}-wIڋ;k_ <νzF).T?mt++6גUaȔuU2Ü_e>!++s+ylkr,/r7whxlxaKQlm?3mu`8`c$t&zk,++++fqNu@b᷋yCZ>~۷({T,[kk>v:Nk.Eu~Ł2ϋ'lc&pǨ߭-(qqlUӈ-S(w9{C{܅t^raNeT9* xXyXyXyMc`1M{!D@TP+}nx%\ :oVsfטuv |>Q]!ߠBLeCt~edsK>UџDEP_O\8tU:#]շ7(g#Ϊ> >~;j`>y J_՛jFZFNqf!UUo*2ҕn?MNf%^ejINvdТtUzIJ&{RzӞɭt+EM[PA. TuEw_72;^b#)cZ_}hئ52J?zrܝwMo&Q(߬2վ&o0X ({ ZrVFwq,]cGzAJ4R+cUYF+]/xDUDcF|8eTm:O|p,q2ZNϙ3~ިVP/BbE 8fq"444p]UiQ=d#]y]y]y]y]y d0<ׁ(yn-JPe0! `kRs`2گ_gv.j9OuS E9ֱNf""HC1SHr!0*xUc$H:1].r!$K3i_/X׻Sp\~UsA2]8{>w]y2Pso_ϜZtix]y]y]y]y]y]y]y]y]y]y]yx Vy-uotop! 0M]i d0OxBRTVu6h[-&Du ^Us6}ֻ7bG[DwE~i"l #. أGTu]A'^p9y'# GsY&['>`bDW3΄j;0wDWDWDWDWDWDWDWDWDWDWDW`T­IENDB`perfbook_html/img218.png0000644000175000017500000000420411672746160015312 0ustar paulmckpaulmckPNG  IHDRc`=6PLTEb``MJK# hffmkkXUV856C@@wuv.*+ytRNS@fIDATx\Ơ W,TvNǃ1MZcV=ڭ/ |6?o(fb ޢqmOuϩeQ-MyF`PO;ߵZRr]is~l1h)bYp%M\Slo_8txKW~Оtq1 E4[ӪGf$=IU2N  PԽVd#ymxWZlA&)\ Fyg2?{h.pnnI1ݰY!YẢW*WjY'1ur?-\!^22ta]7$D`\|0Z5*Bq]=$RUգ):H=ڷ;X,#(yD$=m]2 q!R"jBMкH˷ƹNc"HNR SFMz>#P4&72Ԕn{݂wD1=Ix9/3ckYĠ A04\߇^g^6~Ca(H2(Shh|@$H q{B h\|:p=&&pwTSmQwӘc8Ә(-bOЛi!Z80#H.m1o*b'Dt2Tn\ճ!#`A$ }(1T4Wih?JeI'O,{-zj/ìT &'Y [K0Sq<lQ0+|ˏ`fD[1޼;ЇO6cB&sm͏.)BEkafom228py}zfcQgbn)Tmsy9tnQPҢNbLbz~**'.}J ;mAqڻ_j }6ӮwLqA]6+¬8q-K  >J:^##LOp`=L9YZZP*l4|#!*xQ DY6wrXH9қ V<3a =Bt:r<'Dp㱰u;T  eQ"rqG~K iXllLiA#aOu+Us{Is.P!k'sr6-*VY6SRg-1j TH!l2̗o|M'9ow}3Kgd69±pS!ؒG}HzZ6BtJT9pQ?<YqُbJV2c1rJ/93>Ub( +^B+{ҌxסǗ1q_7չ7r++X YlGxtFs1YҬq&B;3@SDp!|8YY3Pу_ X (mx|}аhNp2wa՞/ls_TzRh=1#8*mjdU D.4.3 Validation of Preemptible RCU


D.4.3 Validation of Preemptible RCU



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node49.html0000644000175000017500000002273411672746161015576 0ustar paulmckpaulmck 5.4 Linux-Kernel Equivalents to POSIX Operations


5.4 Linux-Kernel Equivalents to POSIX Operations


Table: Mapping from POSIX to Linux-Kernel Primitives
Category POSIX Linux Kernel
Thread Management pthread_t struct task_struct
  pthread_create() kthread_create
  pthread_exit() kthread_should_stop() (rough)
  pthread_join() kthread_stop() (rough)
  poll(NULL, 0, 5) schedule_timeout_interruptible()
POSIX Locking pthread_mutex_t spinlock_t (rough)
    struct mutex
  PTHREAD_MUTEX_INITIALIZER DEFINE_SPINLOCK()
    DEFINE_MUTEX()
  pthread_mutex_lock() spin_lock() (and friends)
    mutex_lock() (and friends)
  pthread_mutex_unlock() spin_unlock() (and friends)
    mutex_unlock()
POSIX Reader-Writer pthread_rwlock_t rwlock_t (rough)
Locking   struct rw_semaphore
  PTHREAD_RWLOCK_INITIALIZER DEFINE_RWLOCK()
    DECLARE_RWSEM()
  pthread_rwlock_rdlock() read_lock() (and friends)
    down_read() (and friends)
  pthread_rwlock_unlock() read_unlock() (and friends)
    up_read()
  thread_rwlock_wrlock() write_lock() (and friends)
    down_write() (and friends)
  pthread_rwlock_unlock() write_unlock() (and friends)
    up_write()
Atomic Operations C Scalar Types atomic_t
    atomic64_t
  __sync_fetch_and_add() atomic_add_return()
    atomic64_add_return()
  __sync_fetch_and_sub() atomic_sub_return()
    atomic64_sub_return()
  __sync_val_compare_and_swap() cmpxchg()
  __sync_lock_test_and_set() xchg() (rough)
  __sync_synchronize() smp_mb()


Unfortunately, threading operations, locking primitives, and atomic operations were in reasonably wide use long before the various standards committees got around to them. As a result, there is considerable variation in how these operations are supported. It is still quite common to find these operations implemented in assembly language, either for historical reasons or to obtain better performance in specialized circumstances. For example, the gcc __sync_ family of primitives all provide memory-ordering semantics, motivating many developers to create their own implementations for situations where the memory ordering semantics are not required.

Therefore, Table [*] on page [*] provides a rough mapping between the POSIX and gcc primitives to those used in the Linux kernel. Exact mappings are not always available, for example, the Linux kernel has a wide variety of locking primitives, while gcc has a number of atomic operations that are not directly available in the Linux kernel. Of course, on the one hand, user-level code does not need the Linux kernel's wide array of locking primitives, while on the other hand, gcc's atomic operations can be emulated reasonably straightforwardly using cmpxchg().

Quick Quiz 5.21: What happened to the Linux-kernel equivalents to fork() and join()? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node153.html0000644000175000017500000000631311672746162015646 0ustar paulmckpaulmck 10.3.3.4 So, What is RCU Really?


10.3.3.4 So, What is RCU Really?

At its core, RCU is nothing more nor less than an API that supports publication and subscription for insertions, waiting for all RCU readers to complete, and maintenance of multiple versions. That said, it is possible to build higher-level constructs on top of RCU, including the reader-writer-locking, reference-counting, and existence-guarantee constructs listed in the companion article. Furthermore, I have no doubt that the Linux community will continue to find interesting new uses for RCU, just as they do for any of a number of synchronization primitives throughout the kernel.

Of course, a more-complete view of RCU would also include all of the things you can do with these APIs.

However, for many people, a complete view of RCU must include sample RCU implementations. The next section therefore presents a series of ``toy'' RCU implementations of increasing complexity and capability.



Paul E. McKenney 2011-12-16
perfbook_html/img54.png0000644000175000017500000001440411672746047015237 0ustar paulmckpaulmckPNG  IHDRKm[PLTEݸ^UhE>wwwodQflVMUUUs g\333wU3FX\2xl/;>T+'"]u{pppfff#,.u<6C#DDD MEft"""d4.D:IM"ktRNS@fIDATx] C۶v[֪֙F2|LD|[W 8w*e,Fy ).? Zqd@>9@v rQAU[wYw:8oe>H)1za,vhܾl $n[4;!+p]VU$u^pva,'UF;Ăid )%Rо@ M/=+ ӓ B6:)C?ebq&N+/5UuTА@bAeyX1y˺A2":FֱіL(%ySyO!;tCUYٿW3v3∋V"cq'²T%7rukVN,+PZ\VO2>ʲ6`͂ se6+Y@U8}GueeMȋf JG+ШH!#T!XʤV Tʲ6K,I*QjQ]8^q5~ m,uH(=4!ԷE_XozO7OoRϲ 076«!+.gm?aO2`ST\frd*#v\m=V>:4W`uq <&0n]B4툈Jo[13>OhRF3 ;#4䆊sVZi@'ARS HURU%δ۞Q =f1O61P# )F6P$YSwZY+ t0逝)h#ČdIF[/P<1s:WyR-E_F90y\z,{lF*[g|+J.l=yIܣ gYu\4\9 \=mmLGYA]V|8?bmV㩺yI96ߔid d~°vdl\ӴXjQ+;&bXRU1߯@[)Py^.j9Ub@ Rd 1ˋkH1>652kkVc>mhs~z:^?]-MMV7u]LU.\GIF97CG}+a@aS'tl^'o-F[t  BW}F1 (s=>~ +~p 2xڹlD.q(bT#!Ti3 ^"IQ ,= yh^  b,eJE\@PP|S%??,0(yIz\_N>JLQm6r$_hYh'Z8Pc66,+Nv'Z♲ wlQ AIBh) @)W"iD'J]߀` J >\"( [|\W "-_5Te25HT\P터`)/\A+c Ftz3& QDKj@ "d9-.&MSbVO;AKƒ2Sa#'yq$AKw-xnBA/[KCfpFf_c:Sf5RЬ0%/u%~1tے5]ImѦkhQޫK*Ց@IT9"@&8 Pz(V=;F'J*H/P]1saڢ@Y*$˷4\\I[Oqx{47 ͳ,g.S<;.(5 olO+hSX hUdmʜeK2)ڥ-2X5BB{5'7?8J9F81V !r r2󨶃. F>xL+BU;8@5dt77^{kNOoUdPG5IC[nNmzQajɛͧxE olО0܉)ݻfSh경Aj ?n!u&0#cHzh &D=v9L rgxc^Ѡ!1Yfe:Y$?ل& 4^wܗ7Jg/n{!G/S"'A\s5uWZ7VpbnEn6 F oXLaFC d)?Ai,L#8}HiHkp an]NE>fć@چѨXxA]I67l5MNR|XjݭV1 k%Ɛ,& s?lJX'& V7Pl=+r3RX@6hu0Ye ⶃUKlvb5&JqTnF#kzR!d.(>,zFٰIPsV)B@P}K~Z %Loa.e,:ZY*+)GA۷m+[4ZH{H5ejL03uL,B3ȳm!tCLSHCô |)Xft}l -vgT&OBSТ+6U!5":>5[x1hk 2c4.ahݫ{I@gK)j|obλgv0z׹ޔ4?;3fw7dd{6|澾`¦{1;u=߇_41&Eo=&Hָ!YΘߨ|yvACm )0q%,'C/[I9*,%la^U`,S_ݖ kL%joC 1UXt) L:xAd11k1]̽1` fzvԘ"[N9nPۉŔHȓ? 2&uk+#1p+∃s3P=rn߭VwSa~GxzcMV~߾My|zttu57t?Os~{w2AK4;?X@yBa'5}) &)`B0LӈH$Sj)ljݑncg_])A!GZԈ"Kׅ90L+jM:"ljβa: As82ʗh4]XMM4"O$y63_L-ɯ:xv/{`Ofg/<0/шok|<5>3ϕA³~? jO E4Uk 5PZ_,,*GQ4= R xm˶y(-W^s]IŸ+::ɴw'm3KgXbQg.#hAU.Yԯ1lQRThQ\F0Ov ۠ ϺIɜ4ɍx6Iy-sZmgRh;8.>OIO% MO!<Q!ArIu)zp<6=PU %M{mg)3v),:nӪM')_> IWIsm&{5h* $  ȷ=ןiZwBYņG]cg?/>'Q7[TW^r~}(jAc&3qeξ~ۈ'.|sAED)x9I{~=sByz=YRë^4wa 1(zϔ'Ef#FY.50r$`[ /6띬uq`9û˓v ۽[']<ڹ3 @ gyp's`עS8_X'# SPY/l0+,JB}hQҦ,"(!r= ;<4a~~u81ZV;e' S#j\ViοEF8a._L<.L~5Zݦ;W]I4ⴿcA}d8:)ߡb  ǏqN$oYQj_7Hq _OkZ59.$;a+N3xxM~+G|yz}| _?L4=^B#ԗa~dNWO7߆UpcW O /q &\_}bs?$yoIO#uIENDB`perfbook_html/img155.png0000644000175000017500000000466711672746107015330 0ustar paulmckpaulmckPNG  IHDR1k39PLTEMJK# b``vstmkkXUV856C@@wuv.*+ܵwtRNS@f ,IDAThr( >حu{3Dގ1{`%1~d7ƙ VbL4 }3Bu "Hjr*ƎӠ&֖Lvop}S`&(?[J`Dc0 6#:>|q,xjV?QUfԩNd(ـ={*pqN )L03=7i~gS++s"-3ci`yYF };ڪ\ZbVΘxQ:Cd[k+)ؾ,uVL &66Etuz9Chm.3J@$s,|+o>mTl~˰l{¡xxPPq| tMDc +&ȓq/ћ,^uv0+:Fr#XHH-e108B! -r7XU@t/$j,SRʬZ"IKEVMoiPxȒ&l6؈b76at<& YNIڮ1a2dLncJ)NV3TAK]Mqݡk^G_ͯ_.iw cYh(zј0H=W&iK6{Yr5Z15+f5>"z_ o&2G3pG~^29)H!ϕ2{6fꁏC-2.k1>gV#F+fxػӃyjIeČFWo0#yd'>+ɤ Tg{ph::TNT!4sx*>ٌ O s`_iE!2CRhsFfcrdÚ~2tqQc)@V3Iuj>eEQI$玚"''ktE3A4/^J|FcqS)4\: Y2| d. BBǜX.Kêr}OiI1}`zWJ{ {  ~(OU.Reix,e0B&HBcl:G\W a XP_oH~彔P[nsa*ӼP.Jd"JϟU (i6t 'M󼐒B%tb298i˹T?h|\ EA^8d%T-<ਖgԆ1P?wAtnmWAl'An3=k{TM{3x  0t.Vh̝`{6*cS|0!Ȟ$" @eYֱF9u?!&иWyO* 5l,T礡XHޙ!ɟX-f+ ,¯/P&DW}6^V/8t$08zIDBdƛ2Ԕ| T6>>XҰeޅÓǺ=KsK+aDBh߁KŅʙMdfzL nM81{ĔnrJD=o~SsA@nգ ^_.lubp<h"4)ipkPAjC1SEa6zX-HRH:"M Q \WGaPf0dD$|T|Tb3=ԇPLwXrߕA-AAI%,mĊ_P?%]tc| "\4qFofCy;KNc Llؼ agb:7o<]=栶#cN4kj_unJz9ۂn=WjӘD^-xZ,vVgDŷBԗo/Ket-E*YW-8SsJ3M{m2ipKJuQ;Jia#KױE,z-M[d0mAwf5_6 Z<(z^s/`T+GmFK% Trx_Qw|xZÿĩ_=*ƛIENDB`perfbook_html/node404.html0000644000175000017500000002413511672746163015650 0ustar paulmckpaulmck D.4.2.1 General Approach


D.4.2.1 General Approach

Figure: Classic vs. Preemptible RCU Callback Processing
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptListsCompare}}

Because this implementation of preemptible RCU does not require memory barriers in rcu_read_lock() and rcu_read_unlock(), a multi-stage grace-period detection algorithm is required. Instead of using a single wait queue of callbacks (which has sufficed for earlier RCU implementations), this implementation uses an array of wait queues, so that RCU callbacks are enqueued on each element of this array in turn. This difference in callback flow is shown in Figure [*] for a preemptible RCU implementation with two waitlist stages per grace period (in contrast, the September 10 2007 patch to -rt [McK07c] uses four waitlist stages).

Given two stages per grace period, any pair of stages forms a full grace period. Similarly, in an implementation with four stages per grace period, any sequence of four stages would form a full grace period.

Figure: Preemptible RCU Counter Flip Operation
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptCounterFlip}}

To determine when a grace-period stage can end, preemptible RCU uses a per-CPU two-element rcu_flipctr array that tracks in-progress RCU read-side critical sections. One element of a given CPU's rcu_flipctr array tracks old RCU read-side critical sections, in other words, critical sections that started before the current grace-period stage. The other element tracks new RCU read-side critical sections, namely those starting during the current grace-period stage. The array elements switch roles at the beginning of each new grace-period stage, as shown in Figure [*].

During the first stage on the left-hand side of the above figure, rcu_flipctr[0] tracks the new RCU read-side critical sections, and is therefore incremented by rcu_read_lock() and decremented by rcu_read_unlock(). Similarly, rcu_flipctr[1] tracks the old RCU read-side critical sections (those that started during earlier stages), and is therefore decremented by rcu_read_unlock() and never incremented at all.

Because each CPU's old rcu_flipctr[1] elements are never incremented, their sum across all CPUs must eventually go to zero, although preemption in the midst of an RCU read-side critical section might cause any individual counter to remain non-zero or even to go negative. For example, suppose that a task calls rcu_read_lock() on one CPU, is preempted, resumes on another CPU, and then calls rcu_read_unlock(). The first CPU's counter will then be +1 and the second CPU's counter will be -1, however, they will still sum to zero. Regardless of possible preemption, when the sum of the old counter elements does go to zero, it is safe to move to the next grace-period stage, as shown on the right-hand side of the above figure.

In this second stage, the elements of each CPU's rcu_flipctr counter array switch roles. The rcu_flipctr[0] counter now tracks the old RCU read-side critical sections, in other words, the ones that started during grace period stage 0. Similarly, the rcu_flipctr[1] counter now tracks the new RCU read-side critical sections that start in grace period stage 1. Therefore, rcu_read_lock() now increments rcu_flipctr[1], while rcu_read_unlock() still might decrement either counter. Specifically, if the matching rcu_read_lock() executed during grace-period stage 0 (the old stage at this point), then rcu_read_unlock() must decrement rcu_flipctr[0], but if the matching rcu_read_lock() executed during grace-period stage 1 (the new stage), then rcu_read_unlock() must instead decrement rcu_flipctr[1].

The critical point is that all rcu_flipctr elements tracking the old RCU read-side critical sections must strictly decrease. Therefore, once the sum of these old counters reaches zero, it cannot change.

The rcu_read_lock() primitive uses the bottom bit of the current grace-period counter (rcu_ctrlblk.completed & 0x1) to index the rcu_flipctr array, and records this index in the task structure. The matching rcu_read_unlock() uses this recorded value to ensure that it decrements a counter corresponding to the one that the matching rcu_read_lock() incremented. Of course, if the RCU read-side critical section has been preempted, rcu_read_lock() might be decrementing the counter belonging to a different CPU than the one whose counter was incremented by the matching rcu_read_lock().

Each CPU also maintains rcu_flip_flag and rcu_mb_flag per-CPU variables. The rcu_flip_flag variable is used to synchronize the start of each grace-period stage: once a given CPU has responded to its rcu_flip_flag, it must refrain from incrementing the rcu_flip array element that now corresponds to the old grace-period stage. The CPU that advances the counter (rcu_ctrlblk.completed) changes the value of each CPU's rcu_mb_flag to rcu_flipped, but a given rcu_mb_flag may be changed back to rcu_flip_seen only by the corresponding CPU.

The rcu_mb_flag variable is used to force each CPU to execute a memory barrier at the end of each grace-period stage. These memory barriers are required to ensure that memory accesses from RCU read-side critical sections ending in a given grace-period stage are ordered before the end of that stage. This approach gains the benefits memory barriers at the beginning and end of each RCU read-side critical section without having to actually execute all those costly barriers. The rcu_mb_flag is set to rcu_mb_needed by the CPU that detects that the sum of the old counters is zero, but a given rcu_mb_flag is changed back to rcu_mb_done only by the corresponding CPU, and even then only after executing a memory barrier.

Paul E. McKenney 2011-12-16
perfbook_html/node447.html0000644000175000017500000001205211672746163015652 0ustar paulmckpaulmck E.7.2.4 Interrupts


E.7.2.4 Interrupts

There are a couple of ways to model interrupts in Promela:

  1. using C-preprocessor tricks to insert the interrupt handler between each and every statement of the dynticks_nohz() process, or
  2. modeling the interrupt handler with a separate process.

A bit of thought indicated that the second approach would have a smaller state space, though it requires that the interrupt handler somehow run atomically with respect to the dynticks_nohz() process, but not with respect to the grace_period() process.

Fortunately, it turns out that Promela permits you to branch out of atomic statements. This trick allows us to have the interrupt handler set a flag, and recode dynticks_nohz() to atomically check this flag and execute only when the flag is not set. This can be accomplished with a C-preprocessor macro that takes a label and a Promela statement as follows:

  1 #define EXECUTE_MAINLINE(label, stmt) \
  2 label: skip; \
  3     atomic { \
  4       if \
  5       :: in_dyntick_irq -> goto label; \
  6       :: else -> stmt; \
  7       fi; \
  8     } \

One might use this macro as follows:



EXECUTE_MAINLINE(stmt1,
                 tmp = dynticks_progress_counter)


Line 2 of the macro creates the specified statement label. Lines 3-8 are an atomic block that tests the in_dyntick_irq variable, and if this variable is set (indicating that the interrupt handler is active), branches out of the atomic block back to the label. Otherwise, line 6 executes the specified statement. The overall effect is that mainline execution stalls any time an interrupt is active, as required.

Paul E. McKenney 2011-12-16
perfbook_html/node346.html0000644000175000017500000002620411672746163015654 0ustar paulmckpaulmck D.2.4 Towards a More Scalable RCU Implementation


D.2.4 Towards a More Scalable RCU Implementation

Figure: Hierarchical RCU State
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCU}}

One effective way to reduce lock contention is to create a hierarchy, as shown in Figure [*]. Here, each of the four rcu_node structures has its own lock, so that only CPUs 0 and 1 will acquire the lower left rcu_node's lock, only CPUs 2 and 3 will acquire the lower middle rcu_node's lock, and only CPUs 4 and 5 will acquire the lower right rcu_node's lock. During any given grace period, only one of the CPUs accessing each of the lower rcu_node structures will access the upper rcu_node, namely, the last of each pair of CPUs to record a quiescent state for the corresponding grace period.

This results in a significant reduction in lock contention: instead of six CPUs contending for a single lock each grace period, we have only three for the upper rcu_node's lock (a reduction of 50%) and only two for each of the lower rcu_nodes' locks (a reduction of 67%).

Figure: Mapping rcu_node Hierarchy Into Array
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeMapping}}

The tree of rcu_node structures is embedded into a linear array in the rcu_state structure, with the root of the tree in element zero, as shown in Figure [*] for an eight-CPU system with a three-level hierarchy. Each arrow links a given rcu_node structure to its parent, representing the rcu_node's ->parent field. Each rcu_node indicates the range of CPUs covered, so that the root node covers all of the CPUs, each node in the second level covers half of the CPUs, and each node in the leaf level covering a pair of CPUs. This array is allocated statically at compile time based on the value of NR_CPUS.

Figure: Hierarchical RCU Grace Period
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCUGP}}

The sequence of diagrams in Figure [*] shows how grace periods are detected. In the first figure, no CPU has yet passed through a quiescent state, as indicated by the red rectangles. Suppose that all six CPUs simultaneously try to tell RCU that they have passed through a quiescent state. Only one of each pair will be able to acquire the lock on the corresponding lower rcu_node, and so the second figure shows the result if the lucky CPUs are numbers 0, 3, and 5, as indicated by the green rectangles. Once these lucky CPUs have finished, then the other CPUs will acquire the lock, as shown in the third figure. Each of these CPUs will see that they are the last in their group, and therefore all three will attempt to move to the upper rcu_node. Only one at a time can acquire the upper rcu_node structure's lock, and the fourth, fifth, and sixth figures show the sequence of states assuming that CPU 1, CPU 2, and CPU 4 acquire the lock in that order. The sixth and final figure in the group shows that all CPUs have passed through a quiescent state, so that the grace period has ended.

Figure: Hierarchical RCU State 4,096 CPUs
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCU}}

In the above sequence, there were never more than three CPUs contending for any one lock, in happy contrast to Classic RCU, where all six CPUs might contend. However, even more dramatic reductions in lock contention are possible with larger numbers of CPUs. Consider a hierarchy of rcu_node structures, with 64 lower structures and 64*64=4,096 CPUs, as shown in Figure [*].

Here each of the lower rcu_node structures' locks are acquired by 64 CPUs, a 64-times reduction from the 4,096 CPUs that would acquire Classic RCU's single global lock. Similarly, during a given grace period, only one CPU from each of the lower rcu_node structures will acquire the upper rcu_node structure's lock, which is again a 64x reduction from the contention level that would be experienced by Classic RCU running on a 4,096-CPU system.

Quick Quiz D.5: Wait a minute! With all those new locks, how do you avoid deadlock? End Quick Quiz

Quick Quiz D.6: Why stop at a 64-times reduction? Why not go for a few orders of magnitude instead? End Quick Quiz

Quick Quiz D.7: But I don't care about McKenney's lame excuses in the answer to Quick Quiz 2!!! I want to get the number of CPUs contending on a single lock down to something reasonable, like sixteen or so!!! End Quick Quiz

Figure: Hierarchical RCU State With BH
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBH}}

The implementation maintains some per-CPU data, such as lists of RCU callbacks, organized into rcu_data structures. In addition, rcu (as in call_rcu()) and rcu_bh (as in call_rcu_bh()) each maintain their own hierarchy, as shown in Figure [*].

Quick Quiz D.8: OK, so what is the story with the colors? End Quick Quiz

The next section discusses energy conservation.

Paul E. McKenney 2011-12-16
perfbook_html/node468.html0000644000175000017500000002473211672746163015665 0ustar paulmckpaulmck F.8 Chapter 

F.8 Chapter [*]

Quick Quiz [*].1: 
Why on earth did we need that global lock in the first place?
 
Answer:
A given thread's __thread variables vanish when that thread exits. It is therefore necessary to synchronize any operation that accesses other threads' __thread variables with thread exit. Without such synchronization, accesses to __thread variable of a just-exited thread will result in segmentation faults.

Quick Quiz [*].2: 
Just what is the accuracy of read_count(), anyway?
 
Answer:
Refer to Figure [*] on Page [*]. Clearly, if there are no concurrent invocations of inc_count(), read_count() will return an exact result. However, if there are concurrent invocations of inc_count(), then the sum is in fact changing as read_count() performs its summation. That said, because thread creation and exit are excluded by final_mutex, the pointers in counterp remain constant.

Let's imagine a mythical machine that is able to take an instantaneous snapshot of its memory. Suppose that this machine takes such a snapshot at the beginning of read_count()'s execution, and another snapshot at the end of read_count()'s execution. Then read_count() will access each thread's counter at some time between these two snapshots, and will therefore obtain a result that is bounded by those of the two snapshots, inclusive. The overall sum will therefore be bounded by the pair of sums that would have been obtained from each of the two snapshots (again, inclusive).

The expected error is therefore half of the difference between the pair of sums that would have been obtained from each of the two snapshots, that is to say, half of the execution time of read_count() multiplied by the number of expected calls to inc_count() per unit time.

Or, for those who prefer equations:

\begin{displaymath}
\epsilon = \frac{T_r R_i}{2}
\end{displaymath} (F.1)

where $\epsilon$ is the expected error in read_count()'s return value, $T_r$ is the time that read_count() takes to execute, and $R_i$ is the rate of inc_count() calls per unit time. (And of course, $T_r$ and $R_i$ should use the same units of time: microseconds and calls per microsecond, seconds and calls per second, or whatever, as long as they are the same units.)

Quick Quiz [*].3: 
Hey!!! Line 45 of Figure [*] modifies a value in a pre-existing countarray structure! Didn't you say that this structure, once made available to read_count(), remained constant???
 
Answer:
Indeed I did say that. And it would be possible to make count_register_thread() allocate a new structure, much as count_unregister_thread() currently does.

But this is unnecessary. Recall the derivation of the error bounds of read_count() that was based on the snapshots of memory. Because new threads start with initial counter values of zero, the derivation holds even if we add a new thread partway through read_count()'s execution. So, interestingly enough, when adding a new thread, this implementation gets the effect of allocating a new structure, but without actually having to do the allocation.

Quick Quiz [*].4: 
Wow! Figure [*] contains 69 lines of code, compared to only 42 in Figure [*]. Is this extra complexity really worth it?
 
Answer:
This of course needs to be decided on a case-by-case basis. If you need an implementation of read_count() that scales linearly, then the lock-based implementation shown in Figure [*] simply will not work for you. On the other hand, if calls to count_read() are sufficiently rare, then the lock-based version is simpler and might thus be better, although much of the size difference is due to the structure definition, memory allocation, and NULL return checking.

Of course, a better question is "why doesn't the language implement cross-thread access to __thread variables?" After all, such an implementation would make both the locking and the use of RCU unnecessary. This would in turn enable an implementation that was even simpler than the one shown in Figure [*], but with all the scalability and performance benefits of the implementation shown in Figure [*]!

Paul E. McKenney 2011-12-16
perfbook_html/node14.html0000644000175000017500000001614611672746161015566 0ustar paulmckpaulmck 3.4 What Makes Parallel Programming Hard?


3.4 What Makes Parallel Programming Hard?

It is important to note that the difficulty of parallel programming is as much a human-factors issue as it is a set of technical properties of the parallel programming problem. This is the case because we need human beings to be able to tell parallel systems what to do, and this two-way communication between human and computer is as much a function of the human as it is of the computer. Therefore, appeals to abstractions or to mathematical analyses will necessarily be of severely limited utility.

In the Industrial Revolution, the interface between human and machine was evaluated by human-factor studies, then called time-and-motion studies. Although there have been a few human-factor studies examining parallel programming [ENS05,ES05,HCS+05,SS94], these studies have been extremely narrowly focused, and hence unable to demonstrate any general results. Furthermore, given that the normal range of programmer productivity spans more than an order of magnitude, it is unrealistic to expect an affordable study to be capable of detecting (say) a 10% difference in productivity. Although the multiple-order-of-magnitude differences that such studies can reliably detect are extremely valuable, the most impressive improvements tend to be based on a long series of 10% improvements.

We must therefore take a different approach.

Figure: Categories of Tasks Required of Parallel Programmers
\resizebox{3in}{!}{\includegraphics{intro/FourTaskCategories}}

One such approach is to carefully consider the tasks that parallel programmers must undertake that are not required of sequential programmers. We can then evaluate how well a given programming language or environment assists the developer with these tasks. These tasks fall into the four categories shown in Figure [*], each of which is covered in the following sections.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node376.html0000644000175000017500000001312211672746163015652 0ustar paulmckpaulmck D.3.3.1 rcu_init_levelspread()


D.3.3.1 rcu_init_levelspread()

Figure: rcu_init_levelspread() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1  ...

Figure [*] shows the code for the rcu_init_levelspread() function, which controls the fanout, or the number of children per parent, in the rcu_node hierarchy. There are two versions of this function, one shown on lines 2-9 that enforces the exact fanout (specified by CONFIG_RCU_FANOUT), and the other on lines 11-25 that determines the number of child nodes based indirectly on the specified fanout, but then balances the tree. The CONFIG_RCU_FANOUT_EXACT kernel parameter selects which version to use for a given kernel build.

The exact-fanout version simply assigns all of the elements of the specified rcu_state structure's ->levelspread array to the CONFIG_RCU_FANOUT kernel parameter, as shown by the loop on lines 7 and 8.

The hierarchy-balancing version on lines 11-24 uses a pair of local variables ccur and cprv which track the number of rcu_node structures on the current and previous levels, respectively. This function works from the leaf level up the hierarchy, so cprv is initialized by line 18 to NR_CPUS, which corresponds to the number of rcu_data structures that feed into the leaf level. Lines 19-23 iterate from the leaf to the root. Within this loop, line 20 picking up the number of rcu_node structures for the current level into ccur. Line 21 then rounds up the ratio of the number of nodes on the previous (lower) level (be they rcu_node or rcu_data) to the number of rcu_node structures on the current level, placing the result in the specified rcu_state structure's ->levelspread array. Line 22 then sets up for the next pass through the loop.

After a call to either function, the ->levelspread array contains the number of children for each level of the rcu_node hierarchy.

Paul E. McKenney 2011-12-16
perfbook_html/node192.html0000644000175000017500000001743711672746162015662 0ustar paulmckpaulmck 14.2.3 Variables Can Have More Than One Value


14.2.3 Variables Can Have More Than One Value

It is natural to think of a variable as taking on a well-defined sequence of values in a well-defined, global order. Unfortunately, it is time to say ``goodbye'' to this sort of comforting fiction.

To see this, consider the program fragment shown in Figure [*]. This code fragment is executed in parallel by several CPUs. Line 1 sets a shared variable to the current CPU's ID, line 2 initializes several variables from a gettb() function that delivers the value of fine-grained hardware ``timebase'' counter that is synchronized among all CPUs (not available from all CPU architectures, unfortunately!), and the loop from lines 3-8 records the length of time that the variable retains the value that this CPU assigned to it. Of course, one of the CPUs will ``win'', and would thus never exit the loop if not for the check on lines 7-8.

Quick Quiz 14.3: What assumption is the code fragment in Figure [*] making that might not be valid on real hardware? End Quick Quiz

Figure: Software Logic Analyzer
\begin{figure}{ \centering
\begin{verbatim}1 state.variable = mycpu;
2 lastt...
...();
6 if (lasttb - firsttb > 1000)
7 break;
8 }\end{verbatim}
}\end{figure}

Upon exit from the loop, firsttb will hold a timestamp taken shortly after the assignment and lasttb will hold a timestamp taken before the last sampling of the shared variable that still retained the assigned value, or a value equal to firsttb if the shared variable had changed before entry into the loop. This allows us to plot each CPU's view of the value of state.variable over a 532-nanosecond time period, as shown in Figure [*]. This data was collected on 1.5GHz POWER5 system with 8 cores, each containing a pair of hardware threads. CPUs 1, 2, 3, and 4 recorded the values, while CPU 0 controlled the test. The timebase counter period was about 5.32ns, sufficiently fine-grained to allow observations of intermediate cache states.

Figure: A Variable With Multiple Simultaneous Values
\resizebox{3in}{!}{\includegraphics{advsync/MoreThanOneValue}}

Each horizontal bar represents the observations of a given CPU over time, with the black regions to the left indicating the time before the corresponding CPU's first measurement. During the first 5ns, only CPU 3 has an opinion about the value of the variable. During the next 10ns, CPUs 2 and 3 disagree on the value of the variable, but thereafter agree that the value is ``2'', which is in fact the final agreed-upon value. However, CPU 1 believes that the value is ``1'' for almost 300ns, and CPU 4 believes that the value is ``4'' for almost 500ns.

Quick Quiz 14.4: How could CPUs possibly have different views of the value of a single variable at the same time? End Quick Quiz

Quick Quiz 14.5: Why do CPUs 2 and 3 come to agreement so quickly, when it takes so long for CPUs 1 and 4 to come to the party? End Quick Quiz

We have entered a regime where we must bade a fond farewell to comfortable intuitions about values of variables and the passage of time. This is the regime where memory barriers are needed.

Paul E. McKenney 2011-12-16
perfbook_html/node292.html0000644000175000017500000000630211672746162015650 0ustar paulmckpaulmck B.5 Performance


B.5 Performance

It is instructive to compare the performance of the locked increment shown in Section [*] to that of per-thread variables (see Section [*]), as well as to conventional increment (as in ``counter++'').

@@@ need parable on cache thrashing.

@@@ more here using performance results from a modest multiprocessor.

@@@ Also work in something about critical-section size? Or put later?

The difference in performance is quite large, to put it mildly. The purpose of this book is to help you write SMP programs, perhaps with realtime response, while avoiding such performance pitfalls. The next section starts this process by describing some of the reasons for this performance shortfall.



Paul E. McKenney 2011-12-16
perfbook_html/node78.html0000644000175000017500000001317311672746162015576 0ustar paulmckpaulmck 7.1.2.2 Compound Double-Ended Queue


7.1.2.2 Compound Double-Ended Queue

Figure: Compound Double-Ended Queue
\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqpair}}

One way of forcing non-overlapping lock domains is shown in Figure [*]. Two separate double-ended queues are run in tandem, each protected by its own lock. This means that elements must occasionally be shuttled from one of the double-ended queues to the other, in which case both locks must be held. A simple lock hierarchy may be used to avoid deadlock, for example, always acquiring the left-hand lock before acquiring the right-hand lock. This will be much simpler than applying two locks to the same double-ended queue, as we can unconditionally left-enqueue elements to the left-hand queue and right-enqueue elements to the right-hand queue. The main complication arises when dequeuing from an empty queue, in which case it is necessary to:

  1. If holding the right-hand lock, release it and acquire the left-hand lock, rechecking that the queue is still empty.
  2. Acquire the right-hand lock.
  3. Rebalance the elements across the two queues.
  4. Remove the required element.
  5. Release both locks.

Quick Quiz 7.3: In this compound double-ended queue implementation, what should be done if the queue has become non-empty while releasing and reacquiring the lock? End Quick Quiz

The rebalancing operation might well shuttle a given element back and forth between the two queues, wasting time and possibly requiring workload-dependent heuristics to obtain optimal performance. Although this might well be the best approach in some cases, it is interesting to try for an algorithm with greater determinism.

Paul E. McKenney 2011-12-16
perfbook_html/node434.html0000644000175000017500000001051111672746163015644 0ustar paulmckpaulmck E.6.2 How Many Readers and Updaters Are Really Needed?


E.6.2 How Many Readers and Updaters Are Really Needed?

One approach is to look carefully at the Promela code for qrcu_updater() and notice that the only global state change is happening under the lock. Therefore, only one updater at a time can possibly be modifying state visible to either readers or other updaters. This means that any sequences of state changes can be carried out serially by a single updater due to the fact that Promela does a full state-space search. Therefore, at most two updaters are required: one to change state and a second to become confused.

The situation with the readers is less clear-cut, as each reader does only a single read-side critical section then terminates. It is possible to argue that the useful number of readers is limited, due to the fact that the fastpath must see at most a zero and a one in the counters. This is a fruitful avenue of investigation, in fact, it leads to the full proof of correctness described in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/img243.png0000644000175000017500000002376511672746012015321 0ustar paulmckpaulmckPNG  IHDR,`A>QPLTEb``\ZZMJKPMM# hffmkkXUV856C@@wuv.*+pooa_`|zzrpptRNS@f IDATx} מK?@+5-_hYp&fdzOq ȴEQF%> =2%BESŸQEEP(E."DmcuaoJ5+jjl*X?k_tPpxg_6Ϣ\Ra(j^Ϯ7]%4nj7j3}=PWY alhw&@M#|Pa%hm[u6skrFrF1`q <}9q0e$h)akW(Ɲ<Z,LFhM8Yٿxlmc``Tg|dr]Epܰ&(+nt-V}:qk/|օe,ޭ:u& ^x,A cI%ݢ]#Wv2 qeH7ofF {q|*55dI_+d,޺YP`3c)|D]ǻ7{u<[Ji=s <Җ|Z X6aH:GyBr^h}$ʕoA^mL$QƸ,:k8TKj<@ N@MLDVr.vq9EFU@U1E8ness$}W)lf޻MTzsM#w`Gcc 'J zPS])F{SqY|[[Vs5To!e=m*QŲަ{jU_2z| q~U"ݞǖGK_Hȇ1ȏ_X*AK,ڛD 灷է#LI'x˙8gcY';moEz Jq3w!q OG]cΓXi {I.T۷ׄШM\$v96L5 -U%woAd9Ru{{'!>D-zNlC[n0r©RN8='y= ?=v=)*u#AXsu+J( Ur8M>J݃50EbWWB0[q.$_,9fP 9-XqPUYr[uv@u0 YuVB#x9/sK8ZZPDZ-į÷]bEw2r?5dku:qzsM5 n2~AV?#}z B}U:cqjZL8Q;D2(zMNq¹ZYMZ2Wd BEjgCwqbCcMnȮg,X+vkezojbx&bU}cUl_ XcDՉd><dLa釶S-xbV+-g=Cɏ!N*f&9@MsS񚪅eTg^'ԮdpS8xV׉4:ŊU(,Aq\K.aB@Z-{ZrVB 5 f-R[ ~KaC*i48IECUl4De~G~Vc!L||I2Tt7[A&4$q N!c˚<6؃gќxS3vPPjv0ϕ-m=\n |Z[TuE ˞Qj_LF1 ={i l5Xtҽj0FC4c+fpmwEyse66go=f?@Q\*ۮgIcΣcQn`kmW骍Lz%w&/UFJ+<į64 |ژ 2̼GGW]\|7ClhRCOOy x5}R31o#m=#/z5@j ?/ ^1PM7*~$,JtV/XEGTd*hQ!@_(> iű!;: Pmi'?XTSh8AE'glKXo4%㖸jz /AA6:*l:;`!3|Tf,*;_%D+fK跐o  (;+%I-2^dx//GCfK -J"dZ|J_H- `XGg~3vbʠk;qL]%ӕ{csFWxX,t%'I,RW^ЕQ^-Du$"Yo-jU_ϵf_!dE&! QS|R4*?.UT&dl0ש '}j>$nvϕ_I8d^eCRH;p9e{'PnꑌL$&$ vT\WDZ$8&GRZdƦpEP ՆdBn!}bΌZdyR͞EZ߰|RJ vDA}+N4Fh U1d&57G-(qAPH0T5hRHлx m\#z螖53'oUI:YZc%nbV-0ʼ}\3_к>C>ɰa_JPQR\B8:J`Y#%]/$p9f[}YhH[:B撬Plsp bl@}4[SLBCe9nƧ6 t 3}ɤC9'!8r@s)0s JF?L7&;ߑ!dUʲq.KPjԉ/P-bP:0Nßa4%Cjaj3Ygn!?tF:4*}uC23!Waո>?)3Y".gg&ٮS+NIdQcG<ܠ+lZ)O=(79 /%a{w-jDuD=LGE&sr\noՐxQEGw>< 6iW8WZdm[V&aa&#Eễbu?MIy8Yv4&]1*`װؼ)9dskm 3s]RMɠDkUֽCts{hSܥj 1}m-r0]2gF'|v۠+Iob~-r>#Zn?D4 !Du>D Z˲rbStX0֢jHȸS_LZ5)v-YO*dEqco]uٰuF1ecż;~52"d",|^aΠ'%S%yփ2ޣW984+k'Z:/#RkeP)x(3.aǰ !r6寁ȳ7ʹTcn'qc7z/$z<l!WSMK֋ş7[ q*FR-sU_$H63 "[_L &K1;W@6[̥du.~w|9(N\#|lIv X:uڬ}b(N:hCnm+άUn45Fռɀ jёە'lU`M~ cӍ®zR 6< -f0D^`:Dgʷ)-~d,V37Ӝ[D)*9I]"s Rr;!$AOyA #+OE%=^Kt^zR2az4ٕyL1오Ug)magf]k[/%Yb\'Fab#Y,S2Q)s[vv~9RE1~Y;l6ߨ[!aa@Yy:_O^Z+.T6PSKT+v}3qn=? mDj+lq=xK"T.~ 2dgyxd5YƉ7S\JatŸ&-ftMb1Yu|XndjxTbUJi&q#0 fz"Sqj܁v)V)DjB'~{J4RC>[u#Jp:RgqYuN@R(^O-^D{_Hs|JXIC-L(-)|N7c7mAaEWx!yęs6il :Ϸ$&sl,3Ԋ qO߈3Qd9dC|,¸MENS988$3+if̓ ~H-Yy2֨sy4Gz&!:vjN3Q8bbE^~H}s̱#Luwԇ{G*"7N/9 ,8.e9;0m0hsԚ: -EXD"ØGxO%c竦JV#DYҳx0[9si|2 ~s"fl>K4[m6UA%Ic**mRl,˔qx By8A͆jCH3u֠<6E`X e0f"3( d>V%K0ͭز*QRՊ3]]T bcf굴]\ [CTqti% *:+ 8Ne`|)WͰ^2cc4MruiqX+@ i[h>EZ [UhA t^bhV;=T|r/N⦃xfEx&Qt"ܙ g,eNseZuƊg ߘ(C5V_˔c%S驳o&Ӌ{8Sz#4<+/6maHkH*cJpx 3{ۇ}Bit:5w<o7QQiރǚn<&)S(t1v5ԣT斤OKY ǒ/ljdFV)A씹p.F hGvn-#tcT:F8~#tUMt [;jq?j<(EӚ|@޺11a+0az`AU'f4+_XEghr o'QSč`5Q_TGն۠S.@DNCh7Vo@oT9KRk7Ԭo[Hұh,+zP%lR(vI?v16Kx9tx- ^}6O7T?m'`_r JK*ALzC}[6D!~cmy+g!ܖ w*o,9fH*b WSL;kC=m16Odns_t%-QbѼ&>d ]+OZ9 Bo[>k(Gf q+Ӱ 1˗1rLLWQ©6\{OG<עo5+;/Uj;@ o?kL7n*U\W!(oB>ӬfR Ob"Eu}Z.L/KzC+c %ƎsNTqid#kʻkֲS7Tu]4PgXѸj 2֍7~f~% ޳x|tˢTQ]*wȪ r6IDrlɠ9ZzQ$p1$dJ/ ɖJv=Ej*F{Il6FIDAT%K -&K$I=^-z7~ $7rBY ѵЙ֍rtdFz y7n|f9Xx7@%+d{y7S׳=b Ee}u~O{) Az5֘+_( Y)d3i, Bju @#돹;ds 5LmLgb~>٠Ws`pRdѥlƔ"S^lf(tT\+k`&ajNm!Jʋ'+P,̾P7݁;o{+?I|`Hi7e{x ujeƍo旼H<1 L,tDFjvɋ:{,ɚ|,3?eӈDh(;NDvjrioSll, 4\\|SsF b3,qVEɡ,o {6)Z./2o8?+&@#o֔1x+, 3$(:O3j]c~ÚdbGcVKY**J=BQSr$NQ6t i3olQ!NY/`-$6 w5KXƪƊ'GScg7VAgL9i,ÜMr-"WĐÚN _@ϲ`=a_PEh|LW) s klkQR&$o1٘$r $;֒Div>8Aрߧ/3r~#_:H]91rF"c'_lYkj"W ^7|/SCR.p8^2zN/CTm ۸؍ 0AC*\QR4ua 𘵠jFa\]*$hِ١sŧ!2KE.$h`z9C:m 4(Ob1PH6 D6|s.]+j<%"' ' *N9T]Qd{HC&ڧcl( o OL<kQ ¥poݓ*4ݥxFJAjCnFGz Y7n۸IV+;|W%k?#,-gF`q_WIvM2J5se.>;(xUDbQmA*əɸj8#KzlFn0^ڸsm{9ݸFy^Jy# lw91ω-Q չǤޮ"\P(?l~VgjTm cY-x{줧 1x#`Bcb{ŰzVΐ"\XO~Vg5$6!tɢqd=S(gTXwsޮRoh_r~1/ mş$mo\V6N}O܄A}֖coY"eadr=zm7Ϟ`)_-+ڿMoM ܝE6`fxʾooZw67a`,w '.P&}o zXLۅǤϫI~?+è!~'gIk dZQ%MpLzK9ģh]ya |42+{|'C9Ģccےb6 KB=%;j=We5ԙm @ KGrV2@j[uݨ׬E+-ȑIENDB`perfbook_html/img134.png0000644000175000017500000001507611672746103015315 0ustar paulmckpaulmckPNG  IHDRڝ YEPLTE^\\URSMJKwvv# b``ommmkkXUV856_\\C@@wuv.*+xǞtRNS@fIDATx]³ fC7eXRGPPxVA (BŘ\*RbJ ks K2^O ;}B}؝^J0S*L+x5GBp'n+=fPf@9~Vþi=[φfSSK=.]5j''@e/r6grX`Q`ot YhmhqYu 4xCO0 f~^9/OM3;{~y'krBx|Й[+\tƢd" X*f x{V _eX{?{5JBE7=״yèhɜ~~Mv)v;){ >%UT)^mb>vL&!?r7Lб @|@mĊ>, }ú{K P;ȇo8VT+ =9$?󆢭gE:-J-W H؎QcOE?{<_HkAp EU# 2.X/ 2]-JXѐ#qoPz=E$ =TK B nQhw *LKRn:E6Hz3:a+y_Le2 ^J^,JءzZXgzC\+/nfLZ`yâ02tF@-1$>=/ IݯܣRvR dXK\2Zh T2Y[͊DMJRXަcQQN+H`n*pKM=; V0@/n%o$a6 MN'.l G5q6i\InIKP Ojp|F.tKbQ@΄.`6T-ÍSJR+~`MhZ sxXp(ROd`jqVME~=Em)q9ϸ]A"Vx(|"^PMW oa> L p kqKUCF3l"ܢxVa 8 R͌δzWv^4Ewl. |[]t?::@%Ib[vɦ5s2C̐}50)FI2!a ngT+>FZVd-_QԠI .SSG)4fl'FIZ[1;$NlS,AՙɃNᖞY d05=xhzInaxni JR Ktohx9Tr`eD7h.̨Eſ1׼!w…N],p8FTo[z\%CKM{s{BU@uqY~X1-u/J6Łcss}dQm*up:`YvnlɯefꃟL)0qw]kU= z:̒-zUƫ6&DD3v3͉J ٬55ByZB3^/كbPkЕw] lC%E)mn0W@+ G`Zޢy> BMycb9ݔ1 >K#H˪׍ӿCjĶo 7f,?_0&zDg@ѓBߘV[C/1)%@(K -[TޘH ~bfw Hݹ'TQLujo[kii} Ө: C\]Ӑw{ht0H~A]~LxF .`vPEb&~-Ut=fc^kQIyUT{A{u0){=ŞUςf[]sՆ˫i\ຩq(dhXJHau90(GxHjAR 7tMswiB2>#!!@Cn\CCꡮrS?"ꞑĄ>N T,]݂ fp :i-ՈFۄ-i-՗몠K]8/C]ћ>/[$Q -(Zӥ3Fwn8[2Er:y^p*S%7'J#F5Im P*L=ud@uU_0F?TId'KΠUWPsj,${sѥq=fguOE=+aq܄-N{C5XuDH̦jsQz^R,g *2P isF_2z3NE4DIdP5KU:|XS[& TbLhYɸ1?=F#|>-7 p\k1,;T/mSg~u`ftqB@΋H;bi^,CuXYu֡mN|u(}Evǡ-dsG5tIoG ~[8 5e%Y{Ur\)@lΧ5PÈcNBA_A_#>n ȁX?0O\\(R%oipH4<ڕvOۃ?nx.["V:=M< $aZͺR $fg ;TچVZ^ns)W}D"VWQ(}m]OCy CXo+waj/+[sq%`Hτ(dނC)|l ŧʫ`ww^RIm@x` VF,_K/ne7q$AcQG۹ qX&nJuV3wV޼ƬzN@n0 l7x{<@bt+FuRG 7=ޟ_4 ({!P&_+lQf蹿,j "[$Uí^Y ,Mӂ8-0w"ؙPECrqq(LŅ2U9 wFilA@G'Ag>[HэGYS}TӜzל&!FuTU@6Ԑ9<4OsC8rRovR;0n5"9Œ5~MTg)멦"΄AioQf'LՇߝ'eᦔw2p"cCjT\$Z3 . (QfC zwWΎQ#Wtqӭܴ;@6xkbjZJJq&$%io+MmX/,@VnX/a\!xB`q*m5 E^X̃o֑}و&$c-ؕV/֯:yIV:g9{mW*NuHR}4 ciNq6BMq51܌&'[݃}Co k4aŵ ō6&>|4$ߩm$7rm.J3zGLqn# =TpO-=H» ӳ ?dDSFZ+Xa8> nuHs/4 ?hD_Pa%|'~&js-xMx nLՉ TM&>` ˏ*}ͩ)'P4rΓ 7TY( T=(qd 8>'Oܜ .;@u r{bN)Re=T=^ K?TKdߒ6AꤏKBȍ, zt{V^ny}얎^lb %%W )FYR-oIZI-e7jH޶0*1I'9nc6+[lFtBn6 ."Wn~i͘:~9^nٙC4Uې FUR5t 8pj ^Zfôf62C#k.J)+0ּV5CnSLQ~`e:z,^K3Wٿ$Uګ1"BaaQӚBzto'GM#+[1{ :硥#oy $."p $~=UxvfԠq>px~f Yۙ}_7u.pY=|̺2G DW4F[7xbx* y 3 k:s^?0@8T JP3i9.4mcw~'`zDxMg62{9 b6>?샿xAvg:xRVn+ ZK>xn * 9 qcY9:ϼL5%HՓtK3΍sũʪ#Rsn/)C6c,XˁgL_3L@gYLg'Ψt _ :*«1#Led  L?,XЃF<E:~NTƪP`ڲJ;6 N@uR3:c^l>X>pWӝlPIERy!HW\w4'ؒď{Ŷ+g5<(Fx]x }uWa!PݾqAƇ NDkS+5q !1K7 Cq+F.|}<z@CwB#[]Dn'ٕ0P 'HWpEHX$En>$GN^ByW x"!?uw խI]i.9yꄔ\| Nye( t׃~ +ݎ[PyyΊN|3u%zx"9İe\uD^^kRkDv|! +N*EfdB,ϠΘ+b1pc Fo;!4N`B*d)Ku x}Ϡtf>N}ѐjw| 'DX":ȍcY:b~BĎ5ZuȖ 2bw>{ 3xB9+lF=tYD-J| #>F90c[3O1nIR)\Pǘ:g61NXȕg[x3ØmW)#\ ՜R)]֍ ^?[S2O1kwF73r\ƧK0E>j{ɼ~1$w D]f)f5`Ylppl:^cNXwF́<z}z;2`y'sm<5~C_ȃ>ᇿ_tJ$d0ɼ.27xxk== 8s@>>H6K&3Gx R5&Sp.BQOFk2kɈ%^ 4. Hardware and its Habits


4. Hardware and its Habits

Most people have an intuitive understanding that passing messages between systems is considerably more expensive than performing simple calculations within the confines of a single system. However, it is not always so clear that communicating among threads within the confines of a single shared-memory system can also be quite expensive. This chapter therefore looks the cost of synchronization and communication within a shared-memory system. This chapter merely scratches the surface of shared-memory parallel hardware design; readers desiring more detail would do well to start with a recent edition of Hennessy and Patterson's classic text [HP95].

Quick Quiz 4.1: Why should parallel programmers bother learning low-level properties of the hardware? Wouldn't it be easier, better, and more general to remain at a higher level of abstraction? End Quick Quiz



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node396.html0000644000175000017500000001227011672746163015657 0ustar paulmckpaulmck D.3.8.2 Handling Offline and Holdout CPUs


D.3.8.2 Handling Offline and Holdout CPUs

Figure: Handling Offline and Holdout CPUs
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_implicit_offline...
...hed();
11 rdp->resched_ipi++;
12 return 0;
13 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_implicit_offline_qs(), which checks for offline CPUs and forcing online holdout CPUs to enter a quiescent state.

Line 3 checks to see if the specified CPU is offline, and, if so, line 4 increments statistical counter ->offline_fqs (which is used only for tracing), and line 5 returns non-zero to indicate that the CPU is in an extended quiescent state.

Otherwise, the CPU is online, not in dynticks-idle mode (or this function would not have been called in the first place), and has not yet passed through a quiescent state for this grace period. Line 7 checks to see if the holdout CPU is the current running CPU, and, if not, line 8 sends the holdout CPU a reschedule IPI. Otherwise, line 10 sets the TIF_NEED_RESCHED flag for the current task, forcing the current CPU into the scheduler. In either case, the CPU should then quickly enter a quiescent state. Line 11 increments statistical counter resched_ipi, which is again used only for tracing. Finally, line 12 returns zero to indicate that the holdout CPU is still refusing to pass through a quiescent state.

Paul E. McKenney 2011-12-16
perfbook_html/node198.html0000644000175000017500000001111711672746162015655 0ustar paulmckpaulmck 14.2.4.4.1 Pairing 1.

14.2.4.4.1 Pairing 1.

In this pairing, one CPU executes a pair of loads separated by a memory barrier, while a second CPU executes a pair of stores also separated by a memory barrier, as follows (both A and B are initially equal to zero):

CPU 1 CPU 2
A=1; Y=B;
smp_mb(); smp_mb();
B=1; X=A;


After both CPUs have completed executing these code sequences, if Y==1, then we must also have X==1. In this case, the fact that Y==1 means that CPU 2's load prior to its memory barrier has seen the store following CPU 1's memory barrier. Due to the pairwise nature of memory barriers, CPU 2's load following its memory barrier must therefore see the store that precedes CPU 1's memory barrier, so that Y==1.

On the other hand, if Y==0, the memory-barrier condition does not hold, and so in this case, X could be either 0 or 1.

Paul E. McKenney 2011-12-16
perfbook_html/img7.png0000644000175000017500000001224611672746034015153 0ustar paulmckpaulmckPNG  IHDRܝPLTE$8D6Sfl@@ hh''*3-EUMM**Q}wcggU3"HoZ~ 44?awZZfu{{ttهD"3%tRNS@fIDATx] C:=nth}a$Q>{g6Ldy8N(5gnVc8, qp~CMA3<[}=;gqԕ=od~aA|Em.4h}1aNy/}JP_sV_թ@Eؐ"uAdzqZ5F>IE  jop]f@lrBSvD߸$+ۥTǫ% }`6ĕ%x1b)©#W] n] 9(].'E#>r{:1] yȍlu8E?z'&SKjt@hoM#6/|Kf%MqM<!?Kgn4Mjӆ'R9)d! $dUߊrMWCSῙP(snƸA\"` z%«7uzSL%:Sx-zfkiTd,]nM]t]i$$T.{vϑOgq=TPURf `K-P5)+5?-6_N0.v,X+]Nkm6PwP ]6^ r[郡gx}:CbXM.7h(ޫ5U:ga(O"@@c/Z3TnnkSu~n^{fUeS[0IU3ݪ4>_9iJʙpd[PV%]|JD\ׅGdPDE'1sB R-hY]諷jNKU}Tdށzj bR_n4S| Ӟ q<)AYX*1!ԯѤ" fs { *jCSu:.DJ^ w '$ir9@Dn!zܢ2⭽Us*:MvT'Cꄁˋ}DzdTOX]Aפ# Jys_@EKv0[Kƹ$g- `ەc.7ނ-TtER.u붻=|BqiTL&pA̡,112ԥq_@>} TuBY͈+d{r(\3|C48rFpV5U–;N:7Î4z8; ܥd+zA5. |Y=3%\_$E%TtJ^NKsWcB]+VR|LW(RE p)G 2!/wӈ `+5]~}L1}ϖJrKY=$M$x {A?wLT>+׌/`z:Ki7Y^iNU kį$pQS0fJbSѾM/V e5#sckcjnju%/KQUobo6][Ve|.IeVh^u $ |!oPq Ks PV3-G_]S \QTWP4iWfq[Lf;^yBٜF8VA.av-Vہ|=|^Am]gE߭6_Y\/6wm:+0CsҎq:lq$\?+RKڏm(dM=OEФ iobV9ϧjS|w 1W IjX8\}\.׭yYݶpV%*)ju((aL`Yѹz ezXn1YDU,Ӳ `fX${^̨sʌ4뇲wcj /S >U+{0 Rdz:~J3BכSՎ'a3CI__݁// `.i~&{Z~=\^ތ6h;zIg*H9+fY̳ қud4OZ{5 YW/魼x~[b;s{J?ڶFQҷO{gG^+3;?hNp^0yֱ[6+S=gYr&Ks?P0t7D a\4@bU7'TmW?׺J y5)S=οW^ mzsd ҢQLh?l{^ MNsc_:@JJ;o\W gOWf5PҶ&(4ho84qwSt V-/FRewo'(aư&~iuE2( hw3̣Z g(rNh^xK4x>ֳ>M|=.Pp:{Us@ JGRj⇇}NK_:->+D'.~WB9Gt܄_,P/kR gu~-;k}٣V:^MhY$ˈ`hMʙ:e3طTgjxԕnί j7olgՉ+h>?w1 ?w6nr6E;'AœGIGe@ڙA}QW? J?*V'K *-~%=ދs2j9yJY$;f޿s4(YG%3)msNڙa4g4+n *qjl|_OS2dT)[:YThos ǎ9OPҀ҄ad[,>P=뀧 bD_pƹ% (tr 8PBvS]#UMfs>c7[屭X_A;ofZC[:Qܜ)T$yң?JJU΂J<ӣ~zNWz(,lo:ni7*E2$^Ģ-19ۑդO<}l?V3M~$9GMI,\-虢UND3(n =,_KFP-5Mݖ6u@m\_׸d I0x+q"YP!k}sqo6~瓩 ]F];2q*Z@?8p3V`-+Zh7+8zC:,upnШ}%gk.xR8HBҞ[.NNKFLtk(˹tqTX'՜W/7lm_ d/,&vFX4ke +J{)Eikֵ;1[\dEj \1 :K|bB]Z8:;h8 aFJT)"h ޻4H+#:D<_w:; })̇ATs;+/mnj)5i!NI> =ܩhg5( 5zr4yAh; #l-E]viqV8 |o862jnp:НS~ MwױwҙUFo*60n;޴\Ԓ6 1⑋py_MFO%2F Pm Jԇ}r$8Bx'Rh$(W: + e,zo!VfwTÕ,y$$VS}bk i4 _kX7|ICpKȀV2jku%^CݳD"]sp`n5B VWac*^mTyQbjm(M)KU i3b9.2yHRvYr!g@?i3GdEol\ ik'59|KH:Z&x\J%]4G(ޟ#GWI%-Rrk[jnE48Pg"=z;A#\2RP;j՚vꁲb浏Nk T7,l.Fyu=lR]b6ٟ%p`|Ⱥ'tO:IW0>~ӰAl9;佽Az\޼HOFJl,%)w-Vᇴ3 r)d13M ^%m+{f;qC6@ݾ~#} ,[B7YW tLfޮuiL-`2R{^W%1X5tOA94G1@Y*Wfp3->ܶohC}۷ld[Cv=l%%@ I"o|'N}şbc?d gOGZyJXc}6Xieͮ\Q2 D?TK}].6gH#fu2\KF%op7؃E0߃ ܏*gcnm&5\{ܛ RTWal$4BDH` Mඖpdcz Nzpa2bS-}-CwZWH;a^GO.?Im; ;L;pЪ7d)r̤>ikR`QO°K 5oI-8 4`r AXDPZW- ^a')rdS8gmU$Űoa)\OYd@HdF2hL@AAkxOS xN6`ܕ'Ʉ"jy]s6@d>@j#']oK05-uv T L>P)8GڃrB]3|R!Vx(p7^J 8R޸ۆԢM葐n\imW& k$w  \8@=!)K@hDwP&ikAADJZb vZYs:T?X(Xs}aTNΆil3r8L"' #)f-z"?67EʒA&boC' CZ,~Hl!Py鱺8:8?0'*"r z.`bA /\U;ڹWSȥ5CU@4|vmHptd?\&scO%z^<.GTrJih4.Uk1Ņ3o 1 E(kӏrr0Q'n禍4d݅B!ӓ3$LGcбErFw -'9QL|\SlTujѹ?41<ޕ4N"y*ٍ9lLkx<6.>̢y j1Q!&1(:sX% #Xb0{G>3^x5g@9Sú~vC[#7Aާ}qh] 2DC`4Qڴb3xmVe>q &i"%.&LbzOhrCÔ!_˃ltB귙^C:QtL {VsA }msv|Q%YM$OiV^Y4PfR#UimDՃlHq$CD`jK5>v:":? #$ Eh8A vir6d8͎ȯKW]-sLӻ#m 8g`ޥ?6TfqA ޯF> &c0arwPhd0NA(ژ%V38DsWϽN@2w3Μ!n#gKNHL?3P[ubIFjg"RU|U w?)! f%졖7ɇ;Wf}`WٰI^*c>pB -)Qzia:gd?J2!LA/t-sA:2!q~].#ƫ jQ0Z0_=0n+`+pȕ/غF{"`]X#;rvi\cGx$~`\J>8==AHy؋ltҩi >8L^ çnkqT5 0X%$9ZT8RWJ4!9AxI5Q.V!U` 'gctM(uݸq~thɽJV)F76}71۠FZR0[[ج;~GʻWI]HOy42 Q2ammADZ#d7LIB1ϘƓ- Tsr;y9t2v}1^^RΥC c;#|HȆ5A"zRi{iROP6x(Vs B ,X,Үkre9M~O({B$e.q%3[nKu"MְXE{Blj}OD uIG;>(kͪ@4\Qjñ;3-,;:ڡUkw7@@庎>ZSO`v+V\3K/{r_9cvr,M')Nգ0* ,-B6MB'XhKE ˰tHHBT,~2ނ?r>N9 zXp.\@bb(з) %oi5D5?M fEoWgP,$ 8›?B\H!Y˩DB}fWd=u 8 |Lw)1.ω/'!S h W;Ak"W,K. /|l w.*YfŢfҡ՚@'iixKQ ;9Mİ>bU5uE2y9D9X.1t`2 FpX ҚTIs=CATPuWz3l tJ{)}1Ui$fd5wNL 7.1.2.1 Right- and Left-Hand Locks


7.1.2.1 Right- and Left-Hand Locks

Figure: Double-Ended Queue With Left- and Right-Hand Locks
\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeq}}

One seemingly straightforward approach would be to have a left-hand lock for left-hand-end enqueue and dequeue operations along with a right-hand lock for right-hand-end operations, as shown in Figure [*]. However, the problem with this approach is that the two locks' domains must overlap when there are fewer than four elements on the list. This overlap is due to the fact that removing any given element affects not only that element, but also its left- and right-hand neighbors. These domains are indicated by color in the figure, with blue indicating the domain of the left-hand lock, red indicating the domain of the right-hand lock, and purple indicating overlapping domains. Although it is possible to create an algorithm that works this way, the fact that it has no fewer than five special cases should raise a big red flag, especially given that concurrent activity at the other end of the list can shift the queue from one special case to another at any time. It is far better to consider other designs.

Paul E. McKenney 2011-12-16
perfbook_html/node190.html0000644000175000017500000001536411672746162015655 0ustar paulmckpaulmck 14.2.1 Memory Ordering and Memory Barriers


14.2.1 Memory Ordering and Memory Barriers

But why are memory barriers needed in the first place? Can't CPUs keep track of ordering on their own? Isn't that why we have computers in the first place, to keep track of things?

Many people do indeed expect their computers to keep track of things, but many also insist that they keep track of things quickly. One difficulty that modern computer-system vendors face is that the main memory cannot keep up with the CPU - modern CPUs can execute hundreds of instructions in time required to fetch a single variable from memory. CPUs therefore sport increasingly large caches, as shown in Figure [*]. Variables that are heavily used by a given CPU will tend to remain in that CPU's cache, allowing high-speed access to the corresponding data.

Figure: Modern Computer System Cache Structure
\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSC}}

Unfortunately, when a CPU accesses data that is not yet in its cache will result in an expensive ``cache miss'', requiring the data to be fetched from main memory. Doubly unfortunately, running typical code results in a significant number of cache misses. To limit the resulting performance degradation, CPUs have been designed to execute other instructions and memory references while waiting for a cache miss to fetch data from memory. This clearly causes instructions and memory references to execute out of order, which could cause serious confusion, as illustrated in Figure [*]. Compilers and synchronization primitives (such as locking and RCU) are responsible for maintaining the illusion of ordering through use of ``memory barriers'' (for example, smp_mb() in the Linux kernel). These memory barriers can be explicit instructions, as they are on ARM, POWER, Itanium, and Alpha, or they can be implied by other instructions, as they are on x86.

Figure: CPUs Can Do Things Out of Order
\resizebox{3in}{2in}{\includegraphics{cartoons/CPU_toon_outoforder_colored}}

Since the standard synchronization primitives preserve the illusion of ordering, your path of least resistance is to stop reading this section and simply use these primitives.

However, if you need to implement the synchronization primitives themselves, or if you are simply interested in understanding how memory ordering and memory barriers work, read on!

The next sections present counter-intuitive scenarios that you might encounter when using explicit memory barriers.

Paul E. McKenney 2011-12-16
perfbook_html/node67.html0000644000175000017500000000626111672746162015574 0ustar paulmckpaulmck 6.4.2 Atomic Limit Counter Discussion

6.4.2 Atomic Limit Counter Discussion

This is the first implementation that actually allows the counter to be run all the way to either of its limits, but it does so at the expense of adding atomic operations to the fastpaths, which slow down the fastpaths significantly. Although some workloads might tolerate this slowdown, it is worthwhile looking for algorithms with better read-side performance. One such algorithm uses a signal handler to steal counts from other threads. Because signal handlers run in the context of the signaled thread, atomic operations are not necessary, as shown in the next section.

Quick Quiz 6.37: But signal handlers can be migrated to some other CPU while running. Doesn't this possibility require that atomic instructions and memory barriers are required to reliably communicate between a thread and a signal handler that interrupts that thread? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/node297.html0000644000175000017500000001367311672746163015667 0ustar paulmckpaulmck C.2.2 MESI Protocol Messages


C.2.2 MESI Protocol Messages

Many of the transitions described in the previous section require communication among the CPUs. If the CPUs are on a single shared bus, the following messages suffice:

  • Read: The ``read'' message contains the physical address of the cache line to be read.
  • Read Response: The ``read response'' message contains the data requested by an earlier ``read'' message. This ``read response'' message might be supplied either by memory or by one of the other caches. For example, if one of the caches has the desired data in ``modified'' state, that cache must supply the ``read response'' message.
  • Invalidate: The ``invalidate'' message contains the physical address of the cache line to be invalidated. All other caches must remove the corresponding data from their caches and respond.
  • Invalidate Acknowledge: A CPU receiving an ``invalidate'' message must respond with an ``invalidate acknowledge'' message after removing the specified data from its cache.
  • Read Invalidate: The ``read invalidate'' message contains the physical address of the cache line to be read, while at the same time directing other caches to remove the data. Hence, it is a combination of a ``read'' and an ``invalidate'', as indicated by its name. A ``read invalidate'' message requires both a ``read response'' and a set of ``invalidate acknowledge'' messages in reply.
  • Writeback: The ``writeback'' message contains both the address and the data to be written back to memory (and perhaps ``snooped'' into other CPUs' caches along the way). This message permits caches to eject lines in the ``modified'' state as needed to make room for other data.

Interestingly enough, a shared-memory multiprocessor system really is a message-passing computer under the covers. This means that clusters of SMP machines that use distributed shared memory are using message passing to implement shared memory at two different levels of the system architecture.

Quick Quiz C.1: What happens if two CPUs attempt to invalidate the same cache line concurrently? End Quick Quiz

Quick Quiz C.2: When an ``invalidate'' message appears in a large multiprocessor, every CPU must give an ``invalidate acknowledge'' response. Wouldn't the resulting ``storm'' of ``invalidate acknowledge'' responses totally saturate the system bus? End Quick Quiz

Quick Quiz C.3: If SMP machines are really using message passing anyway, why bother with SMP at all? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node158.html0000644000175000017500000003007111672746162015651 0ustar paulmckpaulmck 10.3.4.4 Starvation-Free Counter-Based RCU


10.3.4.4 Starvation-Free Counter-Based RCU

Figure: RCU Global Reference-Count Pair Data
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}

Figure: RCU Read-Side Using Global Reference-Count Pair
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcgp.h) shows the read-side primitives of an RCU implementation that uses a pair of reference counters (rcu_refcnt[]), along with a global index that selects one counter out of the pair (rcu_idx), a per-thread nesting counter rcu_nesting, a per-thread snapshot of the global index (rcu_read_idx), and a global lock (rcu_gp_lock), which are themselves shown in Figure [*].

The rcu_read_lock() primitive atomically increments the member of the rcu_refcnt[] pair indexed by rcu_idx, and keeps a snapshot of this index in the per-thread variable rcu_read_idx. The rcu_read_unlock() primitive then atomically decrements whichever counter of the pair that the corresponding rcu_read_lock() incremented. However, because only one value of rcu_idx is remembered per thread, additional measures must be taken to permit nesting. These additional measures use the per-thread rcu_nesting variable to track nesting.

To make all this work, line 6 of rcu_read_lock() in Figure [*] picks up the current thread's instance of rcu_nesting, and if line 7 finds that this is the outermost rcu_read_lock(), then lines 8-10 pick up the current value of rcu_idx, save it in this thread's instance of rcu_read_idx, and atomically increment the selected element of rcu_refcnt. Regardless of the value of rcu_nesting, line 12 increments it. Line 13 executes a memory barrier to ensure that the RCU read-side critical section does not bleed out before the rcu_read_lock() code.

Similarly, the rcu_read_unlock() function executes a memory barrier at line 21 to ensure that the RCU read-side critical section does not bleed out after the rcu_read_unlock() code. Line 22 picks up this thread's instance of rcu_nesting, and if line 23 finds that this is the outermost rcu_read_unlock(), then lines 24 and 25 pick up this thread's instance of rcu_read_idx (saved by the outermost rcu_read_lock()) and atomically decrements the selected element of rcu_refcnt. Regardless of the nesting level, line 27 decrements this thread's instance of rcu_nesting.

Figure: RCU Update Using Global Reference-Count Pair
\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_rcu(void)
2 {...
... 19 spin_unlock(&rcu_gp_lock);
20 smp_mb();
21 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_rcpg.c) shows the corresponding synchronize_rcu() implementation. Lines 6 and 19 acquire and release rcu_gp_lock in order to prevent more than one concurrent instance of synchronize_rcu(). Lines 7-8 pick up the value of rcu_idx and complement it, respectively, so that subsequent instances of rcu_read_lock() will use a different element of rcu_idx that did preceding instances. Lines 10-12 then wait for the prior element of rcu_idx to reach zero, with the memory barrier on line 9 ensuring that the check of rcu_idx is not reordered to precede the complementing of rcu_idx. Lines 13-18 repeat this process, and line 20 ensures that any subsequent reclamation operations are not reordered to precede the checking of rcu_refcnt.

Quick Quiz 10.42: Why the memory barrier on line 5 of synchronize_rcu() in Figure [*] given that there is a spin-lock acquisition immediately after? End Quick Quiz

Quick Quiz 10.43: Why is the counter flipped twice in Figure [*]? Shouldn't a single flip-and-wait cycle be sufficient? End Quick Quiz

This implementation avoids the update-starvation issues that could occur in the single-counter implementation shown in Figure [*].

There are still some serious shortcomings. First, the atomic operations in rcu_read_lock() and rcu_read_unlock() are still quite heavyweight. In fact, they are more complex than those of the single-counter variant shown in Figure [*], with the read-side primitives consuming about 150 nanoseconds on a single Power5 CPU and almost 40 microseconds on a 64-CPU system. The updates-side synchronize_rcu() primitive is more costly as well, ranging from about 200 nanoseconds on a single Power5 CPU to more than 40 microseconds on a 64-CPU system. This means that the RCU read-side critical sections have to be extremely long in order to get any real read-side parallelism.

Second, if there are many concurrent rcu_read_lock() and rcu_read_unlock() operations, there will be extreme memory contention on the rcu_refcnt elements, resulting in expensive cache misses. This further extends the RCU read-side critical-section duration required to provide parallel read-side access. These first two shortcomings defeat the purpose of RCU in most situations.

Third, the need to flip rcu_idx twice imposes substantial overhead on updates, especially if there are large numbers of threads.

Finally, despite the fact that concurrent RCU updates could in principle be satisfied by a common grace period, this implementation serializes grace periods, preventing grace-period sharing.

Quick Quiz 10.44: Given that atomic increment and decrement are so expensive, why not just use non-atomic increment on line 10 and a non-atomic decrement on line 25 of Figure [*]? End Quick Quiz

Despite these shortcomings, one could imagine this variant of RCU being used on small tightly coupled multiprocessors, perhaps as a memory-conserving implementation that maintains API compatibility with more complex implementations. However, it would not not likely scale well beyond a few CPUs.

The next section describes yet another variation on the reference-counting scheme that provides greatly improved read-side performance and scalability.

Paul E. McKenney 2011-12-16
perfbook_html/img240.png0000644000175000017500000002225611672745776015330 0ustar paulmckpaulmckPNG  IHDRcX_D;*PLTE""$8D 6SfDDff"l̙̈3''ݦ*3-EUQ}cD33U@@fMM"33wZZHoUUZww~ ff?awssuݪSGatRNS@f IDATx] [:u8G}Try אh%ktzVفi5{QP}ƥOVڰ*NݦL=cҍB }<7vbgCcqvz&a#YLV*[`E?杚g;$}lcFB:4DOm zdBZC*UY %(pn숕 ()`LF|7U?i$g,)ET e # ]1a@jӢ(|ЋU2F1ԏcNѳ$LqZ+t*Qۍl'1+w hW)2)#eǝeVFkc1Z1oT4 {&վPldh %=# YUVs@3Lǁ'[B CL3'Cz@FK 1c)41`7PjxFH;L3zn!ɭ# H7⎚̕giuʲQ,Er$Y34!IũgRwKτ3QҦq''x"Izu431J =CubB,U뷻D;\ f ta0I=>Ϛy23Ld ߂g+Tq<ܒ<;YYofG-VL@XF!Eh{FEҞf^g<ϮTޱV=Ӂֽyû7=yF"~=#!"/˶kp zf3o *G8|&y%w:ʩgG03R04{` sY;<)؞A3ˣsHg|y8qvXlLsvc w@4s rs0{{ 7Q  0g 'h޳#֓piޛ)FWo˟ʖrVh³ R2gTHޙs 2uyH vro*n[uRAsbbb)S(R]|s̖qN@e-D!_<Ǻ?ܱl FU8CuH0_H%Z]2cog:ff I|!qy97$߱0tLB`2)RCʈG24NU$8 6E!-C$jn),IfI2BYg񢆉W fCEPREJXIʵ dzn*,S+ㄧ$68ˮᘚʞ6qs3Uu~Ţ(Z).CI X_S܃ nAwQ~)6u}񘃙D2n2TQ,_T+<qe^D6ؾ2#ɔe5+F)}/2Y;ؘV\‡㠃m梆leL;d4U%2sVe?Eg--F2HZ%ze|et2冁sH&AY6DD 5JQ ZZY&E"OCʮ|>1v+sS3H;٦~/?SU eȖfyEb듬KIXqzݮ@Mw'f}mqʲd ʰE$eC <1cĴΡytԡHQ?>L :q ֪ފ5@x1(L ^t}DE)+mvuVCnYiOVت>IʍjG]1^C'4#*B%Ι2ZS9Q(FPAEw}Dj1J>#D4AR ưIs2F5U/f ` 3|J3֒Dt, If1|U bK -JEVA X\j>A$qX3p܀t>oww>_~7Ř,KL1&|=秚^m1D]1-$@nwc; H˿-f3DZ Z*G`dCݨy.9{w^v-oy_k.nd% +nXIč1S%?Ӯ]Ob(+lPh3jpI`B+: 7297hme5`2F^!U'Ks"%v#s e. }DD٣V"vS}b o D\0Uhs!ͮ]Jqs]8b'0Ƥm* rV1&n.rvkΆ1 zc*k_ƤWRf(n`2Ci cp(8CLt\[Tn[f1>‰npƖ0L ""PZ0Y.ϤFF8'BBrgES0PEzk}y@/ce̯fXƺ)c[ؐ%ek,Qج)c|(s:OǑuɽ3}$63 ]\Mgl'291e%B`FǠWxZUh0Z[[Ba@5q{_`wwwi ^@acܓ$ꖹ+օJ!z=Hp̈́(Lz Q!0fr}3! kh-f<8WU$1L:0"Ɔ }! M #³i0F\Y!RCAW$JaaLVAab\2c ]ӢE^0Xx(ؒ77u$W+Ufh<-+9k˭w;+Tyz%/gApC1kA>c:׭~:`1AlWzJM(*.5(LZ*EX')E^ yc)"/t-Xc$ct66>*cy7EE9x?cˠ49EUbDUw`J>˱I1q0G5c]F:PjWR ,x` kgz t@%!lrz0/D-T~,f{W@"/i§6z:7Z CFj~.D\Tm`鮤 vWşDぞEנ3s^KH.Xu~XcZl1VPݏv>[͆c|P1+M1,fdJDGrƘ: _pƜ:`2cڕvˌBù:ԑJ4x8ĩ4^ܨ;NaNaKzv`9dc0V-ðMS~;JSYoݕ[.EcL9*$c7'u-,S=]b f:<cN@.ǜ2>jӺ:U\[7i>l0$ծtG)cĨvMvIk3^' r}晛;cMRk>|3! k4Ko&DaR I=%4wA̩"0@"TSE`N'* Q0's3|dGb4V4Ƶb=$uj$dg,D8M%GUY4f8_cf岊<ƿ VqzDTfIԥ+Kl s fzm]c s}@5WrZ5) >Kdq4u-| cև5;&˸dXcRl %Dĥ<~OP?Pn=]|5[4vgu6hL%95,".!Ğ_} -WKeR87KYŠ '0.?k?+%N0".!{.ߠ0{JƪR.lkT W]φ%ypilh|ŋw1 wk%54pƠ1MCИh)Z(XB9DLBK+1?1N+]27*˱D8dkuH[ C8u\1eDc`704:u'O6\c^-Hk5f\+54fpu3yVSSGc}B&B%s~j#a1]&zjzf7hL4SziHփD88} ;qa#vIq:bnfaJ{ MgbAc #ApyhZ7>%FB>Ӛ0㉎si@/2=a&ʂڐusIO13ul-OeRF i$f0+zL݀rHO0.(tF`ټ4ׄ&XKMN\^cu7`T>ܾMdηyh1 k@+z5V X|[8K8}?Éy|[~ߣ/1Z#7ZИhېXNnWB 5p-hL4mj N|m6\41V#ѷʵyhJh,MFL͘kLJ[o *wˇ?ejƘD*f1\4|ċ%ijl蚜os:@%%'B߅O]PBP^#+.\iajle), h'.crA_E ' M0.$ cv'4`LHXrˏ%LH.Y^t9 hlrH WOAcU%TM cr1<|q)Ʀ~vhAObD hlZȬ e_Mb94 $$AcT ƒUĂ<`5\!|2q|ꗴӛRtYv^nndav[/ՋMVN>,vK7MiQdTC'Fcu5S146 |iLʢG-<4+1" sY(gϣvpJ BYk424fFPژ{`ʛ:}^ИYAK4ƶ4kA4WJeL"ICraP՘q,41 a&sf?0{.5?4&x1{h9Ucy- z\䥔M*D\nEQj l-4fZdqx*j=!s-tMsvF/EjjQFFO9]j ojY%NcӘҰ.Pc95fPc_!(sQRWa "/qVZT̊,h x6tmYRLؙ FdK@d^2 Cw46 b093h̠ȂdNcCcbf2g&qΠ>1asAk+ lDcD46IYјF7E%3jY3h:Ɍ0z֌$N2&&0<Ƅ4+̀ã*5Mqw Q31hLc7r$.E)|?Ws 2}oRcp뼱1+33yV +pD 6଎g gAjYИPX4ⳫVcOl[@Sנ>CޯkLfTLc=mIj!x`sP iQ6+293t4kzQ/␭fjl=1QoQ4¾}1 i}Xcl{[+l_KҘȂuIDAT(A{@U#/Oc}2R(giX6-RvXOx1k 쐸< 's8RဳaiOdL kAE Vgc=hWY7]-<g]yOdL0"s#<gYdЌWtYOi 5gSpP1&/l㕵LU˧)1 0pV[UD6 DO{MW$OSF3^ *e렱1 .q>iLM5OTrk,=ј CYi~6'µ @XUg4Sr c4}>T4!.hL]_LJ\$gaY[59h -zq=֖m<%+d_i ܡe[/Oc6hUWXZ4fca,scliL8Q`mà> >+1'XA4.לٮA'1께j/Hc}5F1,&' #] ,9FEj b.0 zZ}S˚s>h4/rt3łx%mJ`&AOsKӛ,[I~y%"^ E %/Fr ܴ46CEߌG/€)$gPQb^֍FSa`,zW U K@2G0:vRJAWkU6بa0$uB]cc]3^50YoE/)k} ͢wuQ}N - KNh1ʄ4`6F,1?- s-uOAsAcf9G)1WSsF\cb.5#H.5\#H.1B1Ap"3`IENDB`perfbook_html/img56.png0000644000175000017500000004533511672746032015242 0ustar paulmckpaulmckPNG  IHDRE{{PLTEgdeb``^\\\ZZURSTRRMJKZWWPMM<99# b`ahffywwmkkiggcaaXUVJGHFCD856KHHC@@A>>wuv.*+a_`|zzrpp1tRNS@f IDATx} ,jZBKms/,3hz'1 sY"ͯϼby>ն|Lyes`U^xEct/(sRoT ]q,P0OSªc0aڬx`*7OuO Sة8-[4\{Ȧ o5yq4L(lfyg!2˙֊6 {pUM(3TCr^'KCkLk[t]VsZ=ʾ)t-˕-a5| "1@IЮ-[c irKxnp8wZDŽfm9S$9JQ27?T&xYq`ú9H>ߪ䂓˰ n{ZF+פ gi\{O'!ckc]WubXe_*'ҩьb^ /Nughi.Ӱÿ >qKP)t3;5G[y,+Z*I’4|\>hvC5]1c|@`j-^Z-> s0Ű3%DbSlBV&qȴgʍQog,`z >&mKgUSwlS* 聎v=3ŕ:Jlk3˝gv0Q&%n/F~=ZX-V5Z92'PDRϔ<7҃**bx@7G9KG=: Ѭ-,Aӡ 7?`|u.g B[4x(*ӲVJ "nܗܺ9 {ZDm.Pb-D&un8DgӬV!>1]z҉]e:BeӝcVa<;ɡ3kO/+$~2UHܢwL~1z9k]w8ԍk?E @dݾUd=y1M?iWS0< E%V\j޹DwE5ϰ|*adog8_'[rMAeCʍV*y'a%3pҽR)Q0B^f #IcwC(OJ1x#B4F 9Ue$pКn.uqyMQҽI7mPlEw4sRq?08,XWM|p1TQ5p*VQV|K}=N~p@oӛ5%48-L2wKr06s!ԇNĴS„"lU&}w%p yW7=y.?cvElj/ݍ> QXnJ~a0Y=%q'@HV)w-%f&l)ۯ{TZΙʿl]VoQֶ/p69!*Utz$2~Ats,;?"qSo'I7#YW v'ч3֑E:q$)^zg艃P\`@B#|X k dܨf Eqǽ/UHvЌ&HIO'R YY ʌ/a!P`g981Bw"7%vqg LΥ{XS^r ;}Vl;KZV4ℙtu)o3b*WPNV9&<ʶ ـUmhioFPJ2njλ:2 X_rxZQhԍB)"7ufˮ0_vQX]ܱnycÍ!$#2<=Yr;goUzɟ=%ɧ/~h3Knnjm{eI2\A^1^7ܜ0_,83\%p%;\߸mr^/sXL :K/0. lj՘Ar.XQ5%oTx ܂;h5|}z7g/:F яFQU(U)!M DÕJeLk v;{].7JZ}!D9[舘OFW[S46U0I)X#K㥻ʨcgnݯ}jvlf.j4׷_t{촴[S:qoB\ZtdAѨ]^!AֻЯT9%h l`&-Ux! N|R_! ׌ԥT`bФ)n| U*=`` ͝:pn.(OcN%'G -|."arƫ8qt}3;WC 0{qB؅^}h@gu䗻Ce5uf;ܔ;Ja-rJ|RO9Dp  ฏbKp~ʭ~[ 7_ V; 74]sO%o0ǸUs{~5Ge|C a~TSHd3Gobg+\*O8g|iΏ-{<1g~jYm:)X?T fӔhpfh}* c3Dl@i/B,1N;f<˅4*!%]'4tOII ^Ayݐ0(E' !0.{:$;'ΓzSܒ{=r=$OA]큆Y 6J>x}4j-g\/lc"TC=pTh,W1@vQxz:^ )q.5(f3&o򉚎xb rbl_D僬yׇnb皑&{Ď~ VIXY}"U-$$NDk;V4۫p\T8kN N@Gu`q@ Ů B 'P@ ŹG#vI E$4 l  ]cn:Ka%c}c?Kj"5LO< ~r~^~!X^B=p7&YsxT|ҡ\aWOԿNtǸբ'~}0Y  -ЉB%; ;,'DNRJQ1:YmHqrgt0a '+[y"尢mT(϶dR򱾊uNF|KQ~aKDBeSg7: g:~ O@ d8nȸ:Z4#htfӐ.0sjq .;j K{wY%,LMP;}u~PShg V4YڏѓϷe/O6E\]U)Hi9}r/uލd{f_]oQg["(vktZ8>oR3n ]bT0t~2 k[^KϏpaWO>T6 CEYDŽZ4 ݻqcm'ƶNRٺ[ 1tye" ^K_G*YnCi9$7})Ll HlV_?=%C͖d께g|tPdw?Ͷ XY)PPo&'tHNqe!북c!l oXsdTºjBiq1n=z'6nuhX| > wAf W:U)Ze,'?ݺ*?܎k]b$$G[Uq|q^%GĂب]dK27do%@BOnG0oh |g2@vdqEg:Ȯ0*:=vI;䈐:O0wy:HHlxxˏq@ncLֿ!>Qs+Xr*ՐWD5VdzrmFһOe!%@G  QP';$>zkG95 C>I A aV#)K OfOg~ ]uʸZh_Gm̓+ٌpϺYH?q5c_uj3V!}g~,gS_uO9OU}`\5oD=;|߫u>.[1 [ʯx3CQ^Wm TǸRefF(Ճ5gByB/n!MhLv>* @6KCg: mKT>jɵ(P$CFL~km-a?NQ /_Aro"':?rPq ;!)Ɂy&{ ]FWF􏩮sᓊ]=z3-j5)Z1=Kf>IBb:A|;`Ap=XȋJ8Ʌv+^^J; 7^ 9՛{tRH{?Fcv@ oyب-c%5FLǣ0A5kT`P:h56VtT PKKlيb7karWMKNjj]XG9;Hj_c5|H._t uu-~=|+N1=k7sϩ3޵ A$xBϤAѿ`\ȥ4ݽRjR.k7OBPќP:CW%]sST\^8W>53U:XԐ Rl|b!rV;D3n{:%\ N)uJr?344Q`2uzƋp|X׉2#mVJ瓀g+-((خ!=[sI/mmO7_ LABo[ǻ$uߍRFjdlBcC|~U~c~~?+bwur@/]VݔH8'S% ApR$c$Wƹrp\hTSasZHv;*E-dR(5L %& Ʀd,t`NQ79} {3T66lJ:@pyfB:wˀϩl@D7w ?Nth)Ǜ# B^F*1VKp$ ۘB IvS z! ~0g "}T1srGJ4αD= 2*$.4z](%n 㖮~u 0M4!?kR#de+߇[IN oGrZ{L\891#FUOAcGps6RDQ@WUetcBm I H yK+ֹn!Oώ~'cpS dtU rM 0v-3?FXVtAb+ WR(*>¹J)E3xEs*7I9i$F7_ìzR{rnM*GȯyTHk\S*|:77gFvc;/}@l=̐=I=\)oW<^RRHs)dI6 LcIمff$ # gZp_h NߐBz/v޿ Ys1:eaz8ޟaSeKxQnGJ$c#v_y7 f-bŊsB[PׄzӯOjpY  vN4cmױ[& J>* I7\pyN9x!hoWԦ xQxR`0^@͞&\W0 ]ݫ% saC (pD(bDWq01a^8/FL cIl*߭(uwKQGN FEAR:{DcYKqC'ϣ%};/Ќݻ寺fwǸ9>b؏-cؐTVAm%fKha] ]K**rԘrv܉q+ H$- #bo?ly;Q!2^鈆VidٽFpe)>*h|?:͒.LTWKmp#ZN矲}9Dۿi>S9ȅˡfHq#:J/~YOݭBdHmN4+*j9G9I㷖Die3;,s2xMmH ӝ7S]zax|\3ǧh5x|ѩuGk1%G>a\DGͰExZED4EC8K,PX:`P sƂ0YԊJ;K 'F3pA,ɿȊ㮏*፸ LliՊŖ2ְ/"M"a5C$ev}>rտei[b[pZn_B~RdAy+RgQИ6W$1#2 )_F޾3P}ܐ1ЍtC1WP^rC_#18#Csn+ &ϫ&o+.*~V(@A7q,mzQ#%Ĩi 'FQ,!P8-Z1 (GP IDAT>_DqO7>cg"%iϜtƄ{tOfHH$9Wv,QzbNdPџIn$"7^}f1NÍhQvwR7#rÌ)+bˊ^(ozAʇ 0#/2D+jQ="|b69#lS/SxϹ4fgo( :%_lk޹US_|6U.fa x- $ ȟ$_Lv RY]AU}uw ˷7%ÖEƀ- –5|"{X 7$-$i9.o [X ]Fз*n [l2[E+?% fygQ`7 $,X6QBW[F;Wv)lWi5,"[m{DmvL81"HML%s\G ?dcF!a1ЦuӮ]bP$:5[FV\G;\IJ6zp#G֠t{{d:30)|qXGX=ܠq-K[j0HXģXt%[k'NT1;=^m,& _1U]&r0!Ea`#=EF9{ ;į˜ i ''LXKR: ЬZ%rQ"~e !~BHm5[n805`/Uq/-&sB}‚p¨0ޠǿPm/v?P-JyлP0;jV@p?0'ubK7s<`BuF񀥓3Nw'Y-~&"nN+6c<(qEsh=#xmIwrT^jhv'QBOXzbMփJUZт%J ܎ws$ ^ ~󦕿+`Y{~u";y5NLU*P# TEG2S k_aYyᚮˤ-.٬Y|*2ň4SR'gF$ĈG!,ǢlLa"$Y aTd7#cF Hģ#! go(t*1b^b|1KUq Hμ$Fi&k 'C%1bNysE#4IyF*%y/Ǩ;ҭ36͸lhjz}2s_v@%{ҭ뮙d\ Xr#`&HnT#lh*q;_=H [#1Z<ϲ . }Isʿ0i֣w;VnY?9#ى99_[_?$ w½:aF.Haa靈3'2Ϡ.J$gv$:ցmxpIB ̮YIFv2ϑ2ə`wO &ܷNə3nlwI^5`{vt`K1nhK奁 =@1X $(?E&Hg,jNn#%F#~nޜ۾DL m9*aAd!H9?鑜6A'G҃h84|"`x{$=liS4i 4|H`'n?cUt0A '=qO@(V,Pz48qVs/]hbräQ́ÈTʢ5T5a Liva8RɁyl]ybAhna# :Bp)QaD[@V Ĉ89sr0$:oYovAPeR~BB՞q`&ƈ`I88qQWFx7͚CjL'V]=÷P4c,X7얕[GaQ(;wf=;} a rGf r!];d qOS&쀗a-1 &܊B{\KIUMhG]bǂ0AYlSu([lGAz˓k,XG#rC+[~/+-<ד͓;Dt<@#)`3CFVblHB1@-|+q0]ĸ$ tP6ҵYdy~,wbI+Flwi;əS"-[_N}* ,8 0l\'}jF1,hoItA ;_,̷N#'@T+QNB$ 큿l7 $O/D7_,̶8>8_נ=W"*'[Ԗ3 u*g.^xu' "uab?/Cl&??Գir*Ȱ`W#zػ,]hh' /nDGK.4'M'|8g/ypOm (X|.Tau t:WVtNpbp|ƤQ.5ȡwhej 9Xp{me8 MU\)ğRiG!kxߤt%Mʵoh% h5?K?܎šp`P rTrZ9}.BRì_i\ϙމ,$9/MwHւ"J 8p>|@ג`Sjn/)wfA_ n*UTJU%h^)!M3260x2!EmQBXn'!*,nID3ep|zۻ`}9BPPkgi ݟnߊu[BR{vW#U;.eӀ߷턖dfZrN|t6[&@$ҏWpmsh^aǘ%=! 1F9Bn+@߃CwPݳwx1*}i;6̭t^?ixаa=v [`{TwN]?c,2F32nmy|fT!wi#Pi@ -EW&.AKvDOݚX11eaMjW=2@עԓ2hJڥB.oUAUdmDaܢqMr*PkS,aDpRjY[Pg9+ ee5#㫡 tЩf !I1"I.>"茌 fCaL^Sb1###By Ͽ]?Tq kXy8SC45-Жvt}Yט QC hQ1q͈s qB:[ƃۃ Tp{ |TmyPz`KL_ w3 =@p u}2lTwDb݃21<+Ռ18(2W{+ nYK{GFkt>hQD@n >"IzP^g]Le/1U:yDZVrЊ^au3`t1ngY3u|/Fļ߮E~QӹZJ'"qۅӷDx87VD#/ UܾCCGKdC vd]~C-|6 p! kj"zSJ Eɪ!!g"8Y W:(w顸So1v%MSmzeMϣ4:ϋc@iR'q/zƃ<@sEjdŌw#k j#u (ya>Be VTh!xY rۊ :/f<:/f:S󌌌#}IxXHUy z<9Њ_]V F|UxXNF!>%CYK $U Wy90Z4ҿr_֫oi#f1zv$b:/a>C=;rRKς Ky xbFi=WM3>Xd-#z&exmHS>D*=R+C$*lҊ`O"w`722>FMYTn5,/###Ã,RbӇEFЈns31.,hm {bVEVΆa%FfldrOX1zr+hHh1"-]/_6@ώ>Άa%Fѓ"a`DW|w61-m :X_A $4X =9 j8q-a4$|n\\MA7q5:z+ȐY9ъb`Ϝqy\5(SQ+Jʲ`'Izۼ3ühȦ179{=]KWpZQ-zڕPfj+i$)a50Ǧz hB A-": ו1i1t T+8"kYjX9 UXƉiE |M_DC+v黖ϑ? &f'++`,|z%pn%a- ad~@؀?B.Xi3+P]d!w~ִPw#85!Awnmx)C+o#C:ᙤntf Y  f VRa:eݴ"bhcd+7hЫľKz Ϥ=|c2ͰW,1Rm ƅj73`+hԊ2݊VoFdݱ,gWȆCrm{oXM tgYi4ӈ&[,l] PtaU7$Qci9"иy GYL" m)@/>E HO`|pe "C1G\]Bxq CoVn+уV}#:#㞠5Zt+X f&xJ07(;5cJnvbf%`i3SV $i+AP_!r]uϬ,m&xJ $i+A_I# bf%)++ MO-1`%@ d\X|=,z[E7~!)9Oojޓ?1&,u/phDYK>J[1 RZM @O$bp 8FEnib{΢ þȡQ?ݫRȋ {6 Q 3^o1($t@BYf+b,"#z%9茌 ^CR!biK"І,.Zى3WX_󾉨o1S2/za څX!ո'Hȿ7}FqڅX&K!QȌ+ h7vdVco].g%S`%%hvŒ,X XfJs+џC6-dZ TҮbLw/Nr.YݲL7sjDы8Js.#_GǐG9,7߄~\xڋ9#i#/H8ljCkV ?:r9 iA̘1#GٱbxХRz k4ʧqxl/6BD sS;\T!+wH 7 s9ur6ap79Fҷx?M/jyah@d@Nd0~Qjr99̈1إ숴3q0~g1R7=ca|֯q%eڋ=)!g'軛ЯϳaэQ'ktcq`ĵ[A讷b'- [}X_#{~`A齿4Pc ׹=vNgƌ #Pgs.0! B̈́A NN!,&žL]YGˀϹ~wBa?_C鑢 *.aj1L;0!,!fB4g IDAT7{vdz{-( aa?a&I: >6ljsKW3=Z`J~VL)v$eϐ|R#k&2.j#/e6b_pB|`bf!+:|# VO~VH{@1P}`-w ^|P6 u #YbդGD°)-['kt4X|pdu=.`5h%?@(aOObĢ+ks߻l+U:]3X/Mۋ?CQHf4:|'U\'9e,̨@N {z_QG>dCBq66"Pj[WA- }AHZ€UDB5/ܶkBze]kU^!7=ڈXw`:$853F\_A?moh#t6>#p bUYkI AP*XǢ"*2M!/>ÿxL;F=\'K=:=$"+OdD GY=@O\Qjs5t#Z:L64fǮ b|Alxlhk0Дk0P$怡N XYyAUdC3&Z 0\C F~Wȫ_1H>vMq1&Wx9#:#Q7h#Fy]> /6շ3~Њ1bQŌ*4ώ~3`gq~P矑 ~G?[|W kY>z{H_ .C+bpG#d1ѻ)h [uw!Pa.xU]& VOKሁGoiO<XLox造'8cw7o?YTLox੓$f/QPj#Hd4<G@֫+y32.HyBŷ8 ɿVl q \ ג``fp.]owi#TfW:Hv\ `6^~*WpG"c-O\qqG"#i`70`9w#)6nB<,26}p$u7=Em7F_QX;BbfDVs"cz* ?BHX8#t 4%Gd1v)3"'HY eGtvcR揪5OG 'Ql1i#ܦ+LF_= #u0#\1't;)w;Ano VPZ X{46BM][^Etr۶$\3Z+Yt؊ X2.%yz4zmDu}qГpے/*k^ALbJÊMjTEu}/Q@h8\(v/.{Q-p[-zJ\k$ 14.2.10.2.2 UNLOCK Operations

14.2.10.2.2 UNLOCK Operations

Unlock operations also act as a one-way permeable barrier. It guarantees that all memory operations before the UNLOCK operation will appear to happen before the UNLOCK operation with respect to the other components of the system.

Memory operations that occur after an UNLOCK operation may appear to happen before it completes.

LOCK and UNLOCK operations are guaranteed to appear with respect to each other strictly in the order specified.

The use of LOCK and UNLOCK operations generally precludes the need for other sorts of memory barrier (but note the exceptions mentioned in the subsection "MMIO write barrier").

Quick Quiz 14.10: What effect does the following sequence have on the order of stores to variables ``a'' and ``b''?
    a = 1;
    b = 1;
    <write barrier> End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img215.png0000644000175000017500000012745211672746061015322 0ustar paulmckpaulmckPNG  IHDRYvPLTEk d^yUNj4)9*/ lgt (F   A!%~  SG_\VuǼ}y쉣#)to 2->C;U    RAS?6J #+ķü   񸇋<1F𖤨-%7 )!6D ; tRNS@f IDATxTSY/(Q]i[*:A-O4qq&yYjX# 3Smb0PJ4J oOk%0iU=(s?RPAN{>~ʧaeW]%o6^'Ẇ _eg7pv:˲nj:\M_cdv%\[Dj]]tX]ِK_5RU޾LW+W O/?ĎUuoʺdKd42_XWaDԸ ʲQȁQ2N@P__#DM0w7^J%pAe/g5A%#Q\V+ {T˽&Dv?nܻ EtO1'H1Re26VpoJJҀ2[\!j=s)[mVAِs9#$\*~G i#n`'Q2QV*ńg!i(k!EwW[ʚ)M #P i31B<جۍ@ ;]5<HFۑWy2pdW5]מ2j0Ck(B |dbxDBF%U؏nsW_+oti{ y~5OUUiׅ|m%Gd ʆ_pՠZo/{X^X,⎾q6=n`vVk v55ي\9® F 4[#z1|-TM4moZ:[(̾1i׃|NNǦDa׎lF\X!2ί_jaxTf`mAg @!4;;2ׁ 2}#r v׍SPk S2@q6g2UUxwfmt^??<2U2+BAav:Wf׳4T~|F l}SLu4H ϳc2`2YnJ*`t 3`d1fj tj\nG#N]mZV %[ю]ҟen Ūl/`Tz]Q5ŤҲ(yޭS]jAzeRB_T`jEj5nq=oS9s 7SXmfK<BfmG:nPK \O¹uU}یõiot6v^VN3VTP`9죂E=jY:C=+. ZQDGJMSjwԎ٢(]`ͻpNEVr6>GAҀyΈA gݵu%s3}tW( dL4pf} Fyҁ@Ac_d*^V[ߚ;`fR=vGj:BXƊ9!ta7Xtz1б&[j JiB>x$d%\>L<?Ō:5A&loJ-*|9㖪S]R!J 6@Wbg|濏a9&d4H2̀Q`H id&*41yXM~C"yGajfy|9 6MQ[|#7Zu f-߄k7W3O#-׸gQ^7ާ; E?}6rɨ,k'6:j.N|.֏^uFU7Bu daY\@7VQUd^CUeˤTH ].P0*t̄Og(N:W10٬h]!P<i{q׹s(BkZL2g[N>CeB(QywqOsZ) "[́XsWN]]y3>HF 'q۶wcT1hO3d>IEP:򍧙S$a$ukB1Z67 եv#k,(`66F* Pi!PHg6C@<<%Lu>S]NI 37eX?#3ٍ燤HeG.]J .XBL"[)5f<u pOqV,VUj,FhUa#922232Zt MuD0H kk5z/V:e ̈́]`X] "da3dL6H$Os#)/SJy%/}e+cYcuR]I©#eTT7$&FaPkdun>7Sp{Zv;`bWi3i֥QYO3m o̾7;d *V5cV#}?] 29ԉ{ˎ2ј!ԊX={g#瀑1$I uۮFCOCp^aaa?~|pcUF jQW28:$gzEw OR^v.k7|榓%d'XԍQ,MUs7QF;"q ʯ N%܈2K.b`g*^0(,#@dQS#G]q2 u2v'ht=w۪U di҄EP(&Ou 3l}i 4a5y, $i*=#\eKT[-AuV^,@势.é,Wc Cja}Īxc@uܪ3&r:7>{0,("wIN rjՒ->- L/' z ]V2 7Mrźߚ[ ;oQp5 Na+X䁸a@}lU 2_&_M+W'πɋj"[cD>wm \bsբ߅}\^\\Xg[N6R@ޑJ2yw/NPRz0_P#"t1Ne{;ݍq;fR+L<ńt㷨<1`{]ϥ# v&Z56[TyX3]2Oy 77_Tu 3gIJ1p[?˿,z6ZBDv*fiIHihKH.knhB?YO@\sz[ZΩjY]{LOzO-* J=vAH7BD .9:CAEp窚3]AtN 0^B&B͍kS#_" |#㌻dCV-ۘGʊdC"θdJlYC1 ڰH,9qr 6jI>FXffޮ4 ,,Y0 I6bMoVMqQ,%=K('AB?٫gy@J?M}' /L_(Xl3heOz <Ϡ~d4}:iZӎT] m~`QVB4 Z$ "ZAqs1j +H$JUGqC&Lҫs9agaME@5j5^ڹ4܈ИE ? hggp0Yy,b{Iffڰ\['eͿ d7f^8FR_ hȺ]N;0l_ǟ܎n7jG1˾|zu?2oE2Ȯ/R_ggFFGg2ei^$e__: /`^BҨv5-K$1>%K Hbp+éT߰}<;l;ՊYU>r٤|ik4{FfffF0|8bP].]旯3jpҴggߙ]zZ.2V^#u_BfD%3a)ɣQZ &kv0.}XڙlW-\IV-{ݽv38?a |8Ta! .ˋF#HS!II3[e) N+ ·!)2͡BA h6-C}NL9TaƃLXĤ ;V]رĘur`PpI*p\ѯH|. ;|~=ӄpuj1Y AywV&b0}.k,MTn Vľ fՙyXVm FPd@Rn2i2 ,kh ܥE&4RxD4oڙF&&g]qd)3&9bpnjȍ 86W#&Q^60HZY{FxYG=]`QىyTEom"#VydM#)L5ΤpR9W0d\EY5YdNXQp}t.`xJEh(=3~Yu()oRR%%:Jw@'$ʣΪ>؜xy0' Lj|u?gMQQ뤊i~?fMVƶUGpyMY.rX'钪t=e* /ft8K0qcU vL S9JJ(^Zo1[8~u+< O" vE2񄠘EMoXpZcP-jyR ; U}1cu#QjF2W'ZMliҙϓq0"W*z`(|EۅT2kk4ǐj9 e&ma;G>HyΚDˉ~Vx<; !z|ܦ-QiڊVKNS LtnxS;GcXYuuK:$ p֧]k^4lN/3.4Yӽ5K2Yܓt 1÷6yxZ#S95W/b⏶c`e2@Ņ)ۺ; ŏ1l5Tu*{teSKt fk\2^eQaGGũ 5TB5k۴qE,LXoB5W]-<T $ۋ&mY63)5SVSιzMMT@OFagA5Sgad jRŘ/e=$oC2[92B[J+Vl ܴ][UIN5RFR)K讇]u׈eWdM1ajX>lD-|ZmA-)#e|c]/1撏b[ kQhdЊTq$E# |tOST- 6<7}NK A ˴rv]KЮTvD_f k*JG@,'eIzo\Q E.A U8 :9+F A v4=ShsG]*S@n{ c4Wg+VwD{Bo8]5Г[6jyXqc);dGQt$ANrg!{rɂ}neQj,c_FzYX<4>-6<Z G$I_LCyi&$[{MtC{PzvE#E'ɕIEbя`} IDAT#lg &W\YNVVl#׫{Lx哔~ 6)+[ɲ"O70( Ó^eSb=@&|؜ < b+3m4̼ySʮ\Y5-쨉!O5s/HGޑt32Xzhe]Ky@!xZQYs;,t /rT:+ J^rU~ a K*7f/y6aN~VPh%34 t^1#E QҿCR)4^*b'f s*;>*!c_RMłhTpRWےfa3YIQsEB=;]livҍm'U jΜ7k,Zv"-YnO5baQ>i.WnG͉ AQvs5$6-fXmhoMZ #A|&CU;;"y {qF<U1TGQ /7Ss)xsMB7h݀ntə CF"G3 x':oy< O=5L&~T*߫ 0_S{Ldݵg/ ~͌gi&6h/ >ƅ41.;N6[k[j">VRn/4ᄹrQ9i Z[)Y326 _}{=l5j^/&=&z>U\M49CY)(L0R0ߒ|)ni ߁zQW;X9l\{dC&AFTDz~z&-M~HkJgD}0?h^2uDƣ։MZ!R.(&ֺH%u~j`C^L,2gcqR18`F-ƪ/Xd!Ѫ.>SM <s{i Jϔ/n4d~~Sv\2:yq :lbLyw 15'n[ \]~i-XժʆϽTUGͭo >׀wW>BhKPZPKqM|ٷѲEe)r ^3)b"*p۪/'&,bGBGhudPQ숄ߊFQ`.kt]EElR1F ;6-1 Gi%y`_6EʞB~φhT+v }4j&_'ꫝ_E<݊%ZY 0<\m0d {?qCnr6J p%&9'fä[# ~`f(XGoe:X~p~u:PwDQۦ5_3[~ҳ&+-J(˻Tձ` FG^/L^ZɂȄMQh~ ::^cwu6(e[8kٹfg{ D\n\S04E v(jH/K?+ɅŸmuN2U^SEv_ w4zf +v1 xʪڧV1kl_Vx_/Im4NDa{&ٙp4ރX/q=k8YmD1ɛ!V>qʶrgz9?.[/nU셗AN}ye8,۳~WB͖DTQjeU6bm4͇}m|@Aw y3F YJIݟ]J` :@^1lMnai>4<{ټA=eYhlZhXILR]vޞV ~ +ײh\͘*ډ"fm,c][~iS0:@9,AHKj9zqk'vyŒHl+Lu nc{8)}&/+RQKLׁw9 ֺ4zD zi21sfԾ)WOt@ @Nr̥zφ4/]eN<і f/66} t7l&$64Pf9̗ٙYuU~8\oE=>pxFah6͞>~6d_S@Ke {s!m.9&'Xn`~;ӟAcGC8}1ч0 -jeSB?޾'8ϛRN~ jU.Eۊ py |)0OL,:<ǚ(cG'<ۚo6(V&]Kg?De!DR,ǸỎt™[zF wf ֎rډM#ܰF`z0:ΰ IG]HL.ЂhP+pPzX /\4̈LOp{+ &`3NS|SyNthC 9C=ts;JB%Y,:ۨxtZ ;f EFB$ 5]P%RZOot\Ct^Ȇ.:uh<9ꚗ'"C8\4+1{q;3z?"wRs)!:mv0 KzKihh#T$H=k&o!X{&{ ʄ7)IՓOFd]J<D"uHhgXˬwf4?I|Wd,/eQyӏ~9@Ś+6cV"]nbSsx)z#E:{Ӻe;_z)țq25A瑽BY@3Wsz:FHtgkda;{OZS\tvBEՐԼ:Oy8VM烽C޹E){DI" MVTp <5֊ƙdǺU޸B=,֑wOvZ^/VQgp!c]t &3Z]$^WyFtFjHδѦ@D-#Ljœ^kBtDiũyZI}pyp ^XCʼiGӢTrƧMƊ)Өċ,| :67&0tޙsLX,Z.~So'0#;w64^ɼ~9M+˞pz<]A%G=W9]Mp#)2j̞*oOi;V\pY2z%2нPC p 5;cS{6 rԥmcl&VLM֯c-? ؆Z.zTԄ}}.̍ ƩfLcQQ@Ō>ϷSԪU-ɲUgx9<ʧ닋-{pGp,6Q0^)y3{8s|;(Mt\/#\tVa;H7>폇[mZԨ\>f[=Ufrk]!:o#5qLnN;kb^Յg p){!^R%8zֳSμ#f}{vJg%wQ &e`vJuRd[-/Q_V/|ۊX]#&8O[+&x  6Pj_xm[dNVl8/Zj*L-e( q0{!XnO/.Ӧ> Nzu}vD' CtЊg8F6\1+VQ:@k1cuy>v?a'+v<^bfk* 0@%kۘ)5dϫvf|3iUy01&GpTkyYln=JΔmckƢI{8/hӥ+OHT 5q,ʚ FJmb]\A}#C 3E6*}Py/ܚ?hm/ߠ3v&YazKMdh@tכщ ?4jtgA%p .Mcd!d5֧)G? u+Ҽ5D\*r]y д?Z ̞ G}4pji;9I^4 n΀Fӭzu}o6YoVvwL݋7VḺìӘ">ռ^D*/f2uvxF.I2N_>ň27SCb~d?WOb{jjbv{unXmbZ-v:6kGZ"2k)TS p9NA82x!]Kmow<wdalZ[MebVEkl- N& Jv<kjċN,yx>5> 0h3;iäs 's/oe[/2 ^N;6k4"3:'Nst"^pv.Ү6~{͏ji',Y5>c8?4`iXqu\;s,uySsȋed=qR(!S#Px{7kQ[T1cX8UΑO¤RcCYqq>p+̞Ɉ]$aXG|^NǟL3r|0R6&"{1A`B}l URm;+YIW݌XNv}SW8O! DyGvh!x-8 BДH-IGC[fF4ڙ[`,Am?r34YPNl} +hu[jcDē~r_W}z$^g䶷7>&dr d#|x>8>f҆ȄѕinU.U |NBt!IJE$]{u^J4f19ĂKŖhb;Sc^muFwCh`#+mnHd'͜Ƚ׺peܯl!PnI24{n[} LQNJᨉR3z% ͆t"lzBLր- a&xMamk ~U^O =ZAY6 NCRgFE)p< CP/Fb'IGr^|^35($)]TT `O联&ђÊ\@(Iѳ#v: &7oLӼk;(o?eu ; F ߊ.kpa,!hXcKϣVƼ@`egvm̽&Dy3Qk֟KfH2ʪ(. &Pk l5faptֱg byKMcsX91<w ]o X *~(ouv=@Z= @ IDAT|YDZ9ct/FzkC{.v. _PM! t-Z;hBǩp/m6[3<&gRetWlVƐ(^!T>B+ҿ32G=7-mB;mEIrpzr/Dm{S0$6FP2ts'QVzMCEF.LɆnҏ- L`JFhoG6Oz%x0p ȝԪ/׋G.f3a&D\@&8nO[\RIf- mC92wo?|“6w [m"RG") `/͞'eūh-YS2¤^OMeҸrGq%+~AIJ~,Crk$1o51 O.?znNxύqA fB1JlF)90#W=^^CdY1ә, 7Pk 6Qk0vț$_ 7ŶB2lXŁ'V݋,G?GYi] Ƒf82DlA):f3JW`X0Y;UѷFJpxlBIƀީ{~ // kvHo~- ހ6͍|pK ]hؙ`.|ݫhzmu&dy,q.ZN*ӎ̖-˶mk 0{!47~PUcIf&_p[ Q6G\u3_dS%r= @<ڇ;aR{I>fRB5,W-qiXDwMVSɴ̜th7S<3dr]Z{2q,+\9M^Έԝz_zA"ZsSN-{SJ8=tm_ &:I _PefQ f4z #R%ӓT:(8 N VO߶ykceր;xw5qmo̫OX`-n]so(ц/dX~Ʃ!rrr0vMY]a#yJU-صMI[.:MYզnH:':VPܑYK/aGKDZX"cMbVIϑ9`{ͽ=E#)^*_2fB=Hl`tywg98vDN ? n?R_ܙ^H/Aj2: Ĭis[\QH9wsgdR<`RWF_w>r]k7oqSxς˛ ^aNϩLugOUoʎ]O&N^vfK^īx?P Y+%+%B {w,|!:lа0UvfwТch~&xn ]&fB}t0<ub^k:mG,)U5bA]"61K+b_d"t VP:ԣ7#P`C%=yJ8 ae(HSȅKpf_z?FϏA[dZbcV%&hYmSv7+IC~d7nn/ҏRL>|k(}(u<3e65b0ftq98E`KOFFݨ {ܯ +f֎z.@of&tne9A@d4ͷGFff^KdGVfzӇhy&GfFd.a<=]fm:Xd" v&<~ןq7?ecL:Gni4>7qkl~TJngv/gq63n}|\6Qkd<1Ҙ"M,//~1DhwޙU>rT_5u F:baYsh` -?D=!޻s/8'!J_2{1Oݜ{xf[:w/eߛ`ljďMW2OydۏlZ>]u#?;m23raWpNz&L g{Ood> fK 6'Q65ud%28kQN5zYezHݓ*SSqȉ |=ziƑsʓl "'x_cu0"M8#Yc;m:~i=|օّwz4wɎj:)WU=W80)71^5YV_w Bl0&aHZQ>@NIg86`wi^# )73@j.J?k?}~Rpmi^Y몪4= Q!asAH+7Kh,I2t A3d&pe0<~U0 8˕d>7`%! R3V&ld0V뻕h4;;;5X:V[jNk;>"FƬ/&?UqHaWgѤC/ "N)a~@433ٌcq3 bhG;D,ۍj)hx"lƣK0Yzc}R1@y--!M^=<ʎaLΙP/*ΈJV67%_Qu~'#r2(j1wT]F6u΁PvamA:hz$`{7[ o)}ѹCx7O( ^8O^lqQKRQ-!O P}Ax3\$!W*!(acQx:•&BǑru7}g2D:y~ηYӎQci ,αكŋ;:C>X{F%K AbT'ՉrH/OOh"/}AYJ9O*6٨mjμXy y < i!0T,;v^4G$ d2 v#Dx(e.O;oL&J{nYZ6,1Cesݬ{qm.ȿAi|yK);If +{w*(`( FpqF;Vptg<g_ _w&8wfY,:RiAUV"!Y\z#om- RZ0toupAƫKvAI%s9pi%I-jv`~<~x먠3>g-`=!i$p춏`s60I$ KsNVȷh7MQ!~MHE؊aBg*gfnPе;x;WFK,rv\fkkn]' R |atZj*䷐FOAFcm#]IrՌ mkyuk]8X!i }î\C[!N [-Rt\W#F!F3z]@~oc쾖}o)w$ yX{$-֦;Wn]V_nJa5Z1N&Y6`yv-RE x|`@gf$l%pls-+ϑ/3&4"Z rջp\@J3ZniёѡmܭP,Gp*}CBqpa=QVnMBlyR㽮ލ xΝe9 Քw& v-6`c#XfVj1^?27ZƾyK3,)S:b0ϭv4/)Yׅ}<,e_CQUvZr'/<`CI~9HY+Py ]{/&'om]Vo|QbFQː\` }B+fLQ 0^r)r ,ylybV4P(M/fYbJV336wBgX˜-OZwL6]Ug_dXi]Gf͜tY^v;qJ"a!IЛ7~KO mLaQņdP[,,f6`1 MSaIqwltߎy>oˢKoXpNyt% 6dy~7AaNp5Q0<\MwN|ԹJr>z2&+N W;x[dT/H<917J5A}_Sbɧau W.\&F٧^jѧ}7F5=­a5?:%BwwJf,[S:{mt :$"-.eGI2W8/bA;W*wu1І" 򪕰-[/66"xok0_~a񺞲_GV.fʺmhP5jBc%>Mmac`tb"둱NO-J@.+  ; G 39ȒG2ފΒ5%)NLW,θbӢo@'dln\0ʞDܦbI{z7&œ6 18c6 m:5FNef(E[a9=5ޟm4tbnB]ĪzFQ tqZRgDNqypA{zY PD"fMaV|M<qi}7ۼ^IRɿ%S(%u[n/*t,N#1(:Q%qF04&MqbrrO [:j2v;yMnz U{'^]$x` h@=$ءVb)CcOA"c lBq0ƦmχN 5y sᡦX[7&yU|-{ťܸR?9v{~^2b{ǘeнxobat_u<<3A>n]{̾Wll+$f*'r6X$/,K{dĆ௢(E{څEBr(ZD{sbhl0Vj~cg`ZQ>"faKL4#̿StnSō)h >SP r=Q1U+`=IoV=" d'XE2 ļ޽kL**,ȉb]Z\4.n7&b8EKk({a$"Cj5RWy2qPOѧ@]cڬWlo6{Eec"C'buBzG`Q1rnk٘.t|-Ջ)$ %ձMm{l-sȔM+~egh]Am=5<$rQBpr01GbAbvN,@ YE/"s,wox) Bh4ј5)! vI´0jQYaKd S@ TXL8֋ iufYYgA>u@|f 㸛^ n$}AG( F -ֱ@wAIm>ę&* ؽ[Bw IDATS]3]X|dDžv_Mu$ 3 g߂ GxA?-S8ͥԟSFK,t<[ [ 9Gԋ $^ǝ/E)bN ¾+f3b,Fu"\AL ZMrB$5WzˁPr^sd N?Xb@nK ,2"c ![p6li͊c9ȉbnnhH^>=4DCRy/fItKLSiT?mDONN`)lH{OBKbmG}RSɻ\on峤聳PX:Q H- hY$E/"v,(jTP;8bY QFO$"gwbAIbDmei P eJGVbbif/wЯTʘq|r ]ah u78܇{i 8yAT_qbw`OL4/bFf+&.R5,eD6-e{ _Wv.s>]^^fݹ20k ?*/HiqSN%ZRҽZuv5KPMwpg{ ŋ F3_$bQj{c)(oe4J{,#41J𫖧N0uI/@~qx,E#ωX IO>5Y.DˢB ucl-G22ɷBB⤒OK~Z-NL"T8bbX]a,7{t9|ɲM%g( P(ex~,)+;qlcX=yEE[O Pux=XtlB,f?vxCIֵ!,-Ἄ$ݐCZ fA:V''>7p'}S~$k78YEi˗MHsjdx]VWOW?`D^DD"`+nQaweG,vA ,L=l+*B.:G<x%z6U }'~^ H\&rH[adܾ4.Ox4hi0n'/I>XXJHED#XToY6nkd#"饉_ $8xa7h錘R faHy ]]f:( `*-$̯Ǜ' HIo"%3jW|P$rW?PyhBQP߽_4g}: vNhsu([B$e gJHpiٵ6IbH_԰ `Hk_bT\,%ei@1ꊋYU. fxH'ἹWQI#FUt|Wjaic4Չ];bW}0!OJ/Q17xUbˤ*a1+3+P&Xl)),$F#Y, 7n8ܜ?ŻGuxy)(xzh;Had+*$֍*}UgƳ -:e/,AQtaI4sXC":7P`#\nt|~ĥāPt,}V.-Cbh2 G {dGc5|xdk3K3zv<ȇ&B@:+9bqEaQY%lleAos7zOHW ~oJx£I=Vu2P\LOnOM gJ),IS!(OK]1EtE X|mP.0r.:*饷w~iNҝ=;=W~$Xxy?t[ǑwOűBx"# oxW`zDTOqqI,k50Xz !,4Sq@"_k~C۩o&OA{ qwR9a}]K%U(1?jJ=DV_@k v6y^RSta-A؀0oe`IVp!\2*PPkr.lj)kD<8祝p8|G"7WM wt:&pU  7r pRIm<-'P#m~E1Z!-4E4X6a8XubZ3 F?lN 9&{QWj:ƶԷM1b|ŐZA1pef'7謝Id|v=oȅwSnW{g?ܦIP?4T#QqH j( #Kg3ba LP@s[Zâvd֘a^kM|8mA?9661+/ogPX%\\aqK]+6}򉘈%oj-DDfJL# "2,k`Ҧ;ܐ0QsY${y:¡P:~䘌Fh sgBĘi߶]uc鯢},Зםؽ'U4zjrg{ۯ߼#ܬq30 1BϔƮU3,kfXqξ@%*1գYW8W ?p/@owoم M <@씅de'^ qC j4rh\MFNNQT'BQ ?^0WT!V`幀+EY6Ծ/_^?#~}wZ9veC~6 i\.J|ֳ q$|&j.O{PCv!SڿVR]\ւAS#;Qa/HNT˟Na ʉbLIiUe}I~`e("-M_7d1dd48`BK `K~'W2 :Z8U}G&2>;,Wm{KۍeX6[X1|W٩xe.܊7Q k/P(`(-'|pcp"8G=nm \[\^OWk5|#x?wM{\|=Z~HVd;G.nǭa{9&%IrP:HI\&k+f/0KrVD{d`4,#5 #j"Abq!R۶| }$ʎ5G}%O:îp$!H:*jnvd@yS&ɛ}y,{k࠹{ײw.*.0R-l]GO0YԅP%geGs vB]L8r"N{5`3h5 X`Hݩ~xN(%s8 hy`7H( ʠ\WUmrL0YלUGkmx'$2wx+dOo.κΟwyd%,򸼾z/ݝs=9< {*i 1<°dlAoH:K016nM䕵656}ھ-G `)ʭk֞JBoW۵~m[Vv8"QF\Ep `(\н[bx n J,{gXxWQ5}RϠ$eڌ!ًM$ )5Qmj%Po/AϺˮ)8ޡ5$ qPo:-"AgQ;|9 w]N\}ode=ʦ$Q_`s l˵ :@HMyԾnMckrYS3g$1dNڇxfHXUC].݉0AVdOX'-zXHS "wӿ\~6INJhj[.u~k7e g+%p]a&HN@WskX9kOxG+45PLrtp,F:î˫ zeA[U7П>@JeVÅ()` iaԎ t^x[qkyN̴CBD -QzEAaStRq0:ʜv(@',00$<#0Go5QMZ\)MFrXv׿ݐC>YFTCެ[\/% r: {dʙwA|;vJwCK8p)zY;|s[^C 򯑍Q2]U2VX( <>Ϫ6sE[W9O 3o↑ s4&GATz8eʁdУ+#YBH 2טdԍ)W\gSnn( N=ʬmlML'$X9, 9o]q v`7jI¢;s]EFڴF̜ ̱<ɨ9b]Ȼ D:b]n>?,˂ +pR\ɬ{Ii } o2 ;脅Tu%&E_{[wfiz:yiݣ9 7ܸIt޼c ڴ3;VG_Ҟq ȱc&n:CRݲƨc.>[Ot:翠,fYR_et ᑓj^`V I$L_TjWhP2C,fh_Il4)K20XBaG_7we}:ie[7qb,Yɢ@$$ Y*q |jCá'A]m fgY2u*.nӶR`7(74a*?_A^\3CI3NzX62dr/#($b# (_*D=@\(ԇ:1:^tRZK;^FP $˭ (^,y[vG ?2ޚѵZ!#cdZowz8K+S;!c,2/D )m#6 !qRKC5fɴfEA$z{gJǦxc#Igzd0{3PW ]Y8%&ݻJ2a5Y l?{Zpdũ{:,Jɦ|ĝesc=-޷'l:K\JAg=M~4UC,mn.=2_X< $HƣKƏC^RrRtqoPIOο guV Va32|ǏF}V))YDP &s+tatHr@> j=? OX' h5D-xyǕ\I+}F%i.DJ6u54x[|Oa%+c~$^ W0qB Q 5 iK,V&);tvR3$p)$ٓ HOʧ ׸7Dg[7۵5SEl-\ d!F]tE󮧺Fѫ~:nAޫ!b)@HxJ7 ?^EsA5 NoOI.|*?ȅ*86_ =Zlg{!Ziԯ%CpNLi-z_W-7-UVgVF> EBH-BѶ]q@d*bhl1]X %ątzS4=G'©ު8Q6Sys23rb#ԧ-Dr1J@[X[sƃhg/2"Zr'\wMs?fk+͐h53OvŜYg'(ȯC3ؑq[Nv?dqK{="Ms7re#Ks]dݒ K,z.%sRo4@擑iIlnfUzN^g{4,N 7VIFziϧ].qyԷfj{rq<*ܼYeXhfTΫۣI"xsH6fwR8ŋuWy￾uSiH:|z;CWSvnsq^VQwrs5ATnq-h/wqksiW3۰I X6IS1}>v%>l֭.S){5v۹>vٝǙ5Bԩ?+JatkG^~r5}_"=S`+w9|ﰯjfEyMݼEVr$9X+i}vIVhT`'mvu`ڥY0|||r,sk}83eLF脟M"_7JaI, ,*&*w&z3^iP?:@8t˸:<рk˼)?RZM D{Wߴ?EdzYTCjmd*&ӭzx!GbRor*Z:KhΫ))`1{JH,@9!2.Mqu"V*y-:>OffR_5uf CK۽_.B$D!= 뷰[})Wy^a] TP֍` tW뛋 )c$Dzņ4áq\@ᴕkHzςqt~kk{<)E'ũJrw 4Yh.oS{>V;,|λ1O%~讏rN7#g;?SZvVAa?FMs=,.&@U(oM E*תꖭ\.:ǭ*˰o%Z]h-^٦p"=]_NkN/_PѸ6=r4 :E:+6d-VY`]:]ɴ뇜~z|cː$h֍'2yko}>]؉J}}]$[i-Z>`% ?|^ 47x躝4 ?sB.,~TPj")xu*|+nմYi> ª( _]As$ $W$򒜓EGۄ%kO!E5 5) OO2KdrYU'(j˲%獌,10EW\|,_rd%ls'2ydWU޳QΝzd \V yXf885&' kbbepf Bzׇ]~Ţ`!, TgF~QFΟS^GOciLe?ŋF9H H s=>S '<9u/RHOjE[xЛĊ B}RuXVQcrk RM:&3M:lr!?rNC/0O,48ڰSzf?xH?_.caT;s$rd2X1}QÁhO'@UېtAe395mO]sؘ|L\6]hSGb~M=SąI͘Py^7\/V_r> [P?_/sMx$Jϣ`sg.nKt @ U9-'upgrܢkI^8h=eu҂e zsȰ|, Dc⽀V?*@g3F._رO˾r B?_.ga[B,Bk ԙ7]AOEV3'5sHR[„ٍn6R'\PHԌN# $xk xZV D͋gh?XT6 ]h Wd)1zQ4~Q@ _`f;Fail 6Fs=3bx1N].)~) n)ޣsZVi\o<KHz0e(b]mLhޕhٹ9 >tq`|;e$YBdBEntPI~ޯ1 |%)} YZMbye"\"qlo. M5_.]:Q>1w! WXbĉ,\aH- KK/|{C($J^]Gpk[*sʺkֵq>P]*oyy!Y9trܪs];BlJ[o &/M%Ha`x޼ý݌$~rhڔ~?E?!ij)UuDbM{\a3<6m| g<.7& ?HOC2IW?oZqϮlEQ9+zڰOIrd:ei0"`,wねdcwHl)Y~$i~}mhD~\!SDh3$=8zF"ڛ>7 .hiB8Q."5?%A\l޾w/rߥ3gZj`:?ҞnG/T;Da)x  O"f\zOAf?vy.˺{ɜ wV1BE'ȼzOW i]34d !A"n,ʓ)Y^d ;Nj |'C?װ,S ]{;4Wy(r6PĚʙZ )eVP.~t*3G\6I#|#cdi'}ȰJ1?\AWp5(kf8rJwQ(2Ztd`SGC:rBdT4JHq{T6@lۜ.ៈ4.nn^^kV-wnOC!;!4zLe"7.OG&ޥ|5;[ !@}soZm;0`|^{UO  :+t}~9gi6Ck1,ϖ6ב4\F%V\3f79+'w&rH 2 ]7.r cc'6+Z0(ToqJ=Ӂ{3cgW. By8 [,;6G&6 ")iqK&ЛGrf<)ܼ38(̘N{Tj|%b>Y m|V$l!T;JywQ^H]D6nl!L.Ro*zՎIHհa (g\]o $;t)KE/m$Rb:]OCNIh}kꃅo=ړkg?;ww x?[_!)ecl-YohtkA@. ڼ߈^#`?,RTHlDv<20`߾}ZmlFW^¥+/6N8bXXv;& IDAT3ZF-gP:yyYHnߝt6- qnD!98Cκ^# Y&؀ /g&/vv{YO] x&!emo#Bfyd+JbQRIA!_Dd2`/$`Eg}%:iCFx='VƝ'>s=jᡇk<")1L@5Db0@b ;sr&esl^In7>; AP nNBd83Sxv=s#:֦:¶T,}5:S}n=`wSK(Ιoĵ~h;1%d[J %xϛƮƅvwstk)gIjNu*Yю'C?^IZa<] 0_z܋60APJ e-AEr5j zvKz诏^7Kp:'{'YEp\m高($!%ZoW XMk Q%Z*J]CWn\8*LA9O,\07{GozF})z{ݫݛCWaf`lG\|VQ^k%s"?P`o2-XyΰgjznԸGvULʺzQ3(hhcG E17eZ20?͗)# {zoleM 6~cJb^ vՅreDRW7OyƶKĺ,L^_Юԍ;U\{"7tmBif1STnZQ5 %&!m޼^af/hZ+/>, ZSYra#ieӻۏ j)E)-+*nSh33VTn4N]N >R5kW#lu[dA;sYv~I{i_?GƯ͚r5X"SɩVlZylOJQRJe:yeiWL-u;{>vc*c5;ߩvI{ SG'zj6>][t!jGKյ_-o,|}ܜ>U8wb[dgJZ{{{}Ur1E` SS [5&B.E99d/ژ҉* M2:JYtg,>b  enVV2mF6񋢃~tmD3+S$WC}Gj& Hı 23h|yPa٪ϩTm3~EZ> z`ŒA0y| 4cZj?c|+Bp5 9AM`S>{3L+ʙ6]^X *r~GUZgN"F.!t:UҪ7SUe2(.+5Н̙Cl(51:p!i!_d{r#me(VncJu{VPת\4k`\Ǹ=ݘaum;cuD4yoA,, K*8I]^9ߞ[X\W.4;qFxqAJ"FĿ!0zjTOŁ}tw2v"72ZhS χGݡ<2Ij5+jeN<&+. ñ;҉kL24}BN ԩdWOQ'%YF#**nDvTrL#; P")~Ŝ"/ #)b2ea07J4&c1BkdEKA3YV/);,FSLE*`h#N:b[mꤠz_*!8#'ǩ#rJZ={41) @m7pBW4J`C+ \CӏRm6gMD欿[C6O^QcrdL:xI!8dWL~pԂ~8E <Wn:Û^:rGt ,)IekڧGB+ aK2=ykdaO6OjTQ1bF+b+Z%$ ga"b;Ȁ 7DlEmfl> Qq#'2?ءHH$kآ GG#.έ8}IVj f-Reo;zv**~aJE0.c>UKI9Ŵ;Mu:`g^13m6zȑU_풡hsĚfyy WT|ALrY7Yi:ASF5o_.SsƊ=3`_b- '1Rt.Eט D 5iRy8>ua$eN37#&nGջ,ɝZ[}t0նca2_a~4%Oou<Ö3Ѭ6eJd#W3hGCbe 11*)V:F\41hVx1i |7qS6Em,<,s` `a/p]5H~_1){\~!gWL<@3/6G̞zO /4Jա yE׶x=%. \("$T(=fv~L<0@LM*npL[-\ 'I#)Chip!Rh"anqFֺaaG4R/r![ (L4faN* 9>[92Ն mm5Ÿ@dȃAMNӢSِzz[jz9) H(YiY~ tm> Io' !WA1v dI~@ tH޳cBտUWn߇$N_Kբj Mъf{HĖSx@yvöE19b \FǍ'|j ?&RZc9"qǀC@Ṏ.!Chm zS) rDiU{@KKh _r y|ض˓50M<܀RO,-d^|;޼qc~׈f2_yADDoLxf궘d;q|.F [B{ܯKdRy삽2YmW1r;I1i,1͗w;*yc;Sįmʉ .Zl״:HGkxD)qdӖ6MjhWa\F~<^p;ɑVO cv'5g"q!窚hz.$ün餆JN}e„Z׼| WJD-ZwO^%֯ɷZG|*vE:$ƾghy9RȤgj62N;6~v|LzPHyGB5E=3x,vĤNG%o!hótџŷ_QI]gSo].u]BE{l]t[hFͧ -yf6Bn ZNSءȟ$453;!vvz\n [C(IВ'Ϫhi KW8Ėۂ9qi >~l55ݾ iw/TRXS7wçeIw:&~uяk7"[==&t;"PXc }I{Bg;#)*jbV|j?Y`o+ê8!vO=N!DZ ]JP7܈0t r&҇{@@/ߒV-ܐgJ'x,xTl6nĪ6Y dr3>$ vb-9iqU-Gu{I1 x[\ۂJ;6J,d,%/[Os&҇Pf4 n?$K#FB?bwȗG `?x>.k7F?,!r\LK>ˉn,ri<@w28)~@OA-‰<"w3bFTt#l]x&+B.&Om}&>b zATA(4__$(> 0H#Ⱥs[LA'EfӗؓKЭi,r$4ME Tۨ(P )W9wL%UhbjOë9aʼw+_KD 0fz]2KG9Q)=DN .J:L9(nD4]IfXX:2KX:0K[6fPuVrgLAM<^Ii|;rH UMYYjD^4G_4yM$%H$a/.x"R8~`r6fID;KTCDR-LIJ9G(/%;GMW8 Ƃ["xtz+_W%K˗Pbm | ie~ Ԕ8Mřջe3ɧXȬ˭ $oTb-z~xT |lʯ|+_CqU(yg a}j};ꧥ>;|+!]' !lv6SR ,3cYٜM>~6 K([&ޘX![C^;Gڣpgߊ凂'!:;8\_BS?+N{ w~sW_C⠴vxZu0KW%:+9%oI醄H*JM$ŵ bH,{JKERkS5x.]pE$m3L!<KGf鞫j;+/UuX΀5H󓆗DID,5;JhƝ|wH 10.3.2.1.1 Performance

10.3.2.1.1 Performance

Figure: Performance Advantage of RCU Over Reader-Writer Locking
\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperf}}

The read-side performance advantages of RCU over reader-writer locking are shown in Figure [*].

Quick Quiz 10.12: WTF? How the heck do you expect me to believe that RCU has a 100-femtosecond overhead when the clock period at 3GHz is more than 300 picoseconds? End Quick Quiz

Note that reader-writer locking is orders of magnitude slower than RCU on a single CPU, and is almost two additional orders of magnitude slower on 16 CPUs. In contrast, RCU scales quite well. In both cases, the error bars span a single standard deviation in either direction.

Figure: Performance Advantage of Preemptible RCU Over Reader-Writer Locking
\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfPREEMPT}}

A more moderate view may be obtained from a CONFIG_PREEMPT kernel, though RCU still beats reader-writer locking by between one and three orders of magnitude, as shown in Figure [*]. Note the high variability of reader-writer locking at larger numbers of CPUs. The error bars span a single standard deviation in either direction.

Figure: Comparison of RCU to Reader-Writer Locking as Function of Critical-Section Duration
\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfwtPREEMPT}}

Of course, the low performance of reader-writer locking in Figure [*] is exaggerated by the unrealistic zero-length critical sections. The performance advantages of RCU become less significant as the overhead of the critical section increases, as shown in Figure [*] for a 16-CPU system, in which the y-axis represents the sum of the overhead of the read-side primitives and that of the critical section.

Quick Quiz 10.13: Why does both the variability and overhead of rwlock decrease as the critical-section overhead increases? End Quick Quiz

However, this observation must be tempered by the fact that a number of system calls (and thus any RCU read-side critical sections that they contain) can complete within a few microseconds.

In addition, as is discussed in the next section, RCU read-side primitives are almost entirely deadlock-immune.

Paul E. McKenney 2011-12-16
perfbook_html/node454.html0000644000175000017500000000751211672746163015655 0ustar paulmckpaulmck E.8.2 Entering and Leaving Dynticks-Idle Mode


E.8.2 Entering and Leaving Dynticks-Idle Mode

Figure: Entering and Exiting Dynticks-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_enter_nohz(void)
2 {
...
...
25 local_irq_restore(flags);
26 smp_mb();
27 }\end{verbatim}
}\end{figure}

Figure [*] shows the rcu_enter_nohz() and rcu_exit_nohz(), which enter and exit dynticks-idle mode, also known as ``nohz'' mode. These two functions are invoked from process context.

Line 6 ensures that any prior memory accesses (which might include accesses from RCU read-side critical sections) are seen by other CPUs before those marking entry to dynticks-idle mode. Lines 7 and 12 disable and reenable irqs. Line 8 acquires a pointer to the current CPU's rcu_dynticks structure, and line 9 increments the current CPU's dynticks counter, which should now be even, given that we are entering dynticks-idle mode in process context. Finally, line 10 decrements dynticks_nesting, which should now be zero.

The rcu_exit_nohz() function is quite similar, but increments dynticks_nesting rather than decrementing it and checks for the opposite dynticks polarity.



Paul E. McKenney 2011-12-16
perfbook_html/node243.html0000644000175000017500000000451411672746162015647 0ustar paulmckpaulmck 14.3.4 ``Macho'' NBS


14.3.4 ``Macho'' NBS

Cite Herlihy and his crowd.

Describe constraints (X-freedom, linearizability, ...) and show examples breaking them.



Paul E. McKenney 2011-12-16
perfbook_html/img23.png0000644000175000017500000000627411672746023015233 0ustar paulmckpaulmckPNG  IHDR^~3PLTEMJK# b``mkkXUV856C@@wuv.*+&@atRNS@f 7IDATx] JPӞ$ƊVN;wbd%n0+__VOR<4jvy[9UPիyV5ЩNjv7E#=TaI?V$\zT u[hT 3zǸ oO,bhfج] l8mSmԙe HBXQSGVU<ƕST}n^yYqwu/:f#E[Y´ |k®V~l; `h wSי$C8Kwu앺{aG<Z ]ӎ 겭g`_e`UW8@Ժ_䧵иyC Tk=Ob& 1k].'dՓ,4ۤ;<cEMQkjkY+78.VFQ͝i7Ȼ24> }6saK($_w1: o5#R߀v'rȍSRՋM[}cKҌɛJzg|bQ1u1/ZwCSu8IFZ]|8mo('SC&{/*>EhUVODjtXkw4נ_W -FuN%X@: _zomү_ҋ0oefHO]aGi6-ԃH wى94eC'EBiwZ">/k"MlG͟W>؊ A2'D*䓍zZQxPLC+]ӤJlIr*Ji,Id (}쇽eR ^(34# vSw AN;EنhOڟr3AXX!zrn栁pmK^%',&#a$˄YXvxG_mY݀rT (Xҙ׻- yWB`R)ZhYa?TRB,iY* <{v4k;TZvλhʳ7.ۉIʑ,4inRfP4g̵Kw`̆۵Ql9/S*Hۭ jU ^-G.ntRêբiB>{B81ܖ/nϯ*hNhn/]Rq4'9U/#bjhy@$JѐЋ Ϙ_q z*%˱R)Ft X ǀ_ʃ I.] 8`=_:oH(gRg~kȜT,]Z*'ER~N"!xT"8)Afh\,Sn[~׹%<4-0ZyPw*otkmDjm%"1j+isf\CJĮe% ůn2-PgddM-ѫQ.%:)_MW;TI@Lm+;N+d|L#yÐoM>#[+ d}j=h 5yi|V rﴥC^[Z` = e&g0)onn&~q_Fײɔ,ILa{ͦ1Ңxt& ?D_Z;EoE[}e(twʄ,?a8sόRX\ CgpCRq/IH8՛G=/IWBlBiCQWPTE?0%Z DF3X)!p>Ho?|ZWۆz1z$? G\~I+ZefHÄ}ĊЖb-K;?#~qt\ß=HMJy1eYpZxLs + PLW#ILϴ++i%g ʼnAXLfwVre%Rҳpl6Vv0JS;+)++i ڇNx6Ͱrֽ1廅ӽ9*.Bcw1dgxw,uy>h: &$_EMgNkPy#4͖L =ؓ2= )BrB1^>}ü\hKkZzwL]ni2}tG1PUh5󖋦쎡ah$Tת紵!wxU-%'# 5oF{"V"1k[R9 cQӐ\v}䎴By J`h? H.5 Figure Credits

H.5 Figure Credits

  1. Figure [*] (p [*]) by Melissa McKenney.
  2. Figure [*] (p [*]) by Melissa McKenney.
  3. Figure [*] (p [*]) by Melissa McKenney.
  4. Figure [*] (p [*]) by Melissa McKenney.
  5. Figure [*] (p [*]) by Melissa McKenney.
  6. Figure [*] (p [*]) by Melissa McKenney.
  7. Figure [*] (p [*]) by Melissa McKenney.
  8. Figure [*] (p [*]) by Melissa McKenney.
  9. Figure [*] (p [*]) by Kornilios Kourtis.
  10. Figure [*] (p [*]) by Kornilios Kourtis.
  11. Figure [*] (p [*]) by Kornilios Kourtis.
  12. Figure [*] (p [*]) by Melissa McKenney.
  13. Figure [*] (p [*]) by Melissa McKenney.
  14. Figure [*] (p [*]) by Melissa McKenney.
  15. Figure [*] (p [*]) by Melissa McKenney.
  16. Figure [*] (p [*]) by David Howells.
  17. Figure [*] (p [*]) by David Howells.
  18. Figure [*] (p [*]) by David Howells.
  19. Figure [*] (p [*]) by David Howells.
  20. Figure [*] (p [*]) by David Howells.
  21. Figure [*] (p [*]) by David Howells.
  22. Figure [*] (p [*]) by David Howells.
  23. Figure [*] (p [*]) by David Howells.
  24. Figure [*] (p [*]) by David Howells.
  25. Figure [*] (p [*]) by David Howells.
  26. Figure [*] (p [*]) by David Howells.
  27. Figure [*] (p [*]) by David Howells.
  28. Figure [*] (p [*]) by David Howells.
  29. Figure [*] (p [*]) by Melissa McKenney.
  30. Figure [*] (p [*]) by Melissa McKenney.
  31. Figure [*] (p [*]) by Melissa McKenney.
  32. Figure [*] (p [*]) by Kornilios Kourtis.

Paul E. McKenney 2011-12-16
perfbook_html/node455.html0000644000175000017500000000712011672746163015651 0ustar paulmckpaulmck E.8.3 NMIs From Dynticks-Idle Mode


E.8.3 NMIs From Dynticks-Idle Mode

Figure: NMIs From Dynticks-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_nmi_enter(void)
2 {
...
...ATELIMIT(rdtp->dynticks_nmi & 0x1, &rcu_rs);
24 }\end{verbatim}
}\end{figure}

Figure [*] show the rcu_nmi_enter() and rcu_nmi_exit() functions, which inform RCU of NMI entry and exit, respectively, from dynticks-idle mode. However, if the NMI arrives during an irq handler, then RCU will already be on the lookout for RCU read-side critical sections from this CPU, so lines 6 and 7 of rcu_nmi_enter and lines 19 and 20 of rcu_nmi_exit silently return if dynticks is odd. Otherwise, the two functions increment dynticks_nmi, with rcu_nmi_enter() leaving it with an odd value and rcu_nmi_exit() leaving it with an even value. Both functions execute memory barriers between this increment and possible RCU read-side critical sections on lines 11 and 21, respectively.



Paul E. McKenney 2011-12-16
perfbook_html/node241.html0000644000175000017500000000455111672746162015646 0ustar paulmckpaulmck 14.3.2 Hazard Pointers


14.3.2 Hazard Pointers

@@@ combination of hazard pointers and RCU to eliminate memory barriers?



Paul E. McKenney 2011-12-16
perfbook_html/node188.html0000644000175000017500000000463711672746162015665 0ustar paulmckpaulmck 14.1 Avoiding Locks


14.1 Avoiding Locks

List the ways: RCU, non-blocking synchronization (notably simpler forms), memory barriers, deferred processing.

@@@ Pull deferral stuff back to this section?



Paul E. McKenney 2011-12-16
perfbook_html/node154.html0000644000175000017500000001477011672746162015655 0ustar paulmckpaulmck 10.3.4 ``Toy'' RCU Implementations


10.3.4 ``Toy'' RCU Implementations

The toy RCU implementations in this section are designed not for high performance, practicality, or any kind of production use, but rather for clarity. Nevertheless, you will need a thorough understanding of Chapters [*], [*], [*], [*], and [*] for even these toy RCU implementations to be easily understandable.

This section provides a series of RCU implementations in order of increasing sophistication, from the viewpoint of solving the existence-guarantee problem. Section [*] presents a rudimentary RCU implementation based on simple locking, while Section [*] through [*] present a series of simple RCU implementations based on locking, reference counters, and free-running counters. Finally, Section [*] provides a summary and a list of desirable RCU properties.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node220.html0000644000175000017500000000606611672746162015646 0ustar paulmckpaulmck 14.2.10.2 Implicit Memory Barriers

14.2.10.2 Implicit Memory Barriers

There are a couple of types of implicit memory barriers, so called because they are embedded into locking primitives:

  1. LOCK operations and
  2. UNLOCK operations.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img83.png0000644000175000017500000000036711672745771015247 0ustar paulmckpaulmckPNG  IHDRvui-PLTEMJK# b``mkkXUV856wuv.*+stRNS@fxIDATc`@\@$^Pƀ@." & @!a#```^­ `f3 000McPI/`yMKԋ,mIENDB`perfbook_html/node329.html0000644000175000017500000000623011672746163015652 0ustar paulmckpaulmck D.1.1.1 Abolish Asynchronous Grace-Period APIs


D.1.1.1 Abolish Asynchronous Grace-Period APIs

The problem with the call_rcu() API is that a single thread can generate an arbitrarily large number of blocks of memory awaiting a grace period, as illustrated by the following:



 1 while (p = kmalloc(sizeof(*p), GFP_ATOMIC))
 2   call_rcu(&p->rcu, f);


In contrast, the analogous code using synchronize_rcu() can have at most a single block of memory per thread awaiting a grace period:



 1 while (p = kmalloc(sizeof(*p),
 2                    GFP_ATOMIC)) {
 3   synchronize_rcu();
 4   kfree(&p->rcu, f);
 5 }


Therefore, SRCU provides an equivalent to synchronize_rcu(), but not to call_rcu().



Paul E. McKenney 2011-12-16
perfbook_html/node412.html0000644000175000017500000000600311672746163015641 0ustar paulmckpaulmck D.4.2.3 Grace-Period State Machine


D.4.2.3 Grace-Period State Machine

This section gives an overview of the states executed by the grace-period state machine, and then walks through the relevant code.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node169.html0000644000175000017500000001645011672746162015660 0ustar paulmckpaulmck 11.1.2 Implementation

11.1.2 Implementation

Figure: RCU and Per-Thread Statistical Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct countarray {
2 unsigned...
...x);
68 synchronize_rcu();
69 free(capold);
70 }\end{verbatim}
}\end{figure}

Lines 1-4 of Figure [*] show the countarray structure, which contains a ->total field for the count from previously exited threads, and a counterp[] array of pointers to the per-thread counter for each currently running thread. This structure allows a given execution of read_count() to see a total that is consistent with the indicated set of running threads.

Lines 6-8 contain the definition of the per-thread counter variable, the global pointer countarrayp referencing the current countarray structure, and the final_mutex spinlock.

Lines 10-13 show inc_count(), which is unchanged from Figure [*].

Lines 15-29 show read_count(), which has changed significantly. Lines 21 and 27 substitute rcu_read_lock() and rcu_read_unlock() for acquisition and release of final_mutex. Line 22 uses rcu_dereference() to snapshot the current countarray structure into local variable cap. Proper use of RCU will guarantee that this countarray structure will remain with us through at least the end of the current RCU read-side critical section at line 27. Line 23 initializes sum to cap->total, which is the sum of the counts of threads that have previously exited. Lines 24-26 add up the per-thread counters corresponding to currently running threads, and, finally, line 28 returns the sum.

The initial value for countarrayp is provided by count_init() on lines 31-39. This function runs before the first thread is created, and its job is to allocate and zero the initial structure, and then assign it to countarrayp.

Lines 41-48 show the count_register_thread() function, which is invoked by each newly created thread. Line 43 picks up the current thread's index, line 45 acquires final_mutex, line 46 installs a pointer to this thread's counter, and line 47 releases final_mutex.

Quick Quiz 11.3: Hey!!! Line 45 of Figure [*] modifies a value in a pre-existing countarray structure! Didn't you say that this structure, once made available to read_count(), remained constant??? End Quick Quiz

Lines 50-70 shows count_unregister_thread(), which is invoked by each thread just before it exits. Lines 56-60 allocate a new countarray structure, line 61 acquires final_mutex and line 67 releases it. Line 62 copies the contents of the current countarray into the newly allocated version, line 63 adds the exiting thread's counter to new structure's total, and line 64 NULLs the exiting thread's counterp[] array element. Line 65 then retains a pointer to the current (soon to be old) countarray structure, and line 66 uses rcu_assign_pointer() to install the new version of the countarray structure. Line 68 waits for a grace period to elapse, so that any threads that might be concurrently executing in read_count, and thus might have references to the old countarray structure, will be allowed to exit their RCU read-side critical sections, thus dropping any such references. Line 69 can then safely free the old countarray structure.

Paul E. McKenney 2011-12-16
perfbook_html/node213.html0000644000175000017500000001441511672746162015645 0ustar paulmckpaulmck 14.2.9 Guarantees


14.2.9 Guarantees

There are some minimal guarantees that may be expected of a CPU:

  1. On any given CPU, dependent memory accesses will be issued in order, with respect to itself. This means that for:



    Q = P; D = *Q;
    


    the CPU will issue the following memory operations:



    Q = LOAD P, D = LOAD *Q
    


    and always in that order.

  2. Overlapping loads and stores within a particular CPU will appear to be ordered within that CPU. This means that for:



    a = *X; *X = b;
    


    the CPU will only issue the following sequence of memory operations:



    a = LOAD *X, STORE *X = b
    


    And for:



    *X = c; d = *X;
    


    the CPU will only issue:



    STORE *X = c, d = LOAD *X
    


    (Loads and stores overlap if they are targetted at overlapping pieces of memory).

  3. A series of stores to a single variable will appear to all CPUs to have occurred in a single order, thought this order might not be predictable from the code, and in fact the order might vary from one run to another.

And there are a number of things that must or must not be assumed:

  1. It must not be assumed that independent loads and stores will be issued in the order given. This means that for:



    X = *A; Y = *B; *D = Z;
    


    we may get any of the following sequences:



    X = LOAD *A,   Y = LOAD *B,  STORE *D = Z
    X = LOAD *A,   STORE *D = Z, Y = LOAD *B
    Y = LOAD *B,   X = LOAD *A,  STORE *D = Z
    Y = LOAD *B,   STORE *D = Z, X = LOAD *A
    STORE *D = Z,  X = LOAD *A,  Y = LOAD *B
    STORE *D = Z,  Y = LOAD *B,  X = LOAD *A
    


  2. It must be assumed that overlapping memory accesses may be merged or discarded. This means that for:



    X = *A; Y = *(A + 4);
    


    we may get any one of the following sequences:



    X = LOAD *A; Y = LOAD *(A + 4);
    Y = LOAD *(A + 4); X = LOAD *A;
    {X, Y} = LOAD {*A, *(A + 4) };
    


    And for:



    *A = X; Y = *A;
    


    we may get either of:



    STORE *A = X; Y = LOAD *A;
    STORE *A = Y = X;
    


Paul E. McKenney 2011-12-16
perfbook_html/node269.html0000644000175000017500000000527011672746162015657 0ustar paulmckpaulmck B.1 Organization and Initialization


B.1 Organization and Initialization

@@@ currently include ../api.h, and there is only pthreads. Expand and complete once the CodeSamples structure settles down.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img325.png0000644000175000017500000001020411672746014015304 0ustar paulmckpaulmckPNG  IHDRcI?PLTEb``^\\\ZZMJK# hffmkkXUV856iffC@@wuv.*+a!tRNS@fIDATx]*[PPso;Yj9u >!2iEEB];];! E륆aNߎM=S2Bj/A;>WfJfퟸ}[d/vGÃ<x)$ "4Ry<sکd'd^h|4B[L&rk(.!,``=n~FyX@h0w4sGL w:<y) ),.d[.KaK)d2W"Ci HS]BťT}k#9ߕÃH am :rs-Re6(:oAti/ek:ZU|.كՍ&iDSj!qвb\C.Ŋ'vжl^# ka3k4Q |* [?Y ifs={.lՎ'|kp(F Y#31)ݞ6kv$pHmtI*Rv ta# i p?sK4k 7?ɬǰԿNoB3*yFAgGkM~;U>້}lq3 p vaפ.ҹYBEd0)م)JY4Y|z@ҡgH0GX/Ff'6lfUćsQDǀnMJ,k墓wCD?Ք&@,4B}AXgs[eV4XS/MhKҷd*J-PiB D˭npطT miflӢ GV((nӒ'RB+B!;GBl l8ͦcͶzA8)w9^ ?w7I?@r2vZt=hD';}1I0)k-i HZ/`^g>A!8efl)pX!QܹEL̓w?ﮤW&48B5#2+d{].KZ%tKWN 8!̵nyl8512:Q157H8Hg8wb|~w s\>{ܛR'|oBD{b('w\2<_‚K/f${ccd~Dʹ:a2GHըԙm)s ;B#퓫/}&{սcsFVk}z>--* ?@jRIbiBSAU0ycM$D0FKNh)',#3s'@O-g٬].lkNW`J<`Ŷ޽%iw<-S'q&w)_niUCvH;]|/D@6gJFy7IsF\fPDmbrŬwܹ0 |^EW'$oHi4: [cf:Ňڌ˖ypȾ`/d;D Ľ poCF!);L2佡 g 6)x9áx:bYVKD7w)"7IF;7ٯ >ʭeV lc!be(W> onLQxBj5wMW.@ձ~X]+N:`ִ| \\ՏSrţK(ϹlJ|W5ʛIm⻪ٗ(o&*]໪/PQ!V+|;lhNȻ櫻(woXJRz7f59ueW Y8+sd0R Ftk,zba򀽙Z+ԄB'8,bjd˜խ!w];dS`lf9Ăe9{knW M*l6Ţ<vzd} K&8>EN|;;`%Dϓz?J4N/7W8V1_S)ǷHwr2DK0jxWe-Wwś]2\P4d ``9_ 7ukzE˯hiWI ;,:SdYb9Z⭗^9ذ2e> Ft+k5BT"Ac/ej/,,=>93 X>i p|Ga{VxQceYTJ}BE@u{|E;^و_ms1籓q=W5@Kl/u.OmRրwO7Hryɜ)/ GM+w]E.W26?}Bɟ[|N_(ot(~mǬR 8n)-nC6IENDB`perfbook_html/footnode.html0000644000175000017500000004702411672746164016313 0ustar paulmckpaulmck Footnotes
... sanity.2.1
Or, perhaps more accurately, without much greater risk to your sanity than that incurred by non-parallel programming. Which, come to think of it, might not be saying all that much. Either way, Appendix [*] discusses some important questions whose answers are less intuitive in parallel programs than in sequential program.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... CPUs.3.1
This plot shows clock frequencies for newer CPUs theoretically capable of retiring one or more instructions per clock, and MIPS for older CPUs requiring multiple clocks to execute even the simplest instruction. The reason for taking this approach is that the newer CPUs' ability to retire multiple instructions per clock is typically limited by memory-system performance.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... optimizations.3.2
Of course, if you are a hobbyist whose primary interest is writing parallel software, that is more than enough reason to parallelize whatever software you are interested in.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... functions.7.1
One could easily create a polymorphic implementation in any number of languages, but doing so is left as an exercise for the reader.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... non-interruptible7.2
Either by masking interrupts or by being oblivious to them.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... interrelationships.7.3
A real-world parallel system will be subject to many additional design criteria, such as data-structure layout, memory size, memory-hierarchy latencies, and bandwidth limitations.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... parallelism.7.4
This plot shows clock frequencies for newer CPUs theoretically capable of retiring one or more instructions per clock, and MIPS for older CPUs requiring multiple clocks to execute even the simplest instruction. The reason for taking this approach is that the newer CPUs' ability to retire multiple instructions per clock is typically limited by memory-system performance.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... point.7.5
The examples in this section are taken from Hart et al. [HMB06], adapted for clarity by gathering code related code from multiple files.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... locks.7.6
If your program instead has locks in data structures, or, in the case of Java, uses classes with synchronized instances, you are instead using ``data locking'', described in Section [*].
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... loop.7.7
Of course, if there are 8 CPUs, each CPU must wait 175 nanoseconds for each of the other CPUs to do its increment before consuming an additional 25 nanoseconds doing its own increment.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... empty.7.8
Both pool sizes (TARGET_POOL_SIZE and GLOBAL_POOL_SIZE) are unrealistically small, but this small size makes it easier to single-step the program in order to get a feel for its operation.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... results7.9
This data was not collected in a statistically meaningful way, and therefore should be viewed with great skepticism and suspicion. Good data-collection and -reduction practice is discussed in Chapter @@@. That said, repeated runs gave similar results, and these results match more careful evaluations of similar algorithms.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... mobile.8.1
And, in contrast to the 1900s, mobility is the common case.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... quickly).10.1
Thanks to James Bottomley for urging me to this formulation, as opposed to simply saying that there are no forward-progress guarantees.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... properties.14.1
Or, better yet, you can avoid explicit use of memory barriers entirely. But that would be the subject of other sections.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... order.14.2
Of course, this order might be different from one run to the next. On any given run, however, all CPUs and threads must have a consistent view of the order of critical sections for a given exclusive lock.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... consistent.14.3
A given CPU's series may of course be incomplete, for example, if a given CPU never loaded or stored the shared variable, then it can have no opinion about that variable's value.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... B,14.4
For example, by executing the store to A, a memory barrier, and then the store to B.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... A,14.5
For example, by executing the load from B, a memory barrier, and then the load from A.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... persists.14.6
Or, for the more competitively oriented, the first CPU's store to B ``wins''.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... hardware14.7
This is of concern primarily in operating-system kernels. For more information on hardware operations and memory ordering, see the files pci.txt, DMA-mapping.txt, and DMA-API.txt in the Documentation directory in the Linux source tree [Tor03].
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... type.14.8
By ``weaker'', we mean "makes fewer ordering guarantees". A weaker barrier is usually also lower-overhead than is a stronger barrier.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... caches,14.9
But note that in ``superscalar'' systems, the CPU might well be accessing both halves of its cache at once, and might in fact be performing multiple concurrent accesses to each of the halves.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... set'',15.1
Due to Josh Triplett.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... frequently.15.2
Those of you with strong operating-system backgrounds, please suspend disbelief. If you are unable to suspend disbelief, send us a better example.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... operations.17.1
This difficulty was pointed out by Michael Factor.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... implications.17.2
This difference between mapping and unmapping was noted by Josh Triplett.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... attributes.17.3
Thanks to Mark Moir for pointing me at this spec, and to Michael Wong for having pointed me at an earlier revision some time back.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... implementations.17.4
Kudos to the TxLinux group, Maged Michael, and Josh Triplett for coming up with a number of the above alternatives.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... control.B.1
There are many other names for similar software constructs, including ``process'', ``task'', ``fiber'', ``event'', and so on. Similar design principles apply to all of them.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... state,B.2
How is that for a circular definition?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... cycles.C.1
It is standard practice to use multiple levels of cache, with a small level-one cache close to the CPU with single-cycle access time, and a larger level-two cache with a longer access time, perhaps roughly ten clock cycles. Higher-performance CPUs often have three or even four levels of cache.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... states,C.2
See Culler et al. [CSG99] pages 670 and 671 for the nine-state and 26-state diagrams for SGI Origin2000 and Sequent (now IBM) NUMA-Q, respectively. Both diagrams are significantly simpler than real life.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... time.C.3
The time required to transfer a cache line from one CPU's cache to another's is typically a few orders of magnitude more than that required to execute a simple register-to-register instruction.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... architecture.C.4
Readers preferring a detailed look at real hardware architectures are encouraged to consult CPU vendors' manuals [SW95,Adv02,Int02b,IBM94,LSH02,SPA94,Int04b,Int04a,Int04c], Gharachorloo's dissertation [Gha95], or Peter Sewell's work [Sew].
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... see.C.5
Any real hardware architect or designer will no doubt be loudly calling for Ralph on the porcelain intercom, as they just might be just a bit upset about the prospect of working out which queue should handle a message involving a cache line that both CPUs accessed, to say nothing of the many races that this example poses. All I can say is ``Give me a better example''.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... up.C.6
Of course, the astute reader will have already recognized that Alpha is nowhere near as mean and nasty as it could be, the (thankfully) mythical architecture in Section [*] being a case in point.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
...synchronize_srcu().D.1
For example, an SRCU-protected hash table might have a lock per hash chain, thus allowing at most one block per hash chain to be waiting for synchronize_srcu().
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... once,D.2
Please note that, despite the name, barrier() has absolutely no effect on the CPU's ability to reorder execution of both code and of memory accesses.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... CPU.D.3
It is important to note that the smp_processor_id() primitive has long-term meaning only if preemption is disabled. In absence of preemption disabling, a potential preemption immediately following execution of this primitive could cause the subsequent code to execute on some other CPU.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
...CONFIG_SMP,D.4
For non-CONFIG_SMP, force_quiescent_state is a simple wrapper around set_need_resched().
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... purchased.F.1
Yes, this sudden realization did cause him to walk quite a bit more carefully. Why do you ask?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... close.F.2
Parallel programming is in some ways more difficult than sequential programming, for example, parallel validation is more difficult. But no longer mind-crushingly difficult.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
... setG.1
In hardware-cache terminology, the word ``set'' is used in the same way that the word ``bucket'' is used when discussing software caches.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
perfbook_html/node36.html0000644000175000017500000001305111672746161015562 0ustar paulmckpaulmck 4.3.1 3D Integration


4.3.1 3D Integration

3-dimensional integration (3DI) is the practice of bonding very thin silicon dies to each other in a vertical stack. This practice provides potential benefits, but also poses significant fabrication challenges [Kni08].

Figure: Latency Benefit of 3D Integration
\resizebox{3in}{!}{\includegraphics{cpu/3DI}}

Perhaps the most important benefit of 3DI is decreased path length through the system, as shown in Figure [*]. A 3-centimeter silicon die is replaced with a stack of four 1.5-centimeter dies, in theory decreasing the maximum path through the system by a factor of two, keeping in mind that each layer is quite thin. In addition, given proper attention to design and placement, long horizontal electrical connections (which are both slow and power hungry) can be replaced by short vertical electrical connections, which are both faster and more power efficient.

However, delays due to levels of clocked logic will not be decreased by 3D integration, and significant manufacturing, testing, power-supply, and heat-dissipation problems must be solved for 3D integration to reach production while still delivering on its promise. The heat-dissipation problems might be solved using semiconductors based on diamond, which is a good conductor for heat, but an electrical insulator. That said, it remains difficult to grow large single diamond crystals, to say nothing of slicing them into wafers. In addition, it seems unlikely that any of these technologies will be able to deliver the exponential increases to which some people have become accustomed. That said, they may be necessary steps on the path to the late Jim Gray's ``smoking hairy golf balls'' [Gra02].

Paul E. McKenney 2011-12-16
perfbook_html/img137.png0000644000175000017500000001173211672745777015333 0ustar paulmckpaulmckPNG  IHDRB*0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fXIDATx]}u?o}ٶD(VzBV1UU"* l$HQµ<0vuH 84P()/Fu6 !GR ei2ݲ$f̽3wv]?kfg=w|܏sgg s86kJHBjNePP5EQݘKGeX4\Rm1\~#J0"kHl͈zvaJsp+M[Xkpr+gDO,5JAC&`|xi@)F7,Vrg5V5@( < ")oʪNTZc-YEfWUl! -Yč WԦwT!`W+kӽ2-9ʭY\턪<~5oE2 &ݽ_d'ڌD3as.Ƣ~_ifƥƧ߼*f%J7!./WDq<Ԧ^uۖ!ϔ wgU4  Uķ[OyY%  ߘ嚌"CG eUs$ #XWm* AkL'jR{N=ҠWuI=BGHSTJzPn]a+FpdJx\=$qH{.dXd–u9Bȹ-,zq7W*P:\G؇Hx> {VceL]Ki #ĴYT8p.~0dv7Jʷ`~ˉ85,'o5\:?0ܒ>y߈~GA5Ąҡ:raBi3(w)%܁RUb.ҁ! &@O7._H/rI E (RO!/oc#kQ}_ P^/OFg\[̘L?BoSf $y3ͼT;_ʅW_0saȃO̜ ap PA*y ,HDpC3> hpݯL"|5ԌmnXQlJ(1u)$#%s8TvDGz}gZ{`\5]3|}f0~UE4^~+b:&Hly>Y-PJ2Tn~57sE-sSO_pЯq{ Rv7h>2Xh'v._V?1*T: yBR(dk +&F-BMkAbM9&REM$e%z* ܸ>nH|4~aûw}ֶ\;WcA̦sFU|j:ר&FL`!j jex _Z&Y?UY6L!3^Q@r2QFr2ʁߐ迼0Ym>!)XhPLfcd|E7k5LV۟erbdN8WhF333^L*<391NVhg3aΤgOTg X.D3@ƴ3.ZYU '˪5̜NH3YG!/c$nX%=_Z>k9d8pƲj)ČdH!4}ױg;l/8,+W wpڙvI 5;R^)|$^9sO2Y!IΊp ##|/C0aYAUv- a,k~m򦞖K"OF%Mx1˚S[˚-j1aڶ02/&-͹oͥ1vtC4 ²鿔>D*'u-}jXV_m^:jч#B kcD:KZj>1jL51*9 cԩ͵rfLǍe-?JOU1ddtS1S(GYV(l Y>0DFHfqCF'VGb2zct)ysY#wM9Q# '_"ǘ͘fY\$c #1a-(H|K3bLR(HIu1JnBZF(WJƈQ\)ͱi/]QW!wz/Q|}S__ocսC@ػ$M?Vj/|>*JߚZu`w83ibEf;+8~h%GIO`@NSP++ Uo+aꩪY0*x p SePaii'!Sip:]tiW?Y\ʦ+8^C|exOwWa\PTeex|K-`>NHylH9[:Oo(uXU,u WGDcFs/ط}=QbgVu)[F+ Q;<S}zhGm.TM8莃jm= K_~wA!lkpt- zZ yHW3$TOHӥ|ȱ:o-Mז~}Hi]'˶f4ZzDZsb="Y>#K(`ʓsw1[፝'pkYيeH@님`PC^X^L>1[AD+Eb V|)?̀4 %*!VvJo&gXxTt@e[lMcԙ [duAR7Wt(2mgp!rvnMj7h47g ne7duSH{x``,ZyTRk1Xf+hU f $p`2[x{!jnXxqwo1 _j&zͣ x?;[#潕;sGrX,eSb7!1*CxG]o#-=,bLCy]J?$VG[j֘ ILU^" Rm釄H7Ycl\@}ϲ&V#nY%T]k}ONk4/|}j;. á;=(v'Hr!ݮ#ު*3$g".@Jp /ne`p'fgfWL1 7$L<~>؎#< 8<:_j~x%uIN~$*[X5FHw5aqHUY]`j&) %H7CRSV讞{ ?&%Ek5.)ď8 tIXEQ smX@=8EhC3R} (v<$S?v\!q=|KN eayHy?lvg"3OuV~-u>e+>eCFDIN|0KqK2ݲ nWPJJrNIENDB`perfbook_html/node100.html0000644000175000017500000001514211672746162015636 0ustar paulmckpaulmck 7.4.3.7 Real-World Design

7.4.3.7 Real-World Design

The toy parallel resource allocator was quite simple, but real-world designs expand on this approach in a number of ways.

First, real-world allocators are required to handle a wide range of allocation sizes, as opposed to the single size shown in this toy example. One popular way to do this is to offer a fixed set of sizes, spaced so as to balance external and internal fragmentation, such as in the late-1980s BSD memory allocator [MK88]. Doing this would mean that the ``globalmem'' variable would need to be replicated on a per-size basis, and that the associated lock would similarly be replicated, resulting in data locking rather than the toy program's code locking.

Second, production-quality systems must be able to repurpose memory, meaning that they must be able to coalesce blocks into larger structures, such as pages [MS93]. This coalescing will also need to be protected by a lock, which again could be replicated on a per-size basis.

Third, coalesced memory must be returned to the underlying memory system, and pages of memory must also be allocated from the underlying memory system. The locking required at this level will depend on that of the underlying memory system, but could well be code locking. Code locking can often be tolerated at this level, because this level is so infrequently reached in well-designed systems [MSK01].

Despite this real-world design's greater complexity, the underlying idea is the same -- repeated application of parallel fastpath, as shown in Table [*].


Table: Schematic of Real-World Parallel Allocator
Level Locking Purpose
Per-thread pool Data ownership High-speed allocation
Global block pool Data locking Distributing blocks among threads
Coalescing Data locking Combining blocks into pages
System memory Code locking Memory from/to system


Paul E. McKenney 2011-12-16
perfbook_html/node107.html0000644000175000017500000000425411672746162015647 0ustar paulmckpaulmck 8.1.4 Inefficiency


8.1.4 Inefficiency



Paul E. McKenney 2011-12-16
perfbook_html/node16.html0000644000175000017500000001230311672746161015557 0ustar paulmckpaulmck 3.4.2 Parallel Access Control


3.4.2 Parallel Access Control

Given a sequential program with only a single thread, that single thread has full access to all of the program's resources. These resources are most often in-memory data structures, but can be CPUs, memory (including caches), I/O devices, computational accelerators, files, and much else besides.

The first parallel-access-control issue is whether the form of the access to a given resource depends on that resource's location. For example, in many message-passing environments, local-variable access is via expressions and assignments, while remote-variable access uses an entirely different syntax, usually involving messaging. The POSIX threads environment [Ope97], Structured Query Language (SQL) [Int92], and partitioned global address-space (PGAS) environments such as Universal Parallel C (UPC) [EGCD03] offer implicit access, while Message Passing Interface (MPI) [MPI08] offers explicit access because access to remote data requires explicit messaging.

The other parallel access-control issue is how threads coordinate access to the resources. This coordination is carried out by the very large number of synchronization mechanisms provided by various parallel languages and environments, including message passing, locking, transactions, reference counting, explicit timing, shared atomic variables, and data ownership. Many traditional parallel-programming concerns such as deadlock, livelock, and transaction rollback stem from this coordination. This framework can be elaborated to include comparisons of these synchronization mechanisms, for example locking vs. transactional memory [MMW07], but such elaboration is beyond the scope of this section.

Paul E. McKenney 2011-12-16
perfbook_html/img19.png0000644000175000017500000002046311672746001015230 0ustar paulmckpaulmckPNG  IHDRW%av6PLTEgggMMM''' tttZZZVVV@@@444ftRNS@f IDATx]FTp!" XfYm%߈\@XeL4R[_cBuR"෦>ȿMYҹ]-u+A L;1lNRFG"U˔srW>*YgIPʌuVX;9o&!UBusMOJ:O׶\w׹3$'FG{]-ӕ1u]R)y'oŹ$Ƒf(W*V-BbB4+!Ab$Ѵlǚꚮm1[ou9%$$u_s?4AZRJտSswB~&SN"}YZ226Sdu@u[>2'J*tSUKT,wrڙ^IRHƸ뎄$LyCޛĽ^?׾麓Nx\VR3^2WR7whk QPI(iZUًy4DtS6PF fHCeG>nI/Rd+0FJ;}Dd'NoE$Ku@V?^YUo<{lfza6_|S і.#UCcTZm2~t{~y֋*5>^NQʆ'5N#yoz /}|Kuy#;b)6?]%yub𐩨E*HҼf^+7%ِܕv^e.$$qCvKBPG:k5Ij ?bͮɹ[[K$#N/蓻+^ˌӖM˄9x6 YX.eJ5[5몎QWX4~WÖ/n}]}ƛ b^ фk&{R}R(7 ]zݽ@l8KAXLwߚo}z|+^n %Sލb*FΦ PK:W>ɶn^`a0Lp-bT|j4Gr*M$x إ'* Ƹ5MXR6/훌[!^͚{.Xϕ~bE{NwXk5m~)m'vdvp̷L{Z5^& zfGC ^ 202#]yf</;t1Y7m.cCm͟Y/܃Jh-`fJ5h'Z9'^ X=m4P2^[3b.GՇ`A%0-c{ɃX0EM'l.'feżr$X}x_n٭BΓl-,bVP ?Y$xNQ oêY#n+PDA k (]7{ Xx Ā>B3&?1'&if`buDa;`%fov\}*lKDФf//n~TuP?t51{K`gR&ەk >="t1 6xKC/k]Ok`D70$Z1bog҂ 8 Åt=s0X4H.M}ZQcH6 2je^> ^c,* `7uv7R@(c̟0>?H'kT\Q`]@"[@o,KY0UO8#}V0cv-}X"%ﱓ %By%f4ҍdb: %G9%Ik9D(Y䈄mWϭ"F8̂f$] "q6̃H0U$nk=)g﯅*r,Y _ `vmy&ܴmHf1#ŚM=N X/jff8ͽN.zܥ3S άh`urI|by `wś9ݕjvY?ct v|Z۴3[K:[0H-Ξ%{e<{O!=djmʣ[}!e I0AEdDAubh;Ru a,l *ʎ+ lͮ; 6'vhʴҀ= K|+8?vwFk֐kgz5fE6!X Pf, 2` +#5%P]:V0.P(v~hi\~ԵE#mSw,]׃w|w/f3d~[KQq ZFa%&gExcO>NlOdr'?U@&8n. $eA 9z]AV)ۖ8f5QOC Y-VԼL/h6*BG ]Y-sKGN9 MBʺb!3EԟnXv$G4:6(ͬ9#+b:gzB+IQ k3ynvRVmJ/<`lky;z5 "kʰBWH ubΓ{gF g2eތz=چu?}:.2D km,z4/=K9֝XNspRϓN]*J=R7!WH?LUFFf\~s'z m/caONN'2K{An]X̺:{At[|0k`9֎ - n0_̏0]R\RHG#pcH2fyU,yXSEDoڥ22H& V ZcP^^q͍E Բ|ZzxeREbj*%JXJthk2X;M- 8G^*֗A컕2nXZ&_2L;6+1W9(cMSߗQB99 +>0*tpU>$ >sƦRwFvf;B3՞Uh,J?st(vKBd6kcckAex2`:+UԵ3Qi=~[e@*6ꐨ ml.^kViHcy ){jL؝8`P%]b[B iDCS{ţ &jDV4|owk?= 뎂+ZGtq)>+~[ú/F?8IXO uǸ5#5X-!ȁy{c qdk?!m"-vq+6ō*\߭ &ڬ,үaNpnX&|mK*U-Ǫ^K/~2G +ȝd8fd XkpCWUGzB:;[vm<\5ZM?,yj-2>ҋ`޲sXgVEX,0}xqhU:Vtvs0ħ.|;}%ƺę|"V;M&XMڬ,X=]z>C=P@W N$iu' aߗ~C=PCjo eF/*3/78h:4x3 4Kiq#͂y}2M㋛%AD?! AnǦe t0 Bf ˵`vJ&:Ȥ4պd6v7Z]B=tWt@cSX5vJc&s KE$X!C΄.>'$+ԁ1Z!V0B$n,Z?昮^oVtbaK[e 83QOL}W>i aŅVq L;%A1f"c{ iIw%EoJ]=z$Q t`逐EPU?)11;cPkBhWC4Y qf^TgP}r$z"K-9|#qQVgrRCp[d,\D/J誶2.37(٧W$נ(K[g।z%^"2eT6+L_Qƅ^RO(@Ш' 2RRO֫;[ௌ~T1DTl0ى'IERR=i"reM"9P*].ނD5r&ѠuDZ&zNmcOJ zȔ!HE۠ɉQg#qCG;7d|#qCƻc zS7X#qCƔ^kU\kftq9L>~Ԅ^'Ot']-1ˆa6}Ԩ6˄g;1<㰷@#pCJp Ly aFpD~2xgvRFȍ߲#Eu^xlv*A.:^/YVeZ4F0ۖI?CG,e{!v*p5Zf\Q׃hG↌W׋'sBZ=mb;IRSsע,(K^z~BZfq&u7+W*t^? J`:pnXT~wB!ExBwnf/ֵU,.ܕ+(-Hp˖"v$nuG↌^w$nuG↌^w$nȘЫ; MNR蘴8wR#x2u>-[Ϋ <>V)rfLwH٥\kE^R#rLd,\D NUx`u(j(ql 5%5B7]܋2(yuUqW(Hy#Wux)˧N+"S+ǾW"N; TCΪ+ii}MI 0v`."Wӻϋ˫I4~^RBx)8mx-c夦Q|reK;7d|#qCG;7d(nYAGУkή!5跦=z衇z ~^CVrjD>J=2xzS}^CVz衇uʜ:MxbIXk&LgBf· 0@Uyƅh7I٫6J)ɻCX `2]-Ǣ'φU`r fl%"ڔԘ幓Fw0Ѳ eN! tU09g3߮;2W `n ylrR7/;hSEs"Q\ЬW!KT #II SF" ҝde&.=᳟KN ;~6G>\~W7rd לHz 3DC EVkrұڼ!4ktH:S(w0٫Եs5rъ9XTJYp2P* JU#KQ ֐/oN(JUe—G"yzi{Qk7:Zf2}EQՂ裤fˤ$˝Az,ڼ&,TFBCH͡G-b.n]PE7.œa\wżtTU@X:lS8Y*(*yTjeAE 6F޷'\&'/4k£9 R^PЫ "V3:dKeei!)^Fj*wHݧ ճYFЫQ9Y^2z '.pz\IDAT~+ ?C1w$3 )9JASlo9 V ծv= z Dg~Ы +̮0 *^џ.n٠*)DTVAi֕gУ,.0,/+qugj;fۚF?ɆIENDB`perfbook_html/node230.html0000644000175000017500000000706611672746162015650 0ustar paulmckpaulmck 14.2.12 Memory-Barrier Examples


14.2.12 Memory-Barrier Examples



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node281.html0000644000175000017500000000475411672746162015657 0ustar paulmckpaulmck B.3.2 spin_lock()

B.3.2 spin_lock()

The spin_lock() primitive acquires the specified spinlock, if necessary, waiting until the spinlock becomes available. In some environments, such as pthreads, this waiting will involve ``spinning'', while in others, such as the Linux kernel, it will involve blocking.

The key point is that only one thread may hold a spinlock at any given time.



Paul E. McKenney 2011-12-16
perfbook_html/img35.png0000644000175000017500000000367311672746126015242 0ustar paulmckpaulmckPNG  IHDRfj ?PLTE^\\MJK# b``mkkXUV856KHHC@@wuv.*+tl,tRNS@f*IDATx[£ewϺIŪ-v~gi+CbBqyC+/.}U=_=>UJG6V.nXLVnEpsuw4mC]'?hT*A4-rL't| K]Z,%C*f&)Qꮏ H4Ϧ6 1A}E /cpCl }ښН 巆޺N$YG(jc3Tڤ#%uKҐvאdYJR̂WSVڴ9/>&w}pK:'Hw޵1PX?o?AF{"=9픑\L}9'N/t[Ӓɡdܧ0Lw6li:oEajC9>_=}5h$-$xqBǥX1 N9*VACt$W8cg?=_|";&CQ8C2F*B6X[C3w}!a9ii y5/G*~OMQi?V`g?> #r06oydvܟBߛ#nTr< ~~M1Nu0t?o;36}N̚3Kʓj&? ^d%$>@㲖mr_D6`Bmc`/[xKv}1σws\@۷u2w:\_RIDĶ=^ '.|}v;ط 䂈 ^l< Gfv yys0myzUگPF?>UK?p!}Qǀ3ؾLgDaX|8J-RإI0Y˾҃]% j μ(:f+GFyoLR%GO[gމTFa4UqH}9>ԅ']H*/^^i )!%Oˡ?ȕÚSM٭I{]C?+?rIU\<[񭳒^<|-¼8/ѿE JIENDB`perfbook_html/node74.html0000644000175000017500000001006411672746162015566 0ustar paulmckpaulmck 7.1 Partitioning Exercises


7.1 Partitioning Exercises

This section uses a pair of exercises (the classic Dining Philosophers problem and a double-ended queue) to demonstrate the value of partitioning.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node239.html0000644000175000017500000000577611672746162015667 0ustar paulmckpaulmck 14.3 Non-Blocking Synchronization


14.3 Non-Blocking Synchronization



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node56.html0000644000175000017500000001770611672746161015577 0ustar paulmckpaulmck 6.2.3 Eventually Consistent Implementation


6.2.3 Eventually Consistent Implementation

One way to retain update-side scalability while greatly improving read-side performance is to weaken consistency requirements. While the counting algorithm in the previous section is guaranteed to return a value between the value that an ideal counter would have taken on near the beginning of read_count()'s execution and that near the end of read_count()'s execution. Eventual consistency [Vog09] provides a weaker guarantee: in absence of calls to inc_count(), calls to read_count() will eventually return the correct answer.

We exploit eventual consistency by maintaining a global counter. However, updaters only manipulate their per-thread counters. A separate thread is provided to transfer counts from the per-thread counters to the global counter. Readers simply access the value of the global counter. If updaters are active, the value used by the readers will be out of date, however, once updates cease, the global counter will eventually converge on the true value--hence this approach qualifies as eventually consistent.

Figure: Array-Based Per-Thread Eventually Consistent Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_PER_THREAD(atomic_t, cou...
...lag < 3)
48 poll(NULL, 0, 1);
49 smp_mb();
50 }\end{verbatim}
}\end{figure}

The implementation is shown in Figure [*] (count_stat_eventual.c). Lines 1-2 show the per-thread variable and the global variable that track the counter's value, and line three shows stopflag which is used to coordinate termination (for the case where we want to terminate the program with an accurate counter value). The inc_count() function shown on lines 5-8 is identical to its counterpart in Figure [*]. The read_count() function shown on lines 10-13 simply returns the value of the global_count variable.

However, the count_init() function on lines 34-42 creates the eventual() thread shown on lines 15-32, which cycles through all the threads, using the atomic_xchg() function to remove count from each thread's local counter, adding the sum to the global_count variable. The eventual() thread waits an arbitrarily chosen one millisecond between passes. The count_cleanup() function on lines 44-50 coordinates termination.

This approach gives extremely fast counter read-out while still supporting linear counter-update performance. However, this excellent read-side performance and update-side scalability comes at the cost of high update-side overhead, due to both the atomic operations and the array indexing hidden in the __get_thread_var() primitive, which can be quite expensive on some CPUs with deep pipelines.

Quick Quiz 6.16: Why does inc_count() in Figure [*] need to use atomic instructions? End Quick Quiz

Quick Quiz 6.17: Won't the single global thread in the function eventual() of Figure [*] be just as severe a bottleneck as a global lock would be? End Quick Quiz

Quick Quiz 6.18: Won't the estimate returned by read_count() in Figure [*] become increasingly inaccurate as the number of threads rises? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img63.png0000644000175000017500000001427111672746002015230 0ustar paulmckpaulmckPNG  IHDRXiPLTE$8D6Sf3!!l݌XXVV*3-EUwwfAAQ} c"aaHoD++Z~wLL" wwff?aẃUUDDu33""__llU66&]tRNS@fIDATx] {=QKR 0V{Z!.2J`c$o@36y dyWe yӾJiPT:V%OȄ?p@ڽ7ɮKP̋$y͊mHWɄE#ycu{o-ND֋"i^ne^TkM3o /xRu{o(]I/ig!T#?mJ򢊼=8&ɛN_5#='LoQ)>]s׶QzF7)Sx^7]!7y/{o(k&NdۛrN웠"ݫ 7#vZxĞ;vV"o v q%`ʼk1o)P}^+&[R#wMgzoLbJݳY/yޢ]T΋ y-|ugya=H+qݞj&GN@l0뺾}f6}f _ 3!Ϣܠl^Tu#wUfyu}vG62S)EkgdcUDz(34^f=S7Tf+׹6$lMJbRҌx몢mY36I  $wY#Of854G]W-Ej(G͢卛R;;%/fjԩ`k[j|0Uláv`HWoۡYZjvԏeewYI.C6_,mbd.('xAQv6*Mf#Hϙ?&mnfq5̢cDކ0bYS[-) u=nYWt4Y8AU^ͭi #ooaͺec9iYA2M~gl Y܀jCc6We^NBnS?L3~9{rY?'Ehs %BĭҦ\fVfS;ϖfAן-¥]Y5٪m}Y2}oJ"⹱Xb+` $4L0;xl5ÊNal%ʱE9<.GԎĹ{AI&y61ۆ4;ZXF7 nf c*(%t) vI/d4kVl1( *3`tLD"`:\O[Q;P$l,ڥf=G9c[gCI^f7,}cAaHYd:) nԤfG@ ,+7hs,|0MsL扑h(*+\f)3fJd9]OFmw҄o)e+c@^,Xz?Sh"D&b`8߸W/*٣Iqoy_eM3dI~V% (}];͚zɃ;'y0dnՍ䦁J+c?A5;d|:;ҩ{ JCKdQh 3/NIa>ұЇ+?51(BJ/ЎN r+a$swx"?5d`X5U3~q1?iCV1TY_gttg|t:/ kmxaͷɞɒ ZߙkLf]b4Tb/;YxyvL gdV,#+"O$,LB/4ct>xy*#kbeY|?nz6ՃݗI\l/v! aѮX Eq P4%,La4&Gzbc% pS'ܜl M"ŧ_K4kx #^LI\jwkZitr4hrG^3,b/8iՓ;9y WvƊʖZ_ eipL:iՑ7*qE9Jm/6Zs dfΣ:<#;Xb6Ȯu7TAftԸXPIRmlJYN:;KV\zH YiLbmȚd_daɚrk!_})Yi2bumEG2=ݷ_$hu 8+@Y {e!?rt]W8reř%1l]m'wT"+}3R%r]dvՑ7$>?^U= Mȑ-~GLz=e 6*z]#^ ~ъ@ECK*a4YD+ol(w,#K:bixvi/쑮KY44?,Ai7%C@{!=iL;7nde`ɇdIձ̐`+0ެ>lB`dLBxsF59!d"O=+K6E>ݨYEr}:# ͖3<_◜LJJ貊l}u^lYc?2u̥h r_OJ~;mJUq۰nm do饸&{ 8Bq+d-a-U֤CK:zݮ5YM{lG(-.nTŕ~ Lҡq-8O);K\z$n^_Lv,y73LNno0S+j#ZR%kxuNid 3ZuWɛָ}j)ԲmD&d- Dme욓 gULve%Fi%6k$ ;7Wv Jv˯9N+=̇|R#'uu\lzҡҦK YG)GC/,ǚP) 6Xϋ-/Uy&VlX)ʁMVP/黳ïcq[őrWMֲ^ZCKeTxhTltiDžE+^q0tǣmjSͬQL| q>{:&;nqfNQ,cnMJlےU@pUazdЩ Gvfz?d d9ˆz').%'{dY^qlAȒ%< {I"tZ,Ys˧m>DzD:gם_J,mndmbu%`,?d`ٝ\0z]{,ȖaRRk4+VX CK%\Ya'aFbq̸/Jt\~ C* _ H02KX4 9drJ,t*$@9**d視Ui*Gy-a;@؁F/^Ve8 Ó>}M+N>}KXH cgz ?Ա"W AXaDw[=KX 62]% &MAU^iIx@a;jЦ3KaPƆ1^~5t"qH|'->aCow}h"%hSVl63S6l'I6YYw wvOk?#KܰckLɰ o>FӋ~ax\EQ, ˝ᜰ=VPv @w:t74dH @]Fi*Ev:ªe~Z<ꊦa6$yu}|߇}ڸ~2B6eP6+RQWvMKW)oaM K+QtV΋^C՗/r%#dSF!f{%yZiaO㊬.+H$7u4CԣyyF" FtE7WrIi"yM"-g3F|Y\dRD.Yc賤q^m`ڜc$+ݮrE^Mٔ[h]xѓsd~Zkw+L}Nc~`BwL&D*y86} ,rTyR\n , ‚*,}լ8AP%>*ÑJBN¢':b5򟅖5}^,[Ҝ5-iK #( [VąDqkNC(/nw^YFcIx|0aZpKkk kx,Kj :MR#Q .[=(l⠨p%Ց16=f4Dz$3i -+x,i`XQ; XLX. GzTKZ5WFcI\x,k~Zۭ6j'Go+a/ Gj),m>%j6 @+ꅕ*|@1 }]d=]akz[#P@wO١{4`a<.8<Z{2ybbI/vt}_Łi]a-K#Sȓ2:i|=d KgbnG7;􋄥@3v8Q0ٜ>m{y l@]$lWDwJ-nc%ǔTzRVɵTaAFX`lK5lWXڤ:, Yay $'~}nVSR-a1X"%yagh ˝"+ -K0ެ nxBڭ$ MV,F\S5–Kz"&. GE@<9OaL]%icOgI&bd-=6Y5EװKjď=)RaeȎUɲSfV?;kl$Keã`jLhtk$.,wfؑ62}݅'\'~w8xZX3l'%܎Y'ǵ$^V[YmcɷTxfer9oUUVVP+] ?"|# IENDB`perfbook_html/img27.png0000644000175000017500000001302011672746160015224 0ustar paulmckpaulmckPNG  IHDRC'6PLTEMJKPMM# b``mkkXUV856C@@wuv.*+rpptRNS@fIDATx]JP$UmsΜV%;Q= TZˆukBT {avu-ψJ> ec7p7䙕t ?֟z(sZRŞvOP-^ٺ9o ]$ /|lMY 嫂%;=`X. e?$/ձ@'J 6C@JOȃ}y*GSHmɋg1֝l?@V,?mLx: Ϋ13l΂;(-{hhsƧ+=?oZХ^ J PwxvEnod+81xO;_Ä= ~6P+%;)h 2R{/|l6k+q9nL7yY= os.f_oT4<DX 0.pHkT<ߩ1*.@{ _WKdS SJrfϞj~]фhRGߤΧw0 {n x$$tt8ԋ~LE:E]4蟣N.*&K{b]NƷܖ0,}KF Wώ|k5o 4g?[MS qRo?,lNK 'NkkjxmU!$C].\SԡDbjQe=m[OjcZ t.@|!-R,8x>b(u@[:>nXYQ}4E.}K&OPߴ{ 5KHhU{JS4()5Q4 ǒ]ҌWnLEkPv$ϗ>h3/,euAk=1u^/ijhY'sa0y($|P8r3u_IsQjf^.=rJ[ğKX򪚵qn&(<)~| nAxݵQD g,mݜb? .Z'4FuD-7.մ;8EGJvRÈ 2ω"5D7hӜ0 =K^tn3ك ǺK_aXũ_4+Y3O >걍7T/):eE+Ej(?72maCP23}(>RoaJ  +EaI٦WI)Z+@vD\}Dn}]" C 鈽bK= |ƛ>q W1T9-J; $C huV>~平Z(*iao*ёk 0p8;;naX^ Hr98CknUBE5{k=0=>?N3B 0홰R:i:j?JV^x 3n?v׍! ,I]B B >K(jVKGFJ6%Wu״2HirQt3=Um3 4sU/xHkߣH`TT,"KL"fO)x҉,SL:.VC ֵ } 7̞"ozKu^8Q G7_I/Kڥ(fhzYːHoppGf?LÞf?L"gesnxs00h?l~J 7mC܃dH|~x(O쇢6!>~3P|~Mm?|?f?kk&jړ6 .ja!ƪs \Qt6 b D؉<2)ʐ\ 3z n%qQ秲d:!֧aCtSz%> =z%EJ_RJf{l_:8۪ahK4QS~Wn?L>kOodzywK;4zsupK33CuO7 $hf1~@|ks^M^Lj;*]^Q23f-*"H 3K8WDwDFef23${K@sEƚT}8FqPC~% 6³VዻC~+C)vi%^;6-&Ɯ"x&3!(Nycs }s0l1jzM6^SP@js/E0sn"SBՕ4Z$&P #!FвT-=@4u.['k9Udh;[U"(mMUl[Yi = ‚8ֿxtuu+T^ ~)ҲQX]I#!>Am@2t|DYMY[~xG4uP,[(R+Cv|†3À={pop1sEWQX:EWtܭU wzE. yX}x1dgl`GG[eIVs@5PY,/eRiNlFQ.\TbyX"RZJ?>|x*0FVR*Y|n V ِϹbUGaet&?%Q>vuD䬂FjdOJTcI>^F 3/w⳱U&}-P!mjjIuʈ؇XMg1ZJ ^E4͐؏ԡ8}5ʏ*xE.PU*w }(s%m`N|+SWI' YM[ a~nК}D̆ *rzJ~~Nd: X1sI;3!1jBF)?kJ, Pdg{'1N)b=k)Qe3Vsɕȡ|jFl,CUdgbbp3 85u`Xok%NՄj0+^ J- y_7n!"ϮhL.ed iqmƾI36(l]1/' Z<\=i0XfG. ѧUR5"W,R1 ~>`jBw EaE68mea4l8@oC>wI㠟UI6nljsBʵNvʉ*wli̊8}Q=@8]"5K,st&Q24ц9 K<5K#+6<`le-U\NK<5K9KvKaCZl5'/p.,wsACvc首c LtWn ~Qӳd5ECȒ-5{Q@!IaCV<tsUsE߸n)l/l!b`nZis/oڸZd<|57=qYf8/P uL#3?\%p]j 2?woev`?;bVv;x,f~-Bxhl$ww;v3dif: w̖K?| '&xJG;E dׁv;2VȖ30L)|L'\ycs^e8w;dlNLy1WÌ37܌IwCC@s};p=x(¦NXlG"5ltS8PFBNftS9=9.QM_"s *oB2{iC>p̕v}naRޛPǕ}HfRI`lG06EҎXÖC xRm=e_fY"l^y~u}nrE?#hl99{AWtF f`EW6oO W-?/P5|+πlZὖoS V?vsɩnJf<\3Q S^_tpOhO(}x@;kT tUi&A>re9$kz>|cgI .je腴`(;gjHVo34y+2y/Z<<UH x2m䧜AA0ümCLk$y22w/SnE|<=/v:̻WXwhp/b˻7Y7⏸ÃOe7~a_;A ͺ[kE>scEy7N` !HmX;Pzpwq"؃yEm IENDB`perfbook_html/node132.html0000644000175000017500000000625611672746162015651 0ustar paulmckpaulmck 10.3.1.4 Summary of RCU Fundamentals


10.3.1.4 Summary of RCU Fundamentals

This section has described the three fundamental components of RCU-based algorithms:

  1. a publish-subscribe mechanism for adding new data,

  2. a way of waiting for pre-existing RCU readers to finish, and

  3. a discipline of maintaining multiple versions to permit change without harming or unduly delaying concurrent RCU readers.

Quick Quiz 10.11: How can RCU updaters possibly delay RCU readers, given that the rcu_read_lock() and rcu_read_unlock() primitives neither spin nor block? End Quick Quiz

These three RCU components allow data to be updated in face of concurrent readers, and can be combined in different ways to implement a surprising variety of different types of RCU-based algorithms, some of which are described in the following section.



Paul E. McKenney 2011-12-16
perfbook_html/node45.html0000644000175000017500000001547311672746161015574 0ustar paulmckpaulmck 5.2.2 POSIX Thread Creation and Destruction


5.2.2 POSIX Thread Creation and Destruction

Figure: Threads Created Via pthread_create() Share Memory
\begin{figure}{ \scriptsize
\begin{verbatim}1 int x = 0;
2
3 void *mythrea...
...ent process sees x=%d\n'', x);
24 return 0;
25 }\end{verbatim}
}\end{figure}

To create a thread within an existing process, invoke the pthread_create() primitive, for example, as shown on line 15 of Figure [*] (pcreate.c). The first argument is a pointer to a pthread_t in which to store the ID of the thread to be created, the second NULL argument is a pointer to an optional pthread_attr_t, the third argument is the function (in this case, mythread() that is to be invoked by the new thread, and the last NULL argument is the argument that will be passed to mythread.

In this example, mythread() simply returns, but it could instead call pthread_exit().

Quick Quiz 5.6: If the mythread() function in Figure [*] can simply return, why bother with pthread_exit()? End Quick Quiz

The pthread_join() primitive, shown on line 19, is analogous to the fork-join wait() primitive. It blocks until the thread specified by the tid variable completes execution, either by invoking pthread_exit() or by returning from the thread's top-level function. The thread's exit value will be stored through the pointer passed as the second argument to pthread_join(). The thread's exit value is either the value passed to pthread_exit() or the value returned by the thread's top-level function, depending on how the thread in question exits.

The program shown in Figure [*] produces output as follows, demonstrating that memory is in fact shared between the two threads:



Child process set x=1
Parent process sees x=1


Note that this program carefully makes sure that only one of the threads stores a value to variable x at a time. Any situation in which one thread might be storing a value to a given variable while some other thread either loads from or stores to that same variable is termed a ``data race''. Because the C language makes no guarantee that the results of a data race will be in any way reasonable, we need some way of safely accessing and modifying data concurrently, such as the locking primitives discussed in the following section.

Quick Quiz 5.7: If the C language makes no guarantees in presence of a data race, then why does the Linux kernel have so many data races? Are you trying to tell me that the Linux kernel is completely broken??? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node322.html0000644000175000017500000001346411672746163015652 0ustar paulmckpaulmck C.7.8 x86

C.7.8 x86

Since the x86 CPUs provide ``process ordering'' so that all CPUs agree on the order of a given CPU's writes to memory, the smp_wmb() primitive is a no-op for the CPU [Int04b]. However, a compiler directive is required to prevent the compiler from performing optimizations that would result in reordering across the smp_wmb() primitive.

On the other hand, x86 CPUs have traditionally given no ordering guarantees for loads, so the smp_mb() and smp_rmb() primitives expand to lock;addl. This atomic instruction acts as a barrier to both loads and stores.

More recently, Intel has published a memory model for x86 [Int07]. It turns out that Intel's actual CPUs enforced tighter ordering than was claimed in the previous specifications, so this model is in effect simply mandating the earlier de-facto behavior. Even more recently, Intel published an updated memory model for x86 [Int09, Section 8.2], which mandates a total global order for stores, although individual CPUs are still permitted to see their own stores as having happened earlier than this total global order would indicate. This exception to the total ordering is needed to allow important hardware optimizations involving store buffers. In addition, memory ordering obeys causality, so that if CPU 0 sees a store by CPU 1, then CPU 0 is guaranteed to see all stores that CPU 1 saw prior to its store. Software may use atomic operations to override these hardware optimizations, which is one reason that atomic operations tend to be more expensive than their non-atomic counterparts. This total store order is not guaranteed on older processors.

However, note that some SSE instructions are weakly ordered (clflush and non-temporal move instructions [Int04a]). CPUs that have SSE can use mfence for smp_mb(), lfence for smp_rmb(), and sfence for smp_wmb().

A few versions of the x86 CPU have a mode bit that enables out-of-order stores, and for these CPUs, smp_wmb() must also be defined to be lock;addl.

Although many older x86 implementations accommodated self-modifying code without the need for any special instructions, newer revisions of the x86 architecture no longer requires x86 CPUs to be so accommodating. Interestingly enough, this relaxation comes just in time to inconvenience JIT implementors.

Paul E. McKenney 2011-12-16
perfbook_html/images.log0000644000175000017500000026371011672745743015564 0ustar paulmckpaulmckThis is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009/Debian) (format=latex 2011.11.14) 16 DEC 2011 14:53 entering extended mode %&-line parsing enabled. **./images.tex (./images.tex LaTeX2e <2009/09/24> Babel and hyphenation patterns for english, usenglishmax, dumylang, noh yphenation, loaded. (/usr/share/texmf-texlive/tex/latex/base/book.cls Document Class: book 2007/10/19 v1.4h Standard LaTeX document class (/usr/share/texmf-texlive/tex/latex/base/bk10.clo File: bk10.clo 2007/10/19 v1.4h Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/usr/share/texmf-texlive/tex/latex/graphics/lscape.sty Package: lscape 2000/10/22 v3.01 Landscape Pages (DPC) (/usr/share/texmf-texlive/tex/latex/graphics/graphics.sty Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/trig.sty Package: trig 1999/03/16 v1.09 sin cos tan (DPC) ) (/etc/texmf/tex/latex/config/graphics.cfg File: graphics.cfg 2009/08/28 v1.8 graphics configuration of TeX Live ) Package graphics Info: Driver file: dvips.def on input line 91. (/usr/share/texmf-texlive/tex/latex/graphics/dvips.def File: dvips.def 1999/02/16 v3.0i Driver-dependant file (DPC,SPQR) ))) (/usr/share/texmf-texlive/tex/latex/graphics/epsfig.sty Package: epsfig 1999/02/16 v1.7a (e)psfig emulation (SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/graphicx.sty Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) (/usr/share/texmf-texlive/tex/latex/graphics/keyval.sty Package: keyval 1999/03/16 v1.13 key=value parser (DPC) \KV@toks@=\toks14 ) \Gin@req@height=\dimen103 \Gin@req@width=\dimen104 ) \epsfxsize=\dimen105 \epsfysize=\dimen106 ) (/usr/share/texmf-texlive/tex/latex/subfigure/subfigure.sty Package: subfigure 2002/03/15 v2.1.5 subfigure package \subfigtopskip=\skip43 \subfigcapskip=\skip44 \subfigcaptopadj=\dimen107 \subfigbottomskip=\skip45 \subfigcapmargin=\dimen108 \subfiglabelskip=\skip46 \c@subfigure=\count88 \c@lofdepth=\count89 \c@subtable=\count90 \c@lotdepth=\count91 **************************************** * Local config file subfigure.cfg used * **************************************** (/usr/share/texmf-texlive/tex/latex/subfigure/subfigure.cfg) \subfig@top=\skip47 \subfig@bottom=\skip48 ) (/usr/share/texmf-texlive/tex/latex/ltxmisc/url.sty \Urlmuskip=\muskip10 Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc. ) (/usr/share/texmf-texlive/tex/latex/tools/enumerate.sty Package: enumerate 1999/03/05 v3.00 enumerate extensions (DPC) \@enLab=\toks15 ) (/usr/share/texmf-texlive/tex/latex/base/ifthen.sty Package: ifthen 2001/05/26 v1.1c Standard LaTeX ifthen package (DPC) ) (/usr/share/texmf-texlive/tex/latex/listings/listings.sty \lst@mode=\count92 \lst@gtempboxa=\box26 \lst@token=\toks16 \lst@length=\count93 \lst@currlwidth=\dimen109 \lst@column=\count94 \lst@pos=\count95 \lst@lostspace=\dimen110 \lst@width=\dimen111 \lst@newlines=\count96 \lst@lineno=\count97 \lst@maxwidth=\dimen112 (/usr/share/texmf-texlive/tex/latex/listings/lstmisc.sty File: lstmisc.sty 2007/02/22 1.4 (Carsten Heinz) \c@lstnumber=\count98 \lst@skipnumbers=\count99 \lst@framebox=\box27 ) (/usr/share/texmf-texlive/tex/latex/listings/listings.cfg File: listings.cfg 2007/02/22 1.4 listings configuration )) Package: listings 2007/02/22 1.4 (Carsten Heinz) (/usr/share/texmf-texlive/tex/latex/hyperref/hyperref.sty Package: hyperref 2009/10/09 v6.79a Hypertext links for LaTeX (/usr/share/texmf-texlive/tex/generic/oberdiek/ifpdf.sty Package: ifpdf 2009/04/10 v2.0 Provides the ifpdf switch (HO) Package ifpdf Info: pdfTeX in pdf mode not detected. ) (/usr/share/texmf-texlive/tex/generic/oberdiek/ifvtex.sty Package: ifvtex 2008/11/04 v1.4 Switches for detecting VTeX and its modes (HO) Package ifvtex Info: VTeX not detected. ) (/usr/share/texmf-texlive/tex/generic/ifxetex/ifxetex.sty Package: ifxetex 2009/01/23 v0.5 Provides ifxetex conditional ) (/usr/share/texmf-texlive/tex/latex/oberdiek/hycolor.sty Package: hycolor 2009/10/02 v1.5 Code for color options of hyperref/bookmark (H O) (/usr/share/texmf-texlive/tex/latex/oberdiek/xcolor-patch.sty Package: xcolor-patch 2009/10/02 xcolor patch )) \@linkdim=\dimen113 \Hy@linkcounter=\count100 \Hy@pagecounter=\count101 (/usr/share/texmf-texlive/tex/latex/hyperref/pd1enc.def File: pd1enc.def 2009/10/09 v6.79a Hyperref: PDFDocEncoding definition (HO) ) (/usr/share/texmf-texlive/tex/generic/oberdiek/etexcmds.sty Package: etexcmds 2007/12/12 v1.2 Prefix for e-TeX command names (HO) (/usr/share/texmf-texlive/tex/generic/oberdiek/infwarerr.sty Package: infwarerr 2007/09/09 v1.2 Providing info/warning/message (HO) ) Package etexcmds Info: Could not find \expanded. (etexcmds) That can mean that you are not using pdfTeX 1.50 or (etexcmds) that some package has redefined \expanded. (etexcmds) In the latter case, load this package earlier. ) (/usr/share/texmf-texlive/tex/latex/latexconfig/hyperref.cfg File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive ) (/usr/share/texmf-texlive/tex/latex/oberdiek/kvoptions.sty Package: kvoptions 2009/08/13 v3.4 Keyval support for LaTeX options (HO) (/usr/share/texmf-texlive/tex/generic/oberdiek/kvsetkeys.sty Package: kvsetkeys 2009/07/30 v1.5 Key value parser with default handler suppor t (HO) )) Package hyperref Info: Option `bookmarks' set `true' on input line 2864. Package hyperref Info: Option `bookmarksnumbered' set `true' on input line 2864 . Package hyperref Info: Hyper figures OFF on input line 2975. Package hyperref Info: Link nesting OFF on input line 2980. Package hyperref Info: Hyper index ON on input line 2983. Package hyperref Info: Plain pages OFF on input line 2990. Package hyperref Info: Backreferencing OFF on input line 2995. Implicit mode ON; LaTeX internals redefined Package hyperref Info: Bookmarks ON on input line 3191. LaTeX Info: Redefining \url on input line 3428. (/usr/share/texmf-texlive/tex/generic/oberdiek/bitset.sty Package: bitset 2007/09/28 v1.0 Data type bit set (HO) (/usr/share/texmf-texlive/tex/generic/oberdiek/intcalc.sty Package: intcalc 2007/09/27 v1.1 Expandable integer calculations (HO) ) (/usr/share/texmf-texlive/tex/generic/oberdiek/bigintcalc.sty Package: bigintcalc 2007/11/11 v1.1 Expandable big integer calculations (HO) (/usr/share/texmf-texlive/tex/generic/oberdiek/pdftexcmds.sty Package: pdftexcmds 2009/09/23 v0.6 LuaTeX support for pdfTeX utility functions (HO) (/usr/share/texmf-texlive/tex/generic/oberdiek/ifluatex.sty Package: ifluatex 2009/04/17 v1.2 Provides the ifluatex switch (HO) Package ifluatex Info: LuaTeX not detected. ) (/usr/share/texmf-texlive/tex/generic/oberdiek/ltxcmds.sty Package: ltxcmds 2009/08/05 v1.0 Some LaTeX kernel commands for general use (HO ) ) Package pdftexcmds Info: LuaTeX not detected. Package pdftexcmds Info: \pdf@primitive is available. Package pdftexcmds Info: \pdf@ifprimitive is available. ))) \Fld@menulength=\count102 \Field@Width=\dimen114 \Fld@charsize=\dimen115 \Field@toks=\toks17 Package hyperref Info: Hyper figures OFF on input line 4377. Package hyperref Info: Link nesting OFF on input line 4382. Package hyperref Info: Hyper index ON on input line 4385. Package hyperref Info: backreferencing OFF on input line 4392. Package hyperref Info: Link coloring OFF on input line 4397. Package hyperref Info: Link coloring with OCG OFF on input line 4402. Package hyperref Info: PDF/A mode OFF on input line 4407. (/usr/share/texmf-texlive/tex/generic/oberdiek/atbegshi.sty Package: atbegshi 2008/07/31 v1.9 At begin shipout hook (HO) ) \Hy@abspage=\count103 \c@Item=\count104 \c@Hfootnote=\count105 ) *hyperref using default driver hdvips* (/usr/share/texmf-texlive/tex/latex/hyperref/hdvips.def File: hdvips.def 2009/10/09 v6.79a Hyperref driver for dvips (/usr/share/texmf-texlive/tex/latex/hyperref/pdfmark.def File: pdfmark.def 2009/10/09 v6.79a Hyperref definitions for pdfmark specials \pdf@docset=\toks18 \pdf@box=\box28 \pdf@toks=\toks19 \pdf@defaulttoks=\toks20 \Fld@listcount=\count106 )) \c@quickquizctr=\count107 Chapter 1. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. } l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. } l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Undefined control sequence. \@outlinefile l.21 \chapter{#2} The control sequence at the end of the top line of your error message was never \def'ed. If you have misspelled it (e.g., `\hobx'), type `I' and the correct spelling (e.g., `I\hbox'). Otherwise just continue, and I'll forget about whatever was undefined. ! Illegal parameter number in definition of \reserved@a. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Missing number, treated as zero. { l.21 \chapter{#2} A number should have been here; I inserted `0'. (If you can't figure out why I needed to see a number, look up `weird error' in the index to The TeXbook.) ! Illegal parameter number in definition of \reserved@a. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \@themark. 2 l.21 \chapter{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.21 \chapter{#2} You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. ! You can't use `macro parameter character #' in internal vertical mode. ## 2 l.21 \chapter{#2} Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. ! Illegal parameter number in definition of \reserved@a. 1 l.22 \label{#1} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.25 ... Quiz \thechapter .\arabic{quickquizctr}:} You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. [1 \BOOKMARK [0][-]{chapter.1}{1 ##2}{} \@writefile{toc}{\contentsline {chapter}{\numberline {1}##2}{1}{chapter.1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{##1}{{1}{1}} ] ! Illegal parameter number in definition of \reserved@a. 2 l.28 \chapter {Answers to Quick Quizzes} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! You can't use `macro parameter character #' in restricted horizontal mode. CHAPTER\ 1. \ ## 2 l.28 \chapter {Answers to Quick Quizzes} Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. [2 ] Chapter 2. ! Undefined control sequence. \@outlinefile l.28 \chapter{Answers to Quick Quizzes} The control sequence at the end of the top line of your error message was never \def'ed. If you have misspelled it (e.g., `\hobx'), type `I' and the correct spelling (e.g., `I\hbox'). Otherwise just continue, and I'll forget about whatever was undefined. ! Missing number, treated as zero. { l.28 \chapter{Answers to Quick Quizzes} A number should have been here; I inserted `0'. (If you can't figure out why I needed to see a number, look up `weird error' in the index to The TeXbook.) ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.28 \chapter{Answers to Quick Quizzes} You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.30 ~ \\ You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. Underfull \hbox (badness 10000) in paragraph at lines 30--32 [] ! LaTeX Error: \QuickQuizAnswerChapter undefined. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.37 \renewcommand{\QuickQuizAnswerChapter} {\ref{#1}} Try typing to proceed. If that doesn't work, type X to quit. ! Illegal parameter number in definition of \QuickQuizAnswerChapter. 1 l.37 ...command{\QuickQuizAnswerChapter}{\ref{#1}} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.39 \section {#2} You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. ! LaTeX Error: Missing \begin{document}. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.39 \section{#2} You're in trouble here. Try typing to proceed. If that doesn't work, type X to quit. ! You can't use `macro parameter character #' in horizontal mode. ## 2 l.39 \section{#2} Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. ! Illegal parameter number in definition of \@themark. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@A. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@temp@B. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. } l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. } l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \HyPsd@String. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \Hy@tempa. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Undefined control sequence. \@outlinefile l.39 \section{#2} The control sequence at the end of the top line of your error message was never \def'ed. If you have misspelled it (e.g., `\hobx'), type `I' and the correct spelling (e.g., `I\hbox'). Otherwise just continue, and I'll forget about whatever was undefined. ! Illegal parameter number in definition of \reserved@a. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Missing number, treated as zero. { l.39 \section{#2} A number should have been here; I inserted `0'. (If you can't figure out why I needed to see a number, look up `weird error' in the index to The TeXbook.) ! Illegal parameter number in definition of \reserved@a. 2 l.39 \section{#2} You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \reserved@a. 1 l.43 ...uick Quiz \ref{#1}.\arabic{quickquizctr}:} #1 ~ \\ You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. LaTeX Warning: Reference `##1' on page 3 undefined on input line 43. ! You can't use `macro parameter character #' in horizontal mode. l.43 ...ck Quiz \ref{#1}.\arabic{quickquizctr}:} # 1 ~ \\ Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. Underfull \hbox (badness 10000) in paragraph at lines 42--44 [] Underfull \hbox (badness 10000) in paragraph at lines 42--44 [] LaTeX Warning: Reference `sec:intro:What Makes Parallel Programming Hard?' on p age 3 undefined on input line 49. LaTeX Warning: Reference `sec:intro:What Makes Parallel Programming Hard?' on p age 3 undefined on input line 51. \citation{PaulEMcKenney2009ProgrammingHard} LaTeX Warning: Citation `PaulEMcKenney2009ProgrammingHard' on page 3 undefined on input line 52. LaTeX Warning: Reference `sec:defer:RCU Fundamentals' on page 3 undefined on in put line 53. LaTeX Warning: Reference `sec:defer:RCU Fundamentals' on page 3 undefined on in put line 55. \citation{PaulEMcKenney2007WhatIsRCUFundamentally} LaTeX Warning: Citation `PaulEMcKenney2007WhatIsRCUFundamentally' on page 3 und efined on input line 56. LaTeX Warning: Reference `sec:defer:RCU Usage' on page 3 undefined on input lin e 57. LaTeX Warning: Reference `sec:defer:RCU Usage' on page 3 undefined on input lin e 59. \citation{PaulEMcKenney2008WhatIsRCUUsage} LaTeX Warning: Citation `PaulEMcKenney2008WhatIsRCUUsage' on page 3 undefined o n input line 60. LaTeX Warning: Reference `sec:defer:RCU Linux-Kernel API' on page 3 undefined o n input line 61. LaTeX Warning: Reference `sec:defer:RCU Linux-Kernel API' on page 3 undefined o n input line 63. \citation{PaulEMcKenney2008WhatIsRCUAPI} LaTeX Warning: Citation `PaulEMcKenney2008WhatIsRCUAPI' on page 3 undefined on input line 64. Underfull \hbox (badness 2653) in paragraph at lines 61--65 []\OT1/cmr/m/n/10 Section [] (``RCU Linux-Kernel API'') on [] LaTeX Warning: Reference `sec:app:whymb:Memory-Barrier Instructions For Specifi c CPUs' on page 3 undefined on input line 65. LaTeX Warning: Reference `sec:app:whymb:Memory-Barrier Instructions For Specifi c CPUs' on page 3 undefined on input line 67. \citation{PaulMcKenney2005i} LaTeX Warning: Citation `PaulMcKenney2005i' on page 3 undefined on input line 6 8. \citation{PaulMcKenney2005j} LaTeX Warning: Citation `PaulMcKenney2005j' on page 3 undefined on input line 6 8. LaTeX Warning: Reference `app:rcuimpl:Sleepable RCU Implementation' on page 3 u ndefined on input line 69. LaTeX Warning: Reference `app:rcuimpl:Sleepable RCU Implementation' on page 3 u ndefined on input line 71. \citation{PaulEMcKenney2006c} LaTeX Warning: Citation `PaulEMcKenney2006c' on page 3 undefined on input line 72. LaTeX Warning: Reference `app:rcuimpl:rcutree:Hierarchical RCU Overview' on pag e 3 undefined on input line 73. LaTeX Warning: Reference `app:rcuimpl:rcutree:Hierarchical RCU Overview' on pag e 3 undefined on input line 75. \citation{PaulEMcKenney2008HierarchicalRCU} LaTeX Warning: Citation `PaulEMcKenney2008HierarchicalRCU' on page 3 undefined on input line 76. LaTeX Warning: Reference `app:rcuimpl:Preemptible RCU' on page 3 undefined on i nput line 77. LaTeX Warning: Reference `app:rcuimpl:Preemptible RCU' on page 3 undefined on i nput line 79. \citation{PaulEMcKenney2007PreemptibleRCU} LaTeX Warning: Citation `PaulEMcKenney2007PreemptibleRCU' on page 3 undefined o n input line 80. LaTeX Warning: Reference `app:formal:Formal Verification' on page 3 undefined o n input line 81. LaTeX Warning: Reference `app:formal:Formal Verification' on page 3 undefined o n input line 83. \citation{PaulEMcKenney2007QRCUspin} LaTeX Warning: Citation `PaulEMcKenney2007QRCUspin' on page 3 undefined on inpu t line 84. \citation{PaulEMcKenney2008dynticksRCU} LaTeX Warning: Citation `PaulEMcKenney2008dynticksRCU' on page 3 undefined on i nput line 84. LaTeX Warning: Reference `fig:cpu:CPU Performance at its Best' on page 3 undefi ned on input line 90. LaTeX Warning: Reference `fig:cpu:CPU Performance at its Best' on page 3 undefi ned on input line 91. LaTeX Warning: Reference `fig:cpu:CPUs Old and New' on page 3 undefined on inpu t line 93. LaTeX Warning: Reference `fig:cpu:CPUs Old and New' on page 3 undefined on inpu t line 94. LaTeX Warning: Reference `fig:cpu:CPU Meets a Pipeline Flush' on page 3 undefin ed on input line 96. LaTeX Warning: Reference `fig:cpu:CPU Meets a Pipeline Flush' on page 3 undefin ed on input line 97. LaTeX Warning: Reference `fig:cpu:CPU Meets a Memory Reference' on page 3 undef ined on input line 99. LaTeX Warning: Reference `fig:cpu:CPU Meets a Memory Reference' on page 3 undef ined on input line 100. LaTeX Warning: Reference `fig:cpu:CPU Meets an Atomic Operation' on page 3 unde fined on input line 102. LaTeX Warning: Reference `fig:cpu:CPU Meets an Atomic Operation' on page 3 unde fined on input line 103. LaTeX Warning: Reference `fig:cpu:CPU Meets a Memory Barrier' on page 3 undefin ed on input line 105. LaTeX Warning: Reference `fig:cpu:CPU Meets a Memory Barrier' on page 3 undefin ed on input line 106. LaTeX Warning: Reference `fig:cpu:CPU Meets a Cache Miss' on page 3 undefined o n input line 108. LaTeX Warning: Reference `fig:cpu:CPU Meets a Cache Miss' on page 3 undefined o n input line 109. LaTeX Warning: Reference `fig:cpu:CPU Waits for I/O Completion' on page 3 undef ined on input line 111. LaTeX Warning: Reference `fig:cpu:CPU Waits for I/O Completion' on page 3 undef ined on input line 112. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem' on page 3 undefined on input line 114. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem' on page 3 undefined on input line 115. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Textbook S olution' on page 3 undefined on input line 117. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Textbook S olution' on page 3 undefined on input line 118. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Partitione d' on page 3 undefined on input line 120. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Partitione d' on page 3 undefined on input line 121. LaTeX Warning: Reference `fig:SMPdesign:Lock Contention' on page 3 undefined on input line 123. LaTeX Warning: Reference `fig:SMPdesign:Lock Contention' on page 3 undefined on input line 124. LaTeX Warning: Reference `fig:SMPdesign:Data Locking' on page 3 undefined on in put line 126. LaTeX Warning: Reference `fig:SMPdesign:Data Locking' on page 3 undefined on in put line 127. LaTeX Warning: Reference `fig:SMPdesign:Data and Skew' on page 3 undefined on i nput line 129. LaTeX Warning: Reference `fig:SMPdesign:Data and Skew' on page 3 undefined on i nput line 130. LaTeX Warning: Reference `fig:advsync:CPUs Can Do Things Out of Order' on page 3 undefined on input line 132. LaTeX Warning: Reference `fig:advsync:CPUs Can Do Things Out of Order' on page 3 undefined on input line 133. LaTeX Warning: Reference `fig:advsync:Abstract Memory Access Model' on page 3 u ndefined on input line 135. LaTeX Warning: Reference `fig:advsync:Abstract Memory Access Model' on page 3 u ndefined on input line 136. [3 \BOOKMARK [0][-]{chapter.2}{2 Answers to Quick Quizzes}{} \@writefile{toc}{\contentsline {chapter}{\numberline {2}Answers to Quick Quizze s}{3}{chapter.2}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \newlabel{chp:Answers to Quick Quizzes}{{2}{3}} \BOOKMARK [1][-]{section.2.1}{2.1 ##2}{chapter.2} \@writefile{toc}{\contentsline {section}{\numberline {2.1}##2}{3}{section.2.1}} ] LaTeX Warning: Reference `fig:advsync:Write Barrier Ordering Semantics' on page 4 undefined on input line 138. LaTeX Warning: Reference `fig:advsync:Write Barrier Ordering Semantics' on page 4 undefined on input line 139. LaTeX Warning: Reference `fig:advsync:Data Dependency Barrier Omitted' on page 4 undefined on input line 141. LaTeX Warning: Reference `fig:advsync:Data Dependency Barrier Omitted' on page 4 undefined on input line 142. LaTeX Warning: Reference `fig:advsync:Data Dependency Barrier Supplied' on page 4 undefined on input line 144. LaTeX Warning: Reference `fig:advsync:Data Dependency Barrier Supplied' on page 4 undefined on input line 145. LaTeX Warning: Reference `fig:advsync:Read Barrier Needed' on page 4 undefined on input line 147. LaTeX Warning: Reference `fig:advsync:Read Barrier Needed' on page 4 undefined on input line 148. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied' on page 4 undefine d on input line 150. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied' on page 4 undefine d on input line 151. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied, Double Load' on pa ge 4 undefined on input line 153. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied, Double Load' on pa ge 4 undefined on input line 154. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied, Take Two' on page 4 undefined on input line 156. LaTeX Warning: Reference `fig:advsync:Read Barrier Supplied, Take Two' on page 4 undefined on input line 157. LaTeX Warning: Reference `fig:advsync:Speculative Load' on page 4 undefined on input line 159. LaTeX Warning: Reference `fig:advsync:Speculative Load' on page 4 undefined on input line 160. LaTeX Warning: Reference `fig:advsync:Speculative Loads and Barrier' on page 4 undefined on input line 162. LaTeX Warning: Reference `fig:advsync:Speculative Loads and Barrier' on page 4 undefined on input line 163. LaTeX Warning: Reference `fig:advsync:Speculative Loads Cancelled by Barrier' o n page 4 undefined on input line 165. LaTeX Warning: Reference `fig:advsync:Speculative Loads Cancelled by Barrier' o n page 4 undefined on input line 166. LaTeX Warning: Reference `fig:advsync:Memory Architecture' on page 4 undefined on input line 168. LaTeX Warning: Reference `fig:advsync:Memory Architecture' on page 4 undefined on input line 169. LaTeX Warning: Reference `fig:advsync:Split Caches' on page 4 undefined on inpu t line 171. LaTeX Warning: Reference `fig:advsync:Split Caches' on page 4 undefined on inpu t line 172. LaTeX Warning: Reference `fig:easy:Shaving the Mandelbrot Set' on page 4 undefi ned on input line 174. LaTeX Warning: Reference `fig:easy:Shaving the Mandelbrot Set' on page 4 undefi ned on input line 175. LaTeX Warning: Reference `fig:app:whymb:Half Memory Barrier' on page 4 undefine d on input line 177. LaTeX Warning: Reference `fig:app:whymb:Half Memory Barrier' on page 4 undefine d on input line 178. LaTeX Warning: Reference `fig:app:rcuimpl:srcu:Sleeping While RCU Reading Consi dered Harmful' on page 4 undefined on input line 180. LaTeX Warning: Reference `fig:app:rcuimpl:srcu:Sleeping While RCU Reading Consi dered Harmful' on page 4 undefined on input line 181. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Fully Part itioned' on page 4 undefined on input line 183. LaTeX Warning: Reference `fig:SMPdesign:Dining Philosophers Problem, Fully Part itioned' on page 4 undefined on input line 184. ! LaTeX Error: Lonely \item--perhaps a missing list environment. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.189 \item # 1~\ref{#2} (``#3'') on page~\pageref{#2} Try typing to proceed. If that doesn't work, type X to quit. ! You can't use `macro parameter character #' in vertical mode. ## l.189 \item # 1~\ref{#2} (``#3'') on page~\pageref{#2} Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. LaTeX Warning: Reference `##2' on page 4 undefined on input line 189. ! You can't use `macro parameter character #' in horizontal mode. l.189 \item #1~\ref{#2} (``# 3'') on page~\pageref{#2} Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. LaTeX Warning: Reference `##2' on page 4 undefined on input line 189. ! You can't use `macro parameter character #' in horizontal mode. l.190 originally appeared in # 4~\cite{#5}. Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. ! Illegal parameter number in definition of \@fortmp. 5 l.190 originally appeared in #4~\cite{#5} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \@citeb. 5 l.190 originally appeared in #4~\cite{#5} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \@citeb. 5 l.190 originally appeared in #4~\cite{#5} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. \citation{##5} LaTeX Warning: Citation `##5' on page 4 undefined on input line 190. ! LaTeX Error: Lonely \item--perhaps a missing list environment. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.193 \item # 1~\ref{#2}--\ref{#3} (``#4'') Try typing to proceed. If that doesn't work, type X to quit. ! You can't use `macro parameter character #' in vertical mode. ## l.193 \item # 1~\ref{#2}--\ref{#3} (``#4'') Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. LaTeX Warning: Reference `##2' on page 4 undefined on input line 193. LaTeX Warning: Reference `##3' on page 4 undefined on input line 193. ! You can't use `macro parameter character #' in horizontal mode. l.193 \item #1~\ref{#2}--\ref{#3} (``# 4'') Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. LaTeX Warning: Reference `##2' on page 4 undefined on input line 194. LaTeX Warning: Reference `##2' on page 4 undefined on input line 194. ! You can't use `macro parameter character #' in horizontal mode. l.195 originally appeared in # 5~\cite{#6}. Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. ! Illegal parameter number in definition of \@fortmp. 6 l.195 originally appeared in #5~\cite{#6} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \@citeb. 6 l.195 originally appeared in #5~\cite{#6} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. ! Illegal parameter number in definition of \@citeb. 6 l.195 originally appeared in #5~\cite{#6} . You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere earlier, and things are all screwed up? I'm going to assume that you meant ##. \citation{##6} LaTeX Warning: Citation `##6' on page 4 undefined on input line 195. ! LaTeX Error: Lonely \item--perhaps a missing list environment. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.198 \item # 1~\ref{#2} (p~\pageref{#2}) by #3. Try typing to proceed. If that doesn't work, type X to quit. ! You can't use `macro parameter character #' in vertical mode. ## l.198 \item # 1~\ref{#2} (p~\pageref{#2}) by #3. Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. LaTeX Warning: Reference `##2' on page 4 undefined on input line 198. LaTeX Warning: Reference `##2' on page 4 undefined on input line 198. ! You can't use `macro parameter character #' in horizontal mode. l.198 \item #1~\ref{#2} (p~\pageref{#2}) by # 3. Sorry, but I'm not programmed to handle this case; I'll just pretend that you didn't ask for it. If you're in the wrong mode, you might be able to return to the right one by typing `I}' or `I$' or `I\par'. (/usr/share/texmf-texlive/tex/latex/graphics/color.sty Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC) (/etc/texmf/tex/latex/config/color.cfg File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive ) Package color Info: Driver file: dvips.def on input line 130. (/usr/share/texmf-texlive/tex/latex/graphics/dvipsnam.def File: dvipsnam.def 1999/02/16 v3.0i Driver-dependant file (DPC,SPQR) )) (/usr/share/texmf-texlive/tex/latex/base/inputenc.sty Package: inputenc 2008/03/30 v1.1d Input encoding file \inpenc@prehook=\toks21 \inpenc@posthook=\toks22 ) \sizebox=\box29 \lthtmlwrite=\write3 No file images.aux. \openout1 = `images.aux'. LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 308. LaTeX Font Info: ... okay on input line 308. \c@lstlisting=\count108 Package hyperref Info: Link coloring OFF on input line 308. (/usr/share/texmf-texlive/tex/latex/hyperref/nameref.sty Package: nameref 2007/05/29 v2.31 Cross-referencing by name of section (/usr/share/texmf-texlive/tex/latex/oberdiek/refcount.sty Package: refcount 2008/08/11 v3.1 Data extraction from references (HO) ) \c@section@level=\count109 ) LaTeX Info: Redefining \ref on input line 308. LaTeX Info: Redefining \pageref on input line 308. \@outlinefile=\write4 \openout4 = `images.out'. \AtBeginShipoutBox=\box30 Package hyperref Warning: Rerun to get /PageLabels entry. latex2htmlLength hsize=169.5pt latex2htmlLength vsize=627.36243pt latex2htmlLength hoffset=0.0pt latex2htmlLength voffset=0.0pt latex2htmlLength topmargin=0.0pt latex2htmlLength topskip=0.00003pt latex2htmlLength headheight=0.0pt latex2htmlLength headsep=0.0pt latex2htmlLength parskip=0.0pt plus 1.0pt latex2htmlLength oddsidemargin=-14.0pt latex2htmlLength evensidemargin=14.0pt [1 ] File: SMPdesign/clockfreq.eps Graphic file (type eps) l2hSize :tex2html_wrap549:223.69797pt::0.0pt::349.0pt. [2 ] File: SMPdesign/mipsperbuck.eps Graphic file (type eps) l2hSize :tex2html_wrap577:223.69797pt::0.0pt::349.0pt. [3 ] File: intro/PPGrelation.eps Graphic file (type eps) l2hSize :tex2html_wrap601:153.7113pt::0.0pt::349.0pt. [4 ] File: intro/Generality.eps Graphic file (type eps) l2hSize :tex2html_wrap609:158.81766pt::0.0pt::349.0pt. [5 ] File: intro/FourTaskCategories.eps Graphic file (type eps) l2hSize :tex2html_wrap675:136.25476pt::0.0pt::349.0pt. [6 ] File: intro/FourTaskOrder.eps Graphic file (type eps) l2hSize :tex2html_wrap723:136.25476pt::0.0pt::349.0pt. [7 ] File: cartoons/trackmeet.eps Graphic file (type eps) l2hSize :tex2html_wrap900:230.06084pt::0.0pt::349.0pt. [8 ] File: cartoons/whippersnapper.eps Graphic file (type eps) l2hSize :tex2html_wrap910:176.79619pt::0.0pt::349.0pt. [9 ] File: cartoons/pipeline.eps Graphic file (type eps) l2hSize :tex2html_wrap920:191.69379pt::0.0pt::349.0pt. [10 ] File: cartoons/ref.eps Graphic file (type eps) l2hSize :tex2html_wrap936:209.28725pt::0.0pt::349.0pt. [11 ] File: cartoons/atomic.eps Graphic file (type eps) l2hSize :tex2html_wrap950:208.24043pt::0.0pt::349.0pt. [12 ] File: cartoons/barrier.eps Graphic file (type eps) l2hSize :tex2html_wrap972:248.5348pt::0.0pt::349.0pt. [13 ] File: cartoons/tollbooth.eps Graphic file (type eps) l2hSize :tex2html_wrap982:275.43224pt::0.0pt::349.0pt. [14 ] File: cartoons/PhoneBooth.eps Graphic file (type eps) l2hSize :tex2html_wrap992:230.20064pt::0.0pt::349.0pt. [15 ] File: cpu/SystemArch.eps Graphic file (type eps) l2hSize :tex2html_wrap1051:186.97734pt::0.0pt::349.0pt. [16 ] File: cpu/3DI.eps Graphic file (type eps) l2hSize :tex2html_wrap1146:96.47234pt::0.0pt::349.0pt. [17 ] File: toolsoftrade/shellparallel.eps Graphic file (type eps) l2hSize :tex2html_wrap1702:158.13509pt::0.0pt::349.0pt. [18 ] l2hSize :figure1258:90.58331pt::0.0pt::349.0pt. [19 ] l2hSize :figure1275:130.58331pt::0.0pt::349.0pt. [20 ] l2hSize :figure1296:131.55554pt::0.0pt::349.0pt. [21 ] l2hSize :figure1321:210.58331pt::0.0pt::349.0pt. [22 ] l2hSize :figure1371:402.58331pt::0.0pt::349.0pt. [23 ] l2hSize :figure1410:162.58331pt::0.0pt::349.0pt. [24 ] l2hSize :figure1435:170.58331pt::0.0pt::349.0pt. [25 ] l2hSize :figure1481:338.58331pt::0.0pt::349.0pt. [26 ] File: CodeSamples/toolsoftrade/rwlockscale.eps Graphic file (type eps) l2hSize :tex2html_wrap1896:242.06781pt::0.0pt::349.0pt. [27 ] LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 807. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 807. l2hSize :displaymath1516:22.95789pt::0.0pt::349.0pt. [28 ] l2hSize :tex2html_wrap_inline1680:6.83331pt::0.0pt::9.625pt. [29 ] l2hSize :tex2html_wrap_inline1682:7.33331pt::7.33331pt::14.89034pt. [30 ] l2hSize :tex2html_wrap_inline1686:7.33331pt::7.33331pt::11.79173pt. [31 ] l2hSize :figure1984:98.58331pt::0.0pt::349.0pt. [32 ] l2hSize :figure1998:98.58331pt::0.0pt::349.0pt. [33 ] File: CodeSamples/count/atomic.eps Graphic file (type eps) l2hSize :tex2html_wrap2889:223.69797pt::0.0pt::349.0pt. [34 ] l2hSize :tex2html_wrap_inline2819:6.95831pt::6.95831pt::24.09486pt. [35 ] File: count/GlobalInc.eps Graphic file (type eps) l2hSize :tex2html_wrap2909:140.233pt::0.0pt::349.0pt. [36 ] l2hSize :figure2046:138.58331pt::0.0pt::349.0pt. [37 ] File: count/PerThreadInc.eps Graphic file (type eps) l2hSize :tex2html_wrap2969:140.233pt::0.0pt::349.0pt. [38 ] l2hSize :figure2089:410.58331pt::0.0pt::349.0pt. [39 ] l2hSize :figure2124:346.58331pt::0.0pt::349.0pt. [40 ] l2hSize :figure2185:67.55554pt::0.0pt::349.0pt. [41 ] File: count/count_lim.eps Graphic file (type eps) l2hSize :tex2html_wrap3085:247.47517pt::0.0pt::349.0pt. [42 ] l2hSize :figure2223:410.58331pt::0.0pt::349.0pt. [43 ] l2hSize :figure2302:314.58331pt::0.0pt::349.0pt. [44 ] l2hSize :figure2362:74.69023pt::0.0pt::349.0pt. [45 ] l2hSize :figure2368:106.58331pt::0.0pt::349.0pt. [46 ] l2hSize :figure2398:274.58331pt::0.0pt::349.0pt. [47 ] l2hSize :figure2453:514.58331pt::0.0pt::349.0pt. [48 ] l2hSize :figure2503:154.58331pt::0.0pt::349.0pt. [49 ] *** image for figure2515 is too tall at 594.58331pt, reducing to .95 vsize *** l2hSize :figure2515:566.41429pt::0.0pt::349.0pt. [50 ] File: count/sig-theft.eps Graphic file (type eps) l2hSize :tex2html_wrap3289:206.95744pt::0.0pt::349.0pt. [51 ] l2hSize :figure2606:146.69023pt::0.0pt::349.0pt. [52 ] l2hSize :figure2616:514.58331pt::0.0pt::349.0pt. [53 ] *** image for figure2655 is too tall at 578.58331pt, reducing to .95 vsize *** l2hSize :figure2655:566.41429pt::0.0pt::349.0pt. [54 ] l2hSize :figure2668:114.58331pt::0.0pt::349.0pt. [55 ] l2hSize :figure2679:290.58331pt::0.0pt::349.0pt. [56 ] File: SMPdesign/DiningPhilosopher5.eps Graphic file (type eps) l2hSize :tex2html_wrap23440:203.05772pt::0.0pt::349.0pt. [57 ] File: SMPdesign/DiningPhilosopher5TB.eps Graphic file (type eps) l2hSize :tex2html_wrap23444:203.05772pt::0.0pt::349.0pt. [58 ] File: SMPdesign/DiningPhilosopher4part-b.eps Graphic file (type eps) l2hSize :tex2html_wrap23448:203.05772pt::0.0pt::349.0pt. [59 ] File: SMPdesign/lockdeq.eps Graphic file (type eps) l2hSize :tex2html_wrap3721:227.8074pt::0.0pt::349.0pt. [60 ] File: SMPdesign/lockdeqpair.eps Graphic file (type eps) l2hSize :tex2html_wrap3731:37.79327pt::0.0pt::349.0pt. [61 ] File: SMPdesign/lockdeqhash.eps Graphic file (type eps) l2hSize :tex2html_wrap3751:91.49954pt::0.0pt::349.0pt. [62 ] File: SMPdesign/lockdeqhash1R.eps Graphic file (type eps) l2hSize :tex2html_wrap3759:377.93294pt::0.0pt::349.0pt. [63 ] File: SMPdesign/lockdeqhashlots.eps Graphic file (type eps) l2hSize :tex2html_wrap3769:72.93103pt::0.0pt::349.0pt. [64 ] l2hSize :figure3600:66.97221pt::0.0pt::349.0pt. [65 ] l2hSize :figure3608:402.58331pt::0.0pt::349.0pt. [66 ] l2hSize :figure3628:458.58331pt::0.0pt::349.0pt. [67 ] File: SMPdesign/LockGranularity.eps Graphic file (type eps) l2hSize :tex2html_wrap23501:200.75pt::0.0pt::349.0pt. [68 ] File: SMPdesign/CPUvsEnet.eps Graphic file (type eps) l2hSize :tex2html_wrap4295:223.69797pt::0.0pt::349.0pt. [69 ] l2hSize :figure3911:202.58331pt::0.0pt::349.0pt. [70 ] l2hSize :figure3923:258.58331pt::0.0pt::349.0pt. [71 ] File: cartoons/OneFighting.eps Graphic file (type eps) l2hSize :tex2html_wrap4331:199.59477pt::0.0pt::349.0pt. [72 ] l2hSize :figure3942:298.58331pt::0.0pt::349.0pt. [73 ] File: cartoons/ManyHappy.eps Graphic file (type eps) l2hSize :tex2html_wrap4349:233.28304pt::0.0pt::349.0pt. [74 ] File: cartoons/ManyFighting.eps Graphic file (type eps) l2hSize :tex2html_wrap4357:208.6218pt::0.0pt::349.0pt. [75 ] l2hSize :tex2html_wrap_inline4213:6.94444pt::0.0pt::6.33339pt. [76 ] l2hSize :tex2html_wrap_inline4215:6.95831pt::6.95831pt::6.52551pt. [77 ] l2hSize :displaymath3985:13.49998pt::0.0pt::349.0pt. [78 ] l2hSize :tex2html_wrap_inline4231:6.45831pt::0.0pt::6.50238pt. [79 ] l2hSize :tex2html_wrap_inline4233:7.44444pt::7.44444pt::10.81952pt. [80 ] l2hSize :tex2html_wrap_inline4235:8.0pt::8.0pt::20.81955pt. [81 ] l2hSize :displaymath3987:23.01347pt::0.0pt::349.0pt. [82 ] l2hSize :displaymath3991:23.01347pt::0.0pt::349.0pt. [83 ] l2hSize :displaymath3995:24.62459pt::0.0pt::349.0pt. [84 ] l2hSize :tex2html_wrap_inline4239:6.83331pt::0.0pt::7.73268pt. [85 ] l2hSize :displaymath3999:28.13123pt::0.0pt::349.0pt. [86 ] l2hSize :tex2html_wrap_inline4241:8.0pt::8.0pt::21.84502pt. [87 ] l2hSize :tex2html_wrap_inline4243:7.44444pt::7.44444pt::6.47229pt. [88 ] l2hSize :displaymath4005:24.06903pt::0.0pt::349.0pt. [89 ] File: SMPdesign/synceff.eps Graphic file (type eps) l2hSize :tex2html_wrap4419:223.69797pt::0.0pt::349.0pt. [90 ] l2hSize :tex2html_wrap_inline4245:6.45831pt::0.0pt::5.1563pt. [91 ] l2hSize :tex2html_wrap_inline4251:7.44444pt::7.44444pt::29.80554pt. [92 ] l2hSize :tex2html_wrap_inline4253:7.44444pt::7.44444pt::34.80556pt. [93 ] File: SMPdesign/matmuleff.eps Graphic file (type eps) l2hSize :tex2html_wrap4429:223.69797pt::0.0pt::349.0pt. [94 ] File: SMPdesign/ParallelFastpath.eps Graphic file (type eps) l2hSize :tex2html_wrap23583:200.75pt::0.0pt::349.0pt. [95 ] l2hSize :figure4061:258.58331pt::0.0pt::349.0pt. [96 ] l2hSize :figure4072:322.58331pt::0.0pt::349.0pt. [97 ] File: SMPdesign/allocatorcache.eps Graphic file (type eps) l2hSize :tex2html_wrap4503:197.91751pt::0.0pt::349.0pt. [98 ] l2hSize :figure4113:131.55554pt::0.0pt::349.0pt. [99 ] File: SMPdesign/AllocatorPool.eps Graphic file (type eps) l2hSize :tex2html_wrap4523:181.84065pt::0.0pt::349.0pt. [100 ] l2hSize :figure4138:202.58331pt::0.0pt::349.0pt. [101 ] l2hSize :figure4146:146.58331pt::0.0pt::349.0pt. [102 ] File: SMPdesign/smpalloc.eps Graphic file (type eps) l2hSize :tex2html_wrap4563:223.69797pt::0.0pt::349.0pt. [103 ] File: locking/LockingTheSlob.eps Graphic file (type eps) l2hSize :tex2html_wrap4728:189.63599pt::0.0pt::349.0pt. [104 ] File: locking/LockingTheHero.eps Graphic file (type eps) l2hSize :tex2html_wrap4734:205.72021pt::0.0pt::349.0pt. [105 ] File: locking/DeadlockCycle.eps Graphic file (type eps) l2hSize :tex2html_wrap4750:302.40633pt::0.0pt::349.0pt. [106 ] l2hSize :figure4646:67.55554pt::0.0pt::349.0pt. [107 ] l2hSize :figure4653:147.55554pt::0.0pt::349.0pt. [108 ] l2hSize :figure4675:226.58331pt::0.0pt::349.0pt. [109 ] l2hSize :figure4838:130.58331pt::0.0pt::349.0pt. [110 ] l2hSize :figure4853:162.58331pt::0.0pt::349.0pt. [111 ] l2hSize :figure4953:218.58331pt::0.0pt::349.0pt. [112 ] l2hSize :figure4966:234.58331pt::0.0pt::349.0pt. [113 ] l2hSize :figure4996:146.58331pt::0.0pt::349.0pt. [114 ] l2hSize :figure5020:338.58331pt::0.0pt::349.0pt. [115 ] l2hSize :figure5249:123.55554pt::0.0pt::349.0pt. [116 ] File: defer/Linux_list.eps Graphic file (type eps) l2hSize :tex2html_wrap5623:57.3082pt::0.0pt::349.0pt. [117 ] File: defer/Linux_list_abbr.eps Graphic file (type eps) l2hSize :tex2html_wrap5629:23.74065pt::0.0pt::349.0pt. [118 ] l2hSize :figure5333:131.55554pt::0.0pt::349.0pt. [119 ] File: defer/Linux_hlist.eps Graphic file (type eps) l2hSize :tex2html_wrap5669:47.67868pt::0.0pt::349.0pt. [120 ] l2hSize :figure5366:131.55554pt::0.0pt::349.0pt. [121 ] File: defer/GracePeriodGood.eps Graphic file (type eps) l2hSize :tex2html_wrap5725:128.73616pt::0.0pt::349.0pt. [122 ] l2hSize :figure5435:179.55554pt::0.0pt::349.0pt. [123 ] File: defer/RCUDeletion.eps Graphic file (type eps) l2hSize :tex2html_wrap5771:245.6564pt::0.0pt::349.0pt. [124 ] File: defer/RCUReplacement.eps Graphic file (type eps) l2hSize :tex2html_wrap5791:496.7795pt::0.0pt::349.0pt. [125 ] File: defer/rwlockRCUperf.eps Graphic file (type eps) l2hSize :tex2html_wrap6134:215.09421pt::0.0pt::349.0pt. [126 ] File: defer/rwlockRCUperfPREEMPT.eps Graphic file (type eps) l2hSize :tex2html_wrap6148:215.09421pt::0.0pt::349.0pt. [127 ] File: defer/rwlockRCUperfwtPREEMPT.eps Graphic file (type eps) l2hSize :tex2html_wrap6156:215.09421pt::0.0pt::349.0pt. [128 ] File: defer/rwlockRCUupdate.eps Graphic file (type eps) l2hSize :tex2html_wrap6200:150.43407pt::0.0pt::349.0pt. [129 ] l2hSize :figurestar5961:82.97221pt::0.0pt::349.0pt. [130 ] l2hSize :figurestar5967:130.58331pt::0.0pt::349.0pt. [131 ] l2hSize :figurestar5973:146.58331pt::0.0pt::349.0pt. [132 ] File: defer/refRCUperfPREEMPT.eps Graphic file (type eps) l2hSize :tex2html_wrap6278:215.09421pt::0.0pt::349.0pt. [133 ] File: defer/refRCUperfwtPREEMPT.eps Graphic file (type eps) l2hSize :tex2html_wrap6290:215.09421pt::0.0pt::349.0pt. [134 ] l2hSize :figure6041:210.58331pt::0.0pt::349.0pt. [135 ] l2hSize :figure6078:226.58331pt::0.0pt::349.0pt. [136 ] File: defer/RCUenvAPI.eps Graphic file (type eps) l2hSize :tex2html_wrap6783:147.83318pt::0.0pt::349.0pt. [137 ] l2hSize :figure6812:130.58331pt::0.0pt::349.0pt. [138 ] l2hSize :figure6837:162.58331pt::0.0pt::349.0pt. [139 ] l2hSize :figure6864:186.58331pt::0.0pt::349.0pt. [140 ] l2hSize :figure6904:50.97221pt::0.0pt::349.0pt. [141 ] l2hSize :figure6910:234.58331pt::0.0pt::349.0pt. [142 ] l2hSize :figure6949:178.58331pt::0.0pt::349.0pt. [143 ] l2hSize :figure6990:50.97221pt::0.0pt::349.0pt. [144 ] l2hSize :figure6996:234.58331pt::0.0pt::349.0pt. [145 ] l2hSize :figure7014:218.58331pt::0.0pt::349.0pt. [146 ] l2hSize :tex2html_wrap_inline7334:6.83331pt::0.0pt::14.62502pt. [147 ] l2hSize :figure7039:50.97221pt::0.0pt::349.0pt. [148 ] l2hSize :figure7045:234.58331pt::0.0pt::349.0pt. [149 ] l2hSize :figure7064:306.58331pt::0.0pt::349.0pt. [150 ] l2hSize :tex2html_wrap_inline7336:8.0pt::8.0pt::22.85002pt. [151 ] l2hSize :figure7106:43.55554pt::0.0pt::349.0pt. [152 ] l2hSize :figure7112:250.58331pt::0.0pt::349.0pt. [153 ] l2hSize :figure7164:59.55554pt::0.0pt::349.0pt. [154 ] l2hSize :figure7170:330.58331pt::0.0pt::349.0pt. [155 ] l2hSize :figure7228:35.55554pt::0.0pt::349.0pt. [156 ] l2hSize :figure7234:234.58331pt::0.0pt::349.0pt. [157 ] l2hSize :figure7277:154.58331pt::0.0pt::349.0pt. [158 ] *** image for figure7817 is too tall at 570.58331pt, reducing to .95 vsize *** l2hSize :figure7817:566.41429pt::0.0pt::349.0pt. [159 ] File: appendix/whymb/cacheSC.eps Graphic file (type eps) l2hSize :tex2html_wrap9088:145.2058pt::0.0pt::349.0pt. [160 ] File: cartoons/CPU_toon_outoforder_colored.eps Graphic file (type eps) l2hSize :tex2html_wrap9096:144.54237pt::0.0pt::349.0pt. [161 ] l2hSize :figure8120:274.8333pt::0.0pt::349.0pt. [162 ] l2hSize :figure8147:106.8333pt::0.0pt::349.0pt. [163 ] File: advsync/MoreThanOneValue.eps Graphic file (type eps) l2hSize :tex2html_wrap9152:67.96632pt::0.0pt::349.0pt. [164 ] File: advsync/AbstractMemoryAccessModel.eps Graphic file (type eps) l2hSize :tex2html_wrap24401:124.465pt::0.0pt::349.0pt. [165 ] l2hSize :tex2html_wrap_inline9032:6.45831pt::0.0pt::10.50005pt. [166 ] l2hSize :tex2html_wrap_inline9060:7.44444pt::7.44444pt::4.94447pt. [167 ] File: advsync/MemoryBarrierPairing.eps Graphic file (type eps) l2hSize :tex2html_wrap24606:52.19499pt::0.0pt::349.0pt. [168 ] File: advsync/WriteBarrierOrdering.eps Graphic file (type eps) Overfull \hbox (38.4475pt too wide) detected at line 4052 [] [] l2hSize :tex2html_wrap24615:139.52124pt::0.0pt::349.0pt. [169 ] File: advsync/DataDependencyNeeded.eps Graphic file (type eps) Overfull \hbox (36.43999pt too wide) detected at line 4058 [] [] l2hSize :tex2html_wrap24634:175.65625pt::0.0pt::349.0pt. [170 ] File: advsync/DataDependencySupplied.eps Graphic file (type eps) l2hSize :tex2html_wrap24655:160.59999pt::0.0pt::349.0pt. [171 ] File: advsync/ReadBarrierNeeded.eps Graphic file (type eps) l2hSize :tex2html_wrap24672:132.495pt::0.0pt::349.0pt. [172 ] File: advsync/ReadBarrierSupplied.eps Graphic file (type eps) l2hSize :tex2html_wrap24691:124.465pt::0.0pt::349.0pt. [173 ] File: advsync/ReadBarrierSupplied1.eps Graphic file (type eps) l2hSize :tex2html_wrap24712:146.54749pt::0.0pt::349.0pt. [174 ] File: advsync/ReadBarrierSupplied2.eps Graphic file (type eps) l2hSize :tex2html_wrap24716:146.54749pt::0.0pt::349.0pt. [175 ] File: advsync/SpeculativeLoad.eps Graphic file (type eps) Overfull \hbox (2.3125pt too wide) detected at line 4095 [] [] l2hSize :tex2html_wrap24732:98.3675pt::0.0pt::349.0pt. [176 ] File: advsync/SpeculativeLoadBarrier.eps Graphic file (type eps) Overfull \hbox (2.3125pt too wide) detected at line 4101 [] [] l2hSize :tex2html_wrap24749:117.43874pt::0.0pt::349.0pt. [177 ] File: advsync/SpeculativeLoadBarrierCancel.eps Graphic file (type eps) Overfull \hbox (2.3125pt too wide) detected at line 4107 [] [] l2hSize :tex2html_wrap24753:120.45pt::0.0pt::349.0pt. [178 ] File: advsync/MemoryArchitecture.eps Graphic file (type eps) Overfull \hbox (32.42499pt too wide) detected at line 4121 [] [] l2hSize :tex2html_wrap24826:157.58875pt::0.0pt::349.0pt. [179 ] File: advsync/SplitCache.eps Graphic file (type eps) l2hSize :tex2html_wrap24831:142.53249pt::0.0pt::349.0pt. [180 ] File: easy/Mandel_zoom_00_mandelbrot_set.eps Graphic file (type eps) l2hSize :tex2html_wrap10030:162.60455pt::0.0pt::349.0pt. [181 ] l2hSize :tex2html_wrap_inline10002:7.33331pt::7.33331pt::26.84715pt. [182 ] File: cartoons/ShavingTheMandelbrotSet.eps Graphic file (type eps) l2hSize :tex2html_wrap10082:148.3875pt::0.0pt::349.0pt. [183 ] l2hSize :figure10510:162.58331pt::0.0pt::349.0pt. [184 ] l2hSize :figure10516:426.58331pt::0.0pt::349.0pt. [185 ] File: appendix/questions/after.eps Graphic file (type eps) l2hSize :tex2html_wrap24953:214.80249pt::0.0pt::349.0pt. [186 ] l2hSize :figurestar10660:58.69023pt::0.0pt::349.0pt. [187 ] l2hSize :figure10700:74.58331pt::0.0pt::349.0pt. [188 ] l2hSize :figure10710:178.58331pt::0.0pt::349.0pt. [189 ] l2hSize :figure10719:43.55554pt::0.0pt::349.0pt. [190 ] l2hSize :figure10757:51.55554pt::0.0pt::349.0pt. [191 ] l2hSize :figure11046:180.0pt::0.0pt::349.0pt. [192 ] File: appendix/whymb/MESI.eps Graphic file (type eps) l2hSize :tex2html_wrap25044:164.61499pt::0.0pt::349.0pt. [193 ] File: appendix/whymb/cacheSCwrite.eps Graphic file (type eps) l2hSize :tex2html_wrap25139:179.67125pt::0.0pt::349.0pt. [194 ] File: appendix/whymb/cacheSB.eps Graphic file (type eps) l2hSize :tex2html_wrap12142:193.93927pt::0.0pt::349.0pt. [195 ] File: appendix/whymb/cacheSBf.eps Graphic file (type eps) l2hSize :tex2html_wrap12164:193.93927pt::0.0pt::349.0pt. [196 ] File: appendix/whymb/cacheSBfIQ.eps Graphic file (type eps) l2hSize :tex2html_wrap12214:225.7652pt::0.0pt::349.0pt. [197 ] File: appendix/whymb/hostileordering.eps Graphic file (type eps) l2hSize :tex2html_wrap12290:167.08614pt::0.0pt::349.0pt. [198 ] l2hSize :picture11457:185.0pt::0.0pt::349.0pt. [199 ] l2hSize :picture11461:185.0pt::0.0pt::349.0pt. [200 ] l2hSize :picture11465:185.0pt::0.0pt::349.0pt. [201 ] l2hSize :picture11469:185.0pt::0.0pt::349.0pt. [202 ] l2hSize :picture11473:185.0pt::0.0pt::349.0pt. [203 ] l2hSize :picture11477:185.0pt::0.0pt::349.0pt. [204 ] l2hSize :picture11481:185.0pt::0.0pt::349.0pt. [205 ] l2hSize :picture11485:185.0pt::0.0pt::349.0pt. [206 ] LaTeX Font Info: Try loading font information for OMS+cmr on input line 4604 . (/usr/share/texmf-texlive/tex/latex/base/omscmr.fd File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 4604. l2hSize :tex2html_nomath_inline12382:5.58475pt::5.58475pt::10.50005pt. [207 ] l2hSize :figure11518:218.58331pt::0.0pt::349.0pt. [208 ] l2hSize :figure11530:170.0pt::0.0pt::349.0pt. [209 ] l2hSize :figure11565:218.58331pt::0.0pt::349.0pt. [210 ] File: cartoons/LD,ACQ.eps Graphic file (type eps) l2hSize :tex2html_wrap12588:144.54118pt::0.0pt::349.0pt. [211 ] File: cartoons/RCUCallbacks.eps Graphic file (type eps) l2hSize :tex2html_wrap13178:140.92395pt::0.0pt::349.0pt. [212 ] l2hSize :figure12922:59.55554pt::0.0pt::349.0pt. [213 ] l2hSize :figure13015:194.58331pt::0.0pt::349.0pt. [214 ] l2hSize :figure13049:74.97221pt::0.0pt::349.0pt. [215 ] File: appendix/rcuimpl/srcuds.eps Graphic file (type eps) l2hSize :tex2html_wrap25484:153.57375pt::0.0pt::349.0pt. [216 ] l2hSize :figure13069:74.58331pt::0.0pt::349.0pt. [217 ] l2hSize :figure13089:242.58331pt::0.0pt::349.0pt. [218 ] l2hSize :figure13109:114.58331pt::0.0pt::349.0pt. [219 ] l2hSize :figure13122:74.58331pt::0.0pt::349.0pt. [220 ] l2hSize :figure13147:162.58331pt::0.0pt::349.0pt. [221 ] File: appendix/rcuimpl/FlatClassicRCU.eps Graphic file (type eps) l2hSize :tex2html_wrap13916:145.52943pt::0.0pt::349.0pt. [222 ] File: appendix/rcuimpl/TreeClassicRCU.eps Graphic file (type eps) l2hSize :tex2html_wrap13940:190.07925pt::0.0pt::349.0pt. [223 ] File: appendix/rcuimpl/TreeMapping.eps Graphic file (type eps) l2hSize :tex2html_wrap13950:63.48163pt::0.0pt::349.0pt. [224 ] File: appendix/rcuimpl/TreeClassicRCUGP.eps Graphic file (type eps) l2hSize :tex2html_wrap13958:180.98091pt::0.0pt::349.0pt. [225 ] File: appendix/rcuimpl/BigTreeClassicRCU.eps Graphic file (type eps) l2hSize :tex2html_wrap13966:194.53424pt::0.0pt::349.0pt. [226 ] File: appendix/rcuimpl/BigTreeClassicRCUBH.eps Graphic file (type eps) l2hSize :tex2html_wrap13988:250.04889pt::0.0pt::349.0pt. [227 ] File: appendix/rcuimpl/BigTreeClassicRCUBHdyntick.eps Graphic file (type eps) l2hSize :tex2html_wrap14010:326.0131pt::0.0pt::349.0pt. [228 ] File: appendix/rcuimpl/GenericRCUStateMachine.eps Graphic file (type eps) l2hSize :tex2html_wrap14022:507.09908pt::0.0pt::349.0pt. [229 ] File: appendix/rcuimpl/TreeRCUStateMachine.eps Graphic file (type eps) l2hSize :tex2html_wrap14034:355.43556pt::0.0pt::349.0pt. [230 ] Overfull \hbox (23.74675pt too wide) in paragraph at lines 5095--5095 [] \OT1/cmtt/m/n/10 15 # define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT)[] [] Overfull \hbox (55.24648pt too wide) in paragraph at lines 5095--5095 [] \OT1/cmtt/m/n/10 21 # define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ)[] [] Overfull \hbox (44.74657pt too wide) in paragraph at lines 5095--5095 [] \OT1/cmtt/m/n/10 22 # define NUM_RCU_LVL_2 (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT))[] [] Overfull \hbox (86.7462pt too wide) in paragraph at lines 5095--5095 [] \OT1/cmtt/m/n/10 28 #define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU _LVL_2 + NUM_RCU_LVL_3)[] [] l2hSize :figurestar14631:358.95135pt::0.0pt::349.0pt. [231 ] l2hSize :figure14685:226.58331pt::0.0pt::349.0pt. [232 ] l2hSize :figure14704:386.58331pt::0.0pt::349.0pt. [233 ] l2hSize :figure14737:378.58331pt::0.0pt::349.0pt. [234 ] l2hSize :figure14774:250.58331pt::0.0pt::349.0pt. [235 ] l2hSize :figure14806:234.58331pt::0.0pt::349.0pt. [236 ] File: appendix/rcuimpl/RCUTreeInit.eps Graphic file (type eps) Overfull \hbox (84.63695pt too wide) detected at line 5352 [] [] l2hSize :tex2html_wrap16031:243.06491pt::0.0pt::349.0pt. [237 ] l2hSize :figure14860:210.0pt::0.0pt::349.0pt. [238 ] l2hSize :figure14891:298.58331pt::0.0pt::349.0pt. [239 ] l2hSize :figure14939:234.58331pt::0.0pt::349.0pt. [240 ] l2hSize :figure14996:354.58331pt::0.0pt::349.0pt. [241 ] l2hSize :figure15031:122.58331pt::0.0pt::349.0pt. [242 ] l2hSize :figure15051:386.58331pt::0.0pt::349.0pt. [243 ] l2hSize :figure15120:250.58331pt::0.0pt::349.0pt. [244 ] l2hSize :figure15147:210.58331pt::0.0pt::349.0pt. [245 ] l2hSize :figure15172:170.58331pt::0.0pt::349.0pt. [246 ] File: appendix/rcuimpl/AdvanceRCUCallbacks.eps Graphic file (type eps) l2hSize :tex2html_wrap16247:194.84793pt::0.0pt::349.0pt. [247 ] l2hSize :figure15201:386.58331pt::0.0pt::349.0pt. [248 ] l2hSize :figure15281:114.58331pt::0.0pt::349.0pt. [249 ] l2hSize :figure15300:114.58331pt::0.0pt::349.0pt. [250 ] l2hSize :figure15317:218.58331pt::0.0pt::349.0pt. [251 ] l2hSize :figure15336:226.58331pt::0.0pt::349.0pt. [252 ] File: appendix/rcuimpl/RCUTreeQSScan.eps Graphic file (type eps) Overfull \hbox (84.63695pt too wide) detected at line 5939 [] [] l2hSize :tex2html_wrap16365:243.06491pt::0.0pt::349.0pt. [253 ] l2hSize :figure15384:362.58331pt::0.0pt::349.0pt. [254 ] l2hSize :figure15412:210.58331pt::0.0pt::349.0pt. [255 ] l2hSize :figure15433:171.55554pt::0.0pt::349.0pt. [256 ] l2hSize :figure15454:202.58331pt::0.0pt::349.0pt. [257 ] l2hSize :figure15479:146.58331pt::0.0pt::349.0pt. [258 ] l2hSize :figure15505:170.58331pt::0.0pt::349.0pt. [259 ] l2hSize :figure15545:106.58331pt::0.0pt::349.0pt. [260 ] l2hSize :figure15564:114.58331pt::0.0pt::349.0pt. [261 ] l2hSize :figure15577:330.58331pt::0.0pt::349.0pt. [262 ] File: appendix/rcuimpl/RCUTreeLeafScan.eps Graphic file (type eps) Overfull \hbox (84.64957pt too wide) detected at line 6277 [] [] l2hSize :tex2html_wrap16521:236.23363pt::0.0pt::349.0pt. [263 ] l2hSize :figure15622:506.58331pt::0.0pt::349.0pt. [264 ] l2hSize :figure15680:66.58331pt::0.0pt::349.0pt. [265 ] l2hSize :figure15688:138.58331pt::0.0pt::349.0pt. [266 ] l2hSize :figure15704:154.58331pt::0.0pt::349.0pt. [267 ] l2hSize :figure15715:290.58331pt::0.0pt::349.0pt. [268 ] File: appendix/rcuimpl/GracePeriodBad.eps Graphic file (type eps) l2hSize :tex2html_wrap17165:118.35268pt::0.0pt::349.0pt. [269 ] File: appendix/rcuimpl/GracePeriodGood.eps Graphic file (type eps) l2hSize :tex2html_wrap17175:128.73616pt::0.0pt::349.0pt. [270 ] File: appendix/rcuimpl/RCUpreemptListsCompare.eps Graphic file (type eps) l2hSize :tex2html_wrap17189:243.63168pt::0.0pt::349.0pt. [271 ] File: appendix/rcuimpl/RCUpreemptCounterFlip.eps Graphic file (type eps) l2hSize :tex2html_wrap17199:165.60275pt::0.0pt::349.0pt. [272 ] File: appendix/rcuimpl/RCUpreemptLists.eps Graphic file (type eps) l2hSize :tex2html_wrap17239:222.00435pt::0.0pt::349.0pt. [273 ] File: appendix/rcuimpl/RCUpreemptStates.eps Graphic file (type eps) l2hSize :tex2html_wrap17281:252.01941pt::0.0pt::349.0pt. [274 ] File: appendix/rcuimpl/RCUpreemptTimeline.eps Graphic file (type eps) l2hSize :tex2html_wrap17289:248.35974pt::0.0pt::349.0pt. [275 ] l2hSize :figure16854:114.58331pt::0.0pt::349.0pt. [276 ] l2hSize :figure16866:66.58331pt::0.0pt::349.0pt. [277 ] l2hSize :figure16875:234.58331pt::0.0pt::349.0pt. [278 ] l2hSize :figure16884:138.58331pt::0.0pt::349.0pt. [279 ] l2hSize :figure16893:122.58331pt::0.0pt::349.0pt. [280 ] l2hSize :figure16904:162.58331pt::0.0pt::349.0pt. [281 ] l2hSize :figure16913:122.58331pt::0.0pt::349.0pt. [282 ] l2hSize :figure16921:362.58331pt::0.0pt::349.0pt. [283 ] l2hSize :figure16940:170.58331pt::0.0pt::349.0pt. [284 ] l2hSize :figure16989:162.58331pt::0.0pt::349.0pt. [285 ] File: appendix/rcuimpl/RCUrt-MBwaste.eps Graphic file (type eps) l2hSize :tex2html_wrap17433:260.90019pt::0.0pt::349.0pt. [286 ] File: appendix/rcuimpl/RCUrt-MBnowaste.eps Graphic file (type eps) l2hSize :tex2html_wrap17441:223.9691pt::0.0pt::349.0pt. [287 ] File: appendix/rcuimpl/RCUpreemptValidation.eps Graphic file (type eps) l2hSize :tex2html_wrap17463:274.25969pt::0.0pt::349.0pt. [288 ] l2hSize :figure17517:330.58331pt::0.0pt::349.0pt. [289 ] l2hSize :figure17537:171.55554pt::0.0pt::349.0pt. [290 ] l2hSize :figurestar17553:347.55554pt::0.0pt::349.0pt. [291 ] l2hSize :figure17562:90.58331pt::0.0pt::349.0pt. [292 ] l2hSize :figure17568:186.58331pt::0.0pt::349.0pt. [293 ] l2hSize :figure17642:142.0pt::0.0pt::349.0pt. [294 ] l2hSize :figure17648:166.8333pt::0.0pt::349.0pt. [295 ] l2hSize :figure17661:178.0pt::0.0pt::349.0pt. [296 ] l2hSize :figure17674:538.8333pt::0.0pt::349.0pt. [297 ] l2hSize :figure17691:194.58331pt::0.0pt::349.0pt. [298 ] l2hSize :figure17734:119.38887pt::0.0pt::349.0pt. [299 ] l2hSize :figure17749:250.8333pt::0.0pt::349.0pt. [300 ] l2hSize :figure17759:178.8333pt::0.0pt::349.0pt. [301 ] l2hSize :figure17770:474.58331pt::0.0pt::349.0pt. [302 ] l2hSize :figure17788:286.8333pt::0.0pt::349.0pt. [303 ] l2hSize :figure18533:114.58331pt::0.0pt::349.0pt. [304 ] l2hSize :figure18539:27.55554pt::0.0pt::349.0pt. [305 ] l2hSize :figure18565:106.97221pt::0.0pt::349.0pt. [306 ] l2hSize :figure18595:226.58331pt::0.0pt::349.0pt. [307 ] l2hSize :figure18612:202.58331pt::0.0pt::349.0pt. [308 ] l2hSize :figure18629:218.58331pt::0.0pt::349.0pt. [309 ] l2hSize :figure18648:146.58331pt::0.0pt::349.0pt. [310 ] l2hSize :figure18662:170.58331pt::0.0pt::349.0pt. [311 ] File: count/GlobalTreeInc.eps Graphic file (type eps) l2hSize :tex2html_wrap21734:140.233pt::0.0pt::349.0pt. [312 ] l2hSize :tex2html_wrap_inline21484:8.0pt::8.0pt::38.46461pt. [313 ] l2hSize :tex2html_wrap_inline21488:8.0pt::8.0pt::25.30835pt. [314 ] l2hSize :figure19582:314.58331pt::0.0pt::349.0pt. [315 ] File: SMPdesign/DiningPhilosopher5PEM.eps Graphic file (type eps) l2hSize :tex2html_wrap26086:203.05772pt::0.0pt::349.0pt. [316 ] l2hSize :tex2html_wrap_inline21490:6.95831pt::6.95831pt::37.19217pt. [317 ] l2hSize :figure19943:130.8333pt::0.0pt::349.0pt. [318 ] l2hSize :figure20035:282.58331pt::0.0pt::349.0pt. [319 ] l2hSize :figure20100:119.38887pt::0.0pt::349.0pt. [320 ] l2hSize :figure20126:107.38887pt::0.0pt::349.0pt. [321 ] l2hSize :figure20136:162.58331pt::0.0pt::349.0pt. [322 ] l2hSize :displaymath20404:21.4579pt::0.0pt::349.0pt. [323 ] l2hSize :tex2html_wrap_inline21500:6.45831pt::0.0pt::4.55907pt. [324 ] l2hSize :tex2html_wrap_inline21502:7.33331pt::7.33331pt::10.77203pt. [325 ] l2hSize :tex2html_wrap_inline21504:7.33331pt::7.33331pt::11.42221pt. [326 ] l2hSize :tex2html_wrap_inline21512:7.33331pt::7.33331pt::31.84717pt. [327 ] l2hSize :tex2html_wrap_inline21514:7.33331pt::7.33331pt::26.84715pt. [328 ] (./images.aux) ) Here is how much of TeX's memory you used: 5815 strings out of 495062 88508 string characters out of 1182643 163390 words of memory out of 3000000 8809 multiletter control sequences out of 15000+50000 6621 words of font info for 25 fonts, out of 3000000 for 9000 28 hyphenation exceptions out of 8191 38i,10n,36p,253b,327s stack positions out of 5000i,500n,10000p,200000b,50000s Output written on images.dvi (331 pages, 376028 bytes). perfbook_html/node356.html0000644000175000017500000001407511672746163015660 0ustar paulmckpaulmck D.2.7.7 Note That a CPU is in Dynticks Idle Mode


D.2.7.7 Note That a CPU is in Dynticks Idle Mode

The force_quiescent_state() function implements a three-phase state machine. The first phase (RCU_INITIALIZING) waits for rcu_start_gp() to complete grace-period initialization. This state is not exited by force_quiescent_state(), but rather by rcu_start_gp().

In the second phase (RCU_SAVE_DYNTICK), the dyntick_save_progress_counter() function scans the CPUs that have not yet reported a quiescent state, recording their per-CPU dynticks and dynticks_nmi counters. If these counters both have even-numbered values, then the corresponding CPU is in dynticks-idle state, which is therefore noted as an extended quiescent state (reported via cpu_quiet_msk()).

In the third phase (RCU_FORCE_QS), the rcu_implicit_dynticks_qs() function again scans the CPUs that have not yet reported a quiescent state (either explicitly or implicitly during the RCU_SAVE_DYNTICK phase), again checking the per-CPU dynticks and dynticks_nmi counters. If each of these has either changed in value or is now even, then the corresponding CPU has either passed through or is now in dynticks idle, which as before is noted as an extended quiescent state.

If rcu_implicit_dynticks_qs() finds that a given CPU has neither been in dynticks idle mode nor reported a quiescent state, it invokes rcu_implicit_offline_qs(), which checks to see if that CPU is offline, which is also reported as an extended quiescent state. If the CPU is online, then rcu_implicit_offline_qs() sends it a reschedule IPI in an attempt to remind it of its duty to report a quiescent state to RCU.

Note that force_quiescent_state() does not directly invoke either dyntick_save_progress_counter() or rcu_implicit_dynticks_qs(), instead passing these functions to an intervening rcu_process_dyntick() function that abstracts out the common code involved in scanning the CPUs and reporting extended quiescent states.

Quick Quiz D.13: And what happens if one CPU comes out of dyntick-idle mode and then passed through a quiescent state just as another CPU notices that the first CPU was in dyntick-idle mode? Couldn't they both attempt to report a quiescent state at the same time, resulting in confusion? End Quick Quiz

Quick Quiz D.14: But what if all the CPUs end up in dyntick-idle mode? Wouldn't that prevent the current RCU grace period from ever ending? End Quick Quiz

Quick Quiz D.15: Given that force_quiescent_state() is a three-phase state machine, don't we have triple the scheduling latency due to scanning all the CPUs? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node445.html0000644000175000017500000001645111672746163015657 0ustar paulmckpaulmck E.7.2.2 Validating Safety


E.7.2.2 Validating Safety

A safe RCU implementation must never permit a grace period to complete before the completion of any RCU readers that started before the start of the grace period. This is modeled by a grace_period_state variable that can take on three states as follows:



  1 #define GP_IDLE    0
  2 #define GP_WAITING  1
  3 #define GP_DONE    2
  4 byte grace_period_state = GP_DONE;


The grace_period() process sets this variable as it progresses through the grace-period phases, as shown below:

  1 proctype grace_period()
  2 {
  3   byte curr;
  4   byte snap;
  5
  6   grace_period_state = GP_IDLE;
  7   atomic {
  8     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);
  9     snap = dynticks_progress_counter;
 10     grace_period_state = GP_WAITING;
 11   }
 12   do
 13   :: 1 ->
 14     atomic {
 15       curr = dynticks_progress_counter;
 16       if
 17       :: (curr == snap) && ((curr & 1) == 0) ->
 18         break;
 19       :: (curr - snap) > 2 || (snap & 1) == 0 ->
 20         break;
 21       :: 1 -> skip;
 22       fi;
 23     }
 24   od;
 25   grace_period_state = GP_DONE;
 26   grace_period_state = GP_IDLE;
 27   atomic {
 28     snap = dynticks_progress_counter;
 29     grace_period_state = GP_WAITING;
 30   }
 31   do
 32   :: 1 ->
 33     atomic {
 34       curr = dynticks_progress_counter;
 35       if
 36       :: (curr == snap) && ((curr & 1) == 0) ->
 37         break;
 38       :: (curr != snap) ->
 39         break;
 40       :: 1 -> skip;
 41       fi;
 42     }
 43   od;
 44   grace_period_state = GP_DONE;
 45 }

Lines 6, 10, 25, 26, 29, and 44 update this variable (combining atomically with algorithmic operations where feasible) to allow the dyntick_nohz() process to verify the basic RCU safety property. The form of this verification is to assert that the value of the grace_period_state variable cannot jump from GP_IDLE to GP_DONE during a time period over which RCU readers could plausibly persist.

Quick Quiz E.13: Given there are a pair of back-to-back changes to grace_period_state on lines 25 and 26, how can we be sure that line 25's changes won't be lost? End Quick Quiz

The dyntick_nohz() Promela process implements this verification as shown below:

  1 proctype dyntick_nohz()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   bit old_gp_idle;
  6
  7   do
  8   :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;
  9   :: i < MAX_DYNTICK_LOOP_NOHZ ->
 10     tmp = dynticks_progress_counter;
 11     atomic {
 12       dynticks_progress_counter = tmp + 1;
 13       old_gp_idle = (grace_period_state == GP_IDLE);
 14       assert((dynticks_progress_counter & 1) == 1);
 15     }
 16     atomic {
 17       tmp = dynticks_progress_counter;
 18       assert(!old_gp_idle ||
 19              grace_period_state != GP_DONE);
 20     }
 21     atomic {
 22       dynticks_progress_counter = tmp + 1;
 23       assert((dynticks_progress_counter & 1) == 0);
 24     }
 25     i++;
 26   od;
 27 }

Line 13 sets a new old_gp_idle flag if the value of the grace_period_state variable is GP_IDLE at the beginning of task execution, and the assertion at lines 18 and 19 fire if the grace_period_state variable has advanced to GP_DONE during task execution, which would be illegal given that a single RCU read-side critical section could span the entire intervening time period.

The resulting model (dyntickRCU-base-s.spin), when run with the runspin.sh script, generates 964 states and passes without errors, which is reassuring. That said, although safety is critically important, it is also quite important to avoid indefinitely stalling grace periods. The next section therefore covers verifying liveness.

Paul E. McKenney 2011-12-16
perfbook_html/node260.html0000644000175000017500000001316211672746162015645 0ustar paulmckpaulmck 17.1.11 Debugging


17.1.11 Debugging

The usual debugging operations such as breakpoints work normally within lock-based critical sections and from RCU read-side critical sections. However, in initial transactional-memory hardware implementations [DLMN09] an exception within a transaction will abort that transaction, which in turn means that breakpoints abort all enclosing transactions

So how can transactions be debugged?

  1. Use software emulation techniques within transactions containing breakpoints. Of course, it might be necessary to emulate all transactions any time a breakpoint is set within the scope of any transaction. If the runtime system is unable to determine whether or not a given breakpoint is within the scope of a transaction, then it might be necessary to emulate all transactions just to be on the safe side. However, this approach might impose significant overhead, which might in turn obscure the bug being pursued.
  2. Use only hardware TM implementations that are capable of handling breakpoint exceptions. Unfortunately, as of this writing (September 2008), all such implementations are strictly research prototypes.
  3. Use only software TM implementations, which are (very roughly speaking) more tolerant of exceptions than are the simpler of the hardware TM implementations. Of course, software TM tends to have higher overhead than hardware TM, so this approach may not be acceptable in all situations.
  4. Program more carefully, so as to avoid having bugs in the transactions in the first place. As soon as you figure out how to do this, please do let everyone know the secret!

There is some reason to believe that transactional memory will deliver productivity improvements compared to other synchronization mechanisms, but it does seem quite possible that these improvements could easily be lost if traditional debugging techniques cannot be applied to transactions. This seems especially true if transactional memory is to be used by novices on large transactions. In contrast, macho ``top-gun'' programmers might be able to dispense with such debugging aids, especially for small transactions.

Therefore, if transactional memory is to deliver on its productivity promises to novice programmers, the debugging problem does need to be solved.

Paul E. McKenney 2011-12-16
perfbook_html/node485.html0000644000175000017500000000511211672746164015654 0ustar paulmckpaulmck H.6 Other Support

H.6 Other Support

We owe thanks to many CPU architects for patiently explaining the instruction- and memory-reordering features of their CPUs, particularly Wayne Cardoza, Ed Silha, Anton Blanchard, Tim Slegel, Juergen Probst, Ingo Adlung, and Ravi Arimilli. Wayne deserves special thanks for his patience in explaining Alpha's reordering of dependent loads, a lesson that Paul resisted quite strenuously!

Portions of this material are based upon work supported by the National Science Foundation under Grant No. CNS-0719851.



Paul E. McKenney 2011-12-16
perfbook_html/img131.png0000644000175000017500000001225111672746002015300 0ustar paulmckpaulmckPNG  IHDRB*0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@f'IDATx]}x\[KVq'Ie]J RPx6Î9Fj,N:eA-6*%(2RL)\ҔR ӫPzmpC 6Λf;s3}y~|ߏ](U![9@mچɵP13 -~4 @h)J" ]`p'|tA$J.Y*YGb~('h|u4F/\6VjڹpgD!hυIG+d υ$-WԸK˺EӋYh[?Ivp@,Jn=m9Y ǯ}qMqa`>y3c>}DN:W} \E5MqpaXXxq Dd`Ȯ'@Јp&ѠlICuQ(-zxe׾A[/i!RM1iSv[.,E&DQ\Nt=)vԹTgJ;w23/`VyIמ\BfBl w>*vGG3Ar5WTZnCSp)͙nbߵ$ͮNd&EzsX,D)M9Y F?R\dJ+aK\jK%_V؃Dowsc_.P "d܉~q@T8E\V%q8H'n&I_qcoqϵҰ;@wR-/}CqR9Y5~4B06?9J܈3q}DqE+tDњM޸C+Z:#-4!Бit1s>!fVBQavq 7 p |@ɫ^t:߄7zXI{/OFg\N12c]f:S2Vh28<(<&7I͈y#+}$l4%…#[`QX/H4Hi);pr|72JVKSDЭ(.JGH8\ U`B®8;q[gݓPIx20ϋpO-j|3uðǟg'ox#L,̚Yg6MF"4x}S7Wb߭sh Iҍo%VҾtH׸kv@~2kW(`2I(pn w 555`+#́LQ'v&=cmWΤfD#*qۙԌ=F}v&cK;F6(Qig H ԨY0001.KG>taa wGI-Ί%A~J>ϑ=]ӯ@4)#bI!SFx1!#_3IB޻z|`>^tKa  ?˚~)!i$~&= RD6ދDӽu{ }txH 'g O:`(Mp|q>K*o =㔱ۯPx~]GX:ȌnK_[%-Lˈ% AD dPb[!jB%M rO*h ,¹)vwkV^(j sgcO!1Rf!pd -zoϥ@| MLr{ef*}/O=Kq2VN}@*w 4*tъR;ߣve~:},_ksXۜ $%$I#Ys n[41*: ctIi'x3c>nLm_'aFܘTqf}22MK1V(pYysI> D{~wV>$ktŒ>ni}{^Ju"/`I^އ8T T RJ+gTVel1*jabjmT~,/RZ20Xz,c%vJ/AIXX$^줹^w[ -aIq܏>Bbo^玛sgs"=)-IC00RZ@kvOU/`j1_# ZXTO@KjveZ2\N yj^skAo_І51-YmzѦg^vA#j@j5&@Scv88xB6mGʇ,C嚅eÚٱfavYkf/zWB VB,S^ EPOY v㧬J.6iL䧐SJgqB()7ޞF4y \rZsw+t.oѭabe@sҦ¶T+ I@4+f[FZ/0J ]I$ X  oUS-Wt$1,G>V+-sj]߂Une$Pa }؟?CGj5P=(쀏v0k!һ[Upz']/F#oix| T:8BU.ҹNOl Wo=1Qm8r>b 0M"HVF.Ӭ/|%pl@܏)XY/%#ބ T&fӋ~{Rzl19˻^Ol 8(V_e*MT>C=WrÑ 1.uXP Meoz)Z?]˙d[DI*Fp3W,pL2֓C_*L|\Kj7 ^-F #~ސTu F 䴖겶%lוp _[gh?`r׍cS_V~p^@s䈝 3,'*q^}Xԇ1[elL4o(bRE2sc3㚼f+7pcv*//-#McyVݢD|cӹV/~廯|/iVt3}grV IT֍gY"钭P.+#yhbaN%E4J#_oB?g}=BGXY6 .]Pkav ztRMܯGW^ e$EJ_FEH$1Xf+r2[2TA"` v+lE>ʵ׷g q2V<_يh\?Q1IiK6 dI;bl$)jM>'+o$E装lF |ʲRDjl?,+jLֿRMoi{cWHeK)ZQV:R2<\кH?Ą,̿hyp|e nk=$LMt_^F[UXR{Iʜz>t[(Kr#VuپU)udWLҪ*a!![HrDEl釄H 3$Eg2ŸGkٕ3/2Ox dI?՚@Ŏ8 dI8\E-YT:`qLvtBjx& =?E"Z"BOA T,\=X=O| aW~8%T}J(^ݏ7=CwP~awDkz8>`3)]# j+ lV@pHC ſ3l,!p\$Lstx\BwϏ!Dc%8[:f7E%`YMy]bl[ ghR/?9/zRGROo;2N6~|̲UƘ0U6k@> ^dsf!E4պqx8fͭMZ,\ 'mPv8OIx>H0cbu (v-$/Q ?= k!,|YHC[~?9FOfC??O*"3ϵߗӅ=MuGsٱQ,0Q\U,NUs+(ЖJ?,IENDB`perfbook_html/node486.html0000644000175000017500000000510311672746164015655 0ustar paulmckpaulmck About this document ...

About this document ...

Is Parallel Programming Hard, And, If So, What Can You Do About It?

This document was generated using the LaTeX2HTML translator Version 2008 (1.71)

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html -show_section_numbers perfbook_html

The translation was initiated by Paul E. McKenney on 2011-12-16


Paul E. McKenney 2011-12-16
perfbook_html/node265.html0000644000175000017500000000447111672746162015655 0ustar paulmckpaulmck 17.3 Process-Based Parallel Functional Programming


17.3 Process-Based Parallel Functional Programming



Paul E. McKenney 2011-12-16
perfbook_html/node186.html0000644000175000017500000000453711672746162015662 0ustar paulmckpaulmck 13.6 Hardware Considerations


13.6 Hardware Considerations

CPU word alignment, cache alignment.

@@@ pull in material from Orran Kreiger's 1995 paper (permission granted).


Paul E. McKenney 2011-12-16
perfbook_html/img219.png0000644000175000017500000001140311672746114015311 0ustar paulmckpaulmckPNG  IHDRAL9tRNSىHIDATx]z:["4UbW,RZOSti*<&J9M*SEQ\Հ_^_aܾ0 \;d `Ga@ެ0(\@Z=׽CIJy>.AQO? *߈.~; g?K* ' H8@R˛%P?$8KUfbl?~|ÚHT{l߱VѬz|lkٖj]/x~7=cbj=;n_K?X!?V`+?VRjP~iPPxGH љϕTnOΡ(͈{KL0ZbSWxrs<?,XJ$osU 7GUF[d v$6LmCk`-vqPP>yGv>F=Vl xym-HLꉞe>k:9g/k`| JH4tiIC[ iЧNbwro1O!'a T[ms$(`;Cpp@:ɟd#/&,J7i%+%hĞwE֙q-oyJ~t;O`3'CO[0{[l1˴bdl@lnrSez -t30v6l -&;v1u1 K*u{ER/#UǝeUxfIPܰŵؔ_Ivžg·Hj.iTG)5S-$`@e{ji-2-&隊-ړ@ʊ՞ $?w}uJ bܝGb47Lp&a4n7QK/-Ɔ QPl|!' ![.[[l-2<0 XL>%v,|f_tE@Z[U+c5n0^)s)jzL("#t@%`6)aY66T5;s6a>{~yXoIj6I>jA x^ ]1+SÉA4ohcI^rφQLBc|_+W7sjc @{-%k8/Mst\-n5Cf[/&kJ^U.[݌R]ssA~e+!Y{. ֱGxFqC_Rkt%pɈ(he_6x;\^L}s]:-k@tѦ)hlvl8%Vu{ϜxMW}l:pN?%84(񳑽4d^ "rM%O_ C0p'_`AkU8`F7$i;:[znVwf;Fc8Gna28 +|PŞ 3%=Έw'{ 7Ru_.˃֢'x63IR&l"L Ŭɍ5 PAxjV$"+W@isQvw ]-J( -pS߃bB:**Y.S)KԂ,Fn,ISyP$EW;%ČPH#T!rl[N?[K+ mTO6O܊ivcNg ʹ )o!-TS]Wo\bۢﺾ%SK]p7f۩evo7զl1W]i3qlMO#lbTk.Y)WʚӼUm\0]Mķ"jRqqs݅5Le6jbQ}R`]|c.Qwh귪˂s*2X.HkX;uhE)"enEi+R_5y$5;z=P1'fS=EmiöVwK0ө2" _.0Aԃ$9oE:y\7 ߟjR l3H rOǯ*>w=A]K H:Y [7Kw6lݽ2̍ qL 퐚1l)_:zLF l\DQ. եtyN\X={_6'f/pp_(MAdmgI+j}Umay380Ty:>l7Ty9Rm_ wEٵ0OWAf:4I]]ߥ~4W` <_^^KJ+pO9Z Wüd]mo]x5s̑aӽt=Kx {v=ԣ?7w.5+'/H [0D<"6#!ďY皦)!arqތy}{aUDdEZw(5ahKKxѲBz6~vcRӄ ?͎EJ=Eg {Dt+e5dW ʿq[74"qR}.tm5 Lg OwQ?5dTׯ&&%;k̍g_mUlF)\&9T|mCE# q(4ޑ]蔯[CIٝ`;@ c88Lb.]ǞBD,kAXg ;0zIENDB`perfbook_html/node417.html0000644000175000017500000001312411672746163015650 0ustar paulmckpaulmck D.4.2.4.2 rcu_read_unlock()


D.4.2.4.2 rcu_read_unlock()

Figure: __rcu_read_unlock() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_unlock(void)
2...
...idx])--;
17 local_irq_restore(flags);
18 }
19 }\end{verbatim}
}\end{figure}

The implementation of rcu_read_unlock() is shown in Figure [*]. Line 7 fetches the rcu_read_lock_nesting counter, which line 8 checks to see if we are under the protection of an enclosing rcu_read_lock() primitive. If so, line 9 simply decrements the counter.

However, as with rcu_read_lock(), we otherwise must do more work. Lines 13 and 17 disable and restore irqs in order to prevent the scheduling-clock interrupt from invoking the grace-period state machine while in the midst of rcu_read_unlock() processing. Line 14 picks up the rcu_flipctr_idx that was saved by the matching rcu_read_lock(), line 15 decrements rcu_read_lock_nesting so that irq and NMI/SMI handlers will henceforth update rcu_flipctr, line 16 decrements the counter (with the same index as, but possibly on a different CPU than, that incremented by the matching rcu_read_lock().

The ACCESS_ONCE() macros and irq disabling are required for similar reasons that they are in rcu_read_lock().

Quick Quiz D.59: What problems could arise if the lines containing ACCESS_ONCE() in rcu_read_unlock() were reordered by the compiler? End Quick Quiz

Quick Quiz D.60: What problems could arise if the lines containing ACCESS_ONCE() in rcu_read_unlock() were reordered by the CPU? End Quick Quiz

Quick Quiz D.61: What problems could arise in rcu_read_unlock() if irqs were not disabled? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img110.png0000644000175000017500000000540011672746054015302 0ustar paulmckpaulmckPNG  IHDRWf6PLTEb``MJK# hffmkkXUV856C@@wuv.*+*tRNS@f xIDATx[( Cɂ%]°ps>cŝ[`'$p2`r@ث|H ౅>^4)dbO#40QqЁ42[*֍ ƛйqxjUlEnèidRdNiwd2mCUɛy]ZTen !5ѽb냜;4kdX. }F$i_mJ:syi(A{U--63mLц$<|+z5=a{uʄCptsꯢ}q4!'kSSzY4'+no6Lhٓg#&x)`0=D;#16!/FklÂ/GSU&؛ܹv  T|am$ e ^Q zWta죡ԅ1VnLVP *SBbug7yS ]jKJJ)?,7R{!`l.5z5x:h6F7a0aMuW&Ś ԛ7ÃJZu4kHCAU8ΆĻL-Qfeoh !w4Yi%06@P POX/H&)8Зyebpa#-M!*-*~DždWLL ]lor%$ኘ D[t_( s?ߓ9\bb4gG "o KMAȄHY> 8g@:!Г9MԒŻl^>TbzRb``{?"~`+ա)܋D>aOCNa=+lDP66e3N MFvye|Vj1m,;$JdE)ufKQ 1ݡ\qEC* \47ۥ{*! La|yhtlF1Aخk``E~TQ|>J` ו{C;k=z8-Ym#+i<1.܁c@8w Ց'=/_µbgj^G Q;ati@a"~"qSG] SljddSh[ՎT/8%YM2b=#q",(*ڦP`yI{5wsMYi)o ,{![U8XûęJ5tP {JkP#Dȏ.<+ s򮹼Ʈ8թ+a:sjALizhIiˣCP7AUPGuj;q-Yaow*\?K>d ~8< kM܇M$K ky|82oNvW2Y1NQA9v우!OuHd@k I44ljY|yb@R:̜;~ 4|=v3m qJ8}<8Y*_8jqIENDB`perfbook_html/node71.html0000644000175000017500000001637111672746162015572 0ustar paulmckpaulmck 6.5 Applying Specialized Parallel Counters


6.5 Applying Specialized Parallel Counters

Although the exact limit counter implementations in Section [*] can be very useful, they are not much help if the counter's value remains near zero at all times, as it might when counting the number of outstanding accesses to an I/O device. The high overhead of such near-zero counting is especially painful given that we normally don't care how many references there are. As noted in the removable I/O device access-count problem on page [*], the number of accesses is irrelevant except in those rare cases when someone is actually trying to remove the device.

One simple solution to this problem is to add a large ``bias'' (for example, one billion) to the counter in order to ensure that the value is far enough from zero that the counter can operate efficiently. When someone wants to remove the device, this bias is subtracted from the counter value. Counting the last few accesses will be quite inefficient, but the important point is that the many prior accesses will have been counted at full speed.

Quick Quiz 6.46: What else had you better have done when using a biased counter? End Quick Quiz

Although a biased counter can be quite helpful and useful, it is only a partial solution to the removable I/O device access-count problem called out on page [*]. When attempting to remove a device, we must not only know the precise number of current I/O accesses, we also need to prevent any future accesses from starting. One way to accomplish this is to read-acquire a reader-writer lock 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:



  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 }


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 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.

Quick Quiz 6.47: This is ridiculous! We are read-acquiring a reader-writer lock to update the counter? What are you playing at??? End Quick Quiz

The code to remove the device might be as follows:



  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();


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 device removal.

Quick Quiz 6.48: What other issues would need to be accounted for in a real system? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node327.html0000644000175000017500000002121211672746163015645 0ustar paulmckpaulmck D.1 Sleepable RCU Implementation


D.1 Sleepable RCU Implementation

Figure: Sleeping While RCU Reading Considered Harmful
\resizebox{3in}{!}{\includegraphics{cartoons/RCUCallbacks}}

Classic RCU requires that read-side critical sections obey the same rules obeyed by the critical sections of pure spinlocks: blocking or sleeping of any sort is strictly prohibited. This has frequently been an obstacle to the use of RCU, and Paul has received numerous requests for a ``sleepable RCU'' (SRCU) that permits arbitrary sleeping (or blocking) within RCU read-side critical sections. Paul had previously rejected all such requests as unworkable, since arbitrary sleeping in RCU read-side could indefinitely extend grace periods, which in turn could result in arbitrarily large amounts of memory awaiting the end of a grace period, which finally would result in disaster, as fancifully depicted in Figure [*], with the most likely disaster being hangs due to memory exhaustion. After all, any concurrency-control primitive that could result in system hangs -- even when used correctly - does not deserve to exist.

However, the realtime kernels that require spinlock critical sections be preemptible [Mol05] also require that RCU read-side critical sections be preemptible [MS05]. Preemptible critical sections in turn require that lock-acquisition primitives block in order to avoid deadlock, which in turns means that both RCU's and spinlocks' critical sections be able to block awaiting a lock. However, these two forms of sleeping have the special property that priority boosting and priority inheritance may be used to awaken the sleeping tasks in short order.

Nevertheless, use of RCU in realtime kernels was the first crack in the tablets of stone on which were inscribed ``RCU read-side critical sections can never sleep''. That said, indefinite sleeping, such as blocking waiting for an incoming TCP connection, is strictly verboten even in realtime kernels.

Quick Quiz D.1: Why is sleeping prohibited within Classic RCU read-side critical sections? End Quick Quiz

Quick Quiz D.2: Why not permit sleeping in Classic RCU read-side critical sections by eliminating context switch as a quiescent state, leaving user-mode execution and idle loop as the remaining quiescent states? End Quick Quiz



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node47.html0000644000175000017500000002705611672746161015576 0ustar paulmckpaulmck 5.2.4 POSIX Reader-Writer Locking


5.2.4 POSIX Reader-Writer Locking

The POSIX API provides a reader-writer lock, which is represented by a pthread_rwlock_t. As with pthread_mutex_t, pthread_rwlock_t may be statically initialized via PTHREAD_RWLOCK_INITIALIZER or dynamically initialized via the pthread_rwlock_init() primitive. The pthread_rwlock_rdlock() primitive read-acquires the specified pthread_rwlock_t, the pthread_rwlock_wrlock() primitive write-acquires it, and the pthread_rwlock_unlock() primitive releases it. Only a single thread may write-hold a given pthread_rwlock_t at any given time, but multiple threads may read-hold a given pthread_rwlock_t, at least while there is no thread currently write-holding it.

As you might expect, reader-writer locks are designed for read-mostly situations. In these situations, a reader-writer lock can provide greater scalability than can an exclusive lock because the exclusive lock is by definition limited to a single thread holding the lock at any given time, while the reader-writer lock permits an arbitrarily large number of readers to concurrently hold the lock. However, in practice, we need to know how much additional scalability is provided by reader-writer locks.

Figure: Measuring Reader-Writer Lock Scalability
\begin{figure}{ \scriptsize
\begin{verbatim}1 pthread_rwlock_t rwl = PTHREAD_...
...9 readcounts[me] = loopcnt;
40 return NULL;
41 }\end{verbatim}
}\end{figure}

Figure [*] (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 holdtime argument controlling the time each thread holds the reader-writer lock, line 3 shows the thinktime argument controlling the time between the release of the reader-writer lock and the next acquisition, line 4 defines the readcounts array into which each reader thread places the number of times it acquired the lock, and line 5 defines the nreadersrunning variable, which determines when all reader threads have started running.

Lines 7-10 define goflag, which synchronizes the start and the end of the test. This variable is initially set to GOFLAG_INIT, then set to GOFLAG_RUN after all the reader threads have started, and finally set to GOFLAG_STOP to terminate the test run.

Lines 12-41 define reader(), which is the reader thread. Line 18 atomically increments the nreadersrunning variable to indicate that this thread is now running, and lines 19-21 wait for the test to start. The ACCESS_ONCE() primitive forces the compiler to fetch goflag on each pass through the loop--the compiler would otherwise be within its rights to assume that the value of goflag would never change.

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 duration (and the 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 lock. Line 37 counts this lock acquisition.

Line 38 moves the lock-acquisition count to this thread's element of the readcounts[] array, and line 40 returns, terminating this thread.

Figure: Reader-Writer Lock Scalability
\resizebox{3in}{!}{\includegraphics{CodeSamples/toolsoftrade/rwlockscale}}

Figure [*] shows the results of running this test on a 64-core Power-5 system with two hardware threads per core for a total of 128 software-visible CPUs. The thinktime parameter was zero for all these tests, and the holdtime parameter set to values ranging from one thousand (``1K'' on the graph) to 100 million (``100M'' on the graph). The actual value plotted is:

\begin{displaymath}
\frac{L_N}{N L_1}
\end{displaymath} (5.1)

where $N$ is the number of threads, $L_N$ is the number of lock acquisitions by $N$ threads, and $L_1$ is the number of lock acquisitions by a single thread. Given ideal hardware and software scalability, this value will always be 1.0.

As can be seen in the figure, reader-writer locking scalability is decidedly non-ideal, especially for smaller sizes of critical sections. To see why read-acquisition can be so slow, consider that all the acquiring threads must update the pthread_rwlock_t data structure. Therefore, if all 128 executing threads attempt to read-acquire the reader-writer lock concurrently, they must update this underlying pthread_rwlock_t one at a time. One lucky thread might do so almost immediately, but the least-lucky thread must wait for all the other 127 threads to do their updates. This situation will only get worse as you add CPUs.

Quick Quiz 5.15: Isn't comparing against single-CPU throughput a bit harsh? End Quick Quiz

Quick Quiz 5.16: But 1,000 instructions is not a particularly small size for a critical section. What do I do if I need a much smaller critical section, for example, one containing only a few tens of instructions? End Quick Quiz

Quick Quiz 5.17: In Figure [*], all of the traces other than the 100M trace deviate gently from the ideal line. In contrast, the 100M trace breaks sharply from the ideal line at 64 CPUs. In addition, the spacing between the 100M trace and the 10M trace is much smaller than that between the 10M trace and the 1M trace. Why does the 100M trace behave so much differently than the other traces? End Quick Quiz

Quick Quiz 5.18: Power 5 is several years old, and new hardware should be faster. So why should anyone worry about reader-writer locks being slow? End Quick Quiz

Despite these limitations, reader-writer locking is quite useful in many cases, for example when the readers must do high-latency file or network I/O. There are alternatives, some of which will be presented in Chapters [*] and [*].

Paul E. McKenney 2011-12-16
perfbook_html/node429.html0000644000175000017500000001454311672746163015661 0ustar paulmckpaulmck E.4.1 Promela Peculiarities


E.4.1 Promela Peculiarities

Although all computer languages have underlying similarities, Promela will provide some surprises to people used to coding in C, C++, or Java.

  1. In C, ``;'' terminates statements. In Promela it separates them. Fortunately, more recent versions of Spin have become much more forgiving of ``extra'' semicolons.
  2. Promela's looping construct, the do statement, takes conditions. This do statement closely resembles a looping if-then-else statement.
  3. In C's switch statement, if there is no matching case, the whole statement is skipped. In Promela's equivalent, confusingly called if, if there is no matching guard expression, you get an error without a recognizable corresponding error message. So, if the error output indicates an innocent line of code, check to see if you left out a condition from an if or do statement.
  4. When creating stress tests in C, one usually races suspect operations against each other repeatedly. In Promela, one instead sets up a single race, because Promela will search out all the possible outcomes from that single race. Sometimes you do need to loop in Promela, for example, if multiple operations overlap, but doing so greatly increases the size of your state space.
  5. In C, the easiest thing to do is to maintain a loop counter to track progress and terminate the loop. In Promela, loop counters must be avoided like the plague because they cause the state space to explode. On the other hand, there is no penalty for infinite loops in Promela as long as the none of the variables monotonically increase or decrease - Promela will figure out how many passes through the loop really matter, and automatically prune execution beyond that point.
  6. In C torture-test code, it is often wise to keep per-task control variables. They are cheap to read, and greatly aid in debugging the test code. In Promela, per-task control variables should be used only when there is no other alternative. To see this, consider a 5-task verification with one bit each to indicate completion. This gives 32 states. In contrast, a simple counter would have only six states, more than a five-fold reduction. That factor of five might not seem like a problem, at least not until you are struggling with a verification program possessing more than 150 million states consuming more than 10GB of memory!
  7. One of the most challenging things both in C torture-test code and in Promela is formulating good assertions. Promela also allows never claims that act sort of like an assertion replicated between every line of code.
  8. Dividing and conquering is extremely helpful in Promela in keeping the state space under control. Splitting a large model into two roughly equal halves will result in the state space of each half being roughly the square root of the whole. For example, a million-state combined model might reduce to a pair of thousand-state models. Not only will Promela handle the two smaller models much more quickly with much less memory, but the two smaller algorithms are easier for people to understand.

Paul E. McKenney 2011-12-16
perfbook_html/img141.png0000644000175000017500000000656711672746102015317 0ustar paulmckpaulmckPNG  IHDRPt?PLTEb``MJK# hffvstmkkXUVVST856C@@wuv.*+\tRNS@f IDATx]ƌ[&?i.|]V @?kw,ͮyDkc[ۀ`-4s>m)YB]]hzA.˶i{V9zfx|=/~#DK .#UړOMho`9G0&~~_PEgE57~me] ̦\whD_7rpRe Iyϲێ"k+=K'unnKn t&rCi=C|~Mh?uZn'x:Ecs>~6d MCVVX{% RţJ+(_5No6^!B:³v[i6i6a% uco J0Pv{=`a꣸ʘӰౘ%+a-ךAN6֋zM sF$K$C`+584m]NC HTp!9fY5դ?v,]ջZ3e*L~Y *kB$9[M3˿y=L>K %;'SlIlxגr{aÎ*p~q^UWb>0k5St~_­rt:8@gR@%sew{W{~r=.tOVE5|NjM |6,r|H9[RBE_mM.MK$[x*Dk[?O79u{Tz:@ԶTqT܋(T}}ɱ"0`Z>u>U2qVN /wN?v7.P(Gߜ(W5 Q> fBpp}&WS& ?]O2; B9'X rĠ 8y%7{ 5@;ll+A5{횒 (;XkDhJbFEo=C=/*hYu5NpU?)OK~챭yQK=b;%h@ZvʿvA&)U8H9!} |#5$+#MJkF†fP&VX}6kB-"͔".mQ χ:@Ҙ,2P>g'B5}aw'>FѠ>^vGv/ۅ>tfj'9)" f+F&li .a&9,MӅ4*}&] Tg`gRBVdewn"gĭ7b+bk-7u 37 =,<\^J£ȟЧs!J7rM[l%n-꺀Zz05^+(F@6꾧ODnglQTx#k)o`k]6s⦰9Zv/њw۩<"16qFGIܵE?,d}g9㒟|%ٜ.`je^oHݕiXWrNׄ hd5g|3Fϯ;"~R(=j@',;bɈ^XBrf]Ul3Ac`3&j!N T}ąPJŸ E9)aAQ:~ʷ=DQӛSŶ0xE=V7}:?U:G'Iz4IO{1MI4ʓc'RX5JTzAjm#5-j'-^wH@)YN+7ND+ Dy'㺑XxJw(nm d5_RSO7z T{6wqJOsVz&Ya9 izZf͍^B3›dU Xk]zw}t_cc71?rPwNiMcнJx`vyн|D[o6Ƀ#ؽb9~ v6|sL>>Ir;vC)i~]aImǗ1bM wĚŗ17cM bM/Ǘ&Ě75}8 t% QmQ0!U@"+˸ 9RX1Zk91;|7zzڿ,4{G~ΊiF=B9'_ ˏ9L-g[>(ŞPSh (zi X$KN|XLy%@<5U~̜˙-}O7ng崵tKޱ2py,"͑Y-d DrrFN`*e}F[~O cY#4o9'*bh3`::'-`fӃn*VEn(g?6loL9hZԕ۠/Sj9ư6lM@:fF&vn*8_a[O]S;` ,2 %cQBuL4*dNFl;fK1FL.fZCS.ܙnjOGkĤ)Fh+ &tQ4S5at:Ǹ@ {erޖǝ/u aĴ˜`Oy)PP ;"uެItbhbXJƘO&h;b쬓, o).zfrx$L/qby30ˆ 31aƨ6`~P+[?XOhjf*"uwqF Rgt1|.vl˥LobE 9\c,{5na(kܢlI}\ U),J&<6etvgihߒ@,:+vMc-t֦0=d FDO,byDl>c1tjA^`\ָIw:aF+87eބqLwی31Pf?jdi{;zgn1:qW`'=k:'A;}l7 p;zpt^na^JɔR[ pd>c+(7-,Xw15mvp1P۳ +3Î > jğ ]4KtEAFY.cl.r_ZjJac~-,.IK1U@|VxK8  4!$1b1W}ۣ7Co(E\b8c1w]41452Vw ؚS`kN _sj} 35˘7U䷭LC?dQC[Vlx*UW_d v>~cŕ:\'5ޖ4;c:c3\)cdb![;Uje*0}`cL~0ֲ]bZMkh/4PpsjtGmPn&&l2'(ۊbWԂM xPJ\:q&29,nTlmx[KF[D9/ļO8vjWZԀ*pITF+S,cU`s(ߚ<{uHo, ̘_/ ,BX\41Ɩ+ ˍZmo=EelWL=RFqzz3~ [# Ē W<%Bh䗈< }(C͠3s#,'$w0BXc_ø}< ';׷ߋl}7H#eif4z)kYT8IcmpRYؾqqBՂz[~IgΙ6ܸ W1.qxh}'tk;:b}'VoW8Ly1!n\HGE_Y4>`$@A^\y}ߺ:7 d{O;Ic+i*.m<@NJTЮǞ4<Ut-rFܠ}!ێzKLpݽH,J'ti"/;T{re ;ïemkԢw[z7[HȚk "@ p((x^_H5% =՛AqOnŰ[ iNXhzҭ,h7!jԺ샴Y"C벲I jGe _j $.Ȫhږ<3R@҂ʁt$ s:~,aAV +A o>%4CRgF?qpLо̺::wzB}1 Fw{S="Q~d°+9zRx0seKiw{ Ua4,DH؏Vx4?ytypE$B5WEY9jpIE9ιH9'qV\8#"Haq ;Kb)m G;52"ĝ] qOys!߮-io\maG='OmeUMys=^Oz#^#x=!4{+й x̽S1$xS>?|H=mgn=5t<Nܭ'hի9[‘8Y+=BP!4?;Q׷lp% Mys<0wNȒ<H4hBWp>9=ap0;7SMfa4?T`UqijE@o{9u -Zsn]v6| >=m淏3cdb_~13V{m6HI_ɋλ]M;w'oC:!K.to{KoaeY:Xٺ[S-УljIENDB`perfbook_html/node235.html0000644000175000017500000001157611672746162015656 0ustar paulmckpaulmck 14.2.12.1.4 Ordering with Multiple CPUs on One Lock:

14.2.12.1.4 Ordering with Multiple CPUs on One Lock:

Suppose, instead of the two different locks as shown in Table [*], both CPUs acquire the same lock, as shown in Table [*]?


Table: Ordering With Multiple CPUs on One Lock
CPU 1 CPU 2
A = a; E = e;
LOCK M; LOCK M;
B = b; F = f;
C = c; G = g;
UNLOCK M; UNLOCK M;
D = d; H = h;


In this case, either CPU 1 acquires M before CPU 2 does, or vice versa. In the first case, the assignments to A, B, and C must precede those to F, G, and H. On the other hand, if CPU 2 acquires the lock first, then the assignments to E, F, and G must precede those to B, C, and D.

Paul E. McKenney 2011-12-16
perfbook_html/img327.png0000644000175000017500000000025311672746123015312 0ustar paulmckpaulmckPNG  IHDR |H0$PLTE# mkk856wuv.*+"bI=tRNS@f5IDATc`Pu*( P% YdV uK 0CIENDB`perfbook_html/node461.html0000644000175000017500000006112211672746163015650 0ustar paulmckpaulmck F.1 Chapter 

F.1 Chapter [*]

Quick Quiz [*].1: 
Come on now!!! Parallel programming has been known to be exceedingly hard for many decades. You seem to be hinting that it is not so hard. What sort of game are you playing?
 
Answer:
If you really believe that parallel programming is exceedingly hard, then you should have a ready answer to the question ``Why is parallel programming hard?'' One could list any number of reasons, ranging from deadlocks to race conditions to testing coverage, but the real answer is that it is not really all that hard. After all, if parallel programming was really so horribly difficult, how could a large number of open-source projects, ranging from Apache to MySQL to the Linux kernel, have managed to master it?

A better question might be: ''Why is parallel programming perceived to be so difficult?'' To see the answer, let's go back to the year 1991. Paul McKenney was walking across the parking lot to Sequent's benchmarking center carrying six dual-80486 Sequent Symmetry CPU boards, when he suddenly realized that he was carrying several times the price of the house he had just purchased.F.1 This high cost of parallel systems meant that parallel programming was restricted to a privileged few who worked for an employer who either manufactured or could afford to purchase machines costing upwards of $100,000 -- in 1991 dollars US.

In contrast, in 2006, Paul finds himself typing these words on a dual-core x86 laptop. Unlike the dual-80486 CPU boards, this laptop also contains 2GB of main memory, a 60GB disk drive, a display, Ethernet, USB ports, wireless, and Bluetooth. And the laptop is more than an order of magnitude cheaper than even one of those dual-80486 CPU boards, even before taking inflation into account.

Parallel systems have truly arrived. They are no longer the sole domain of a privileged few, but something available to almost everyone.

The earlier restricted availability of parallel hardware is the real reason that parallel programming is considered so difficult. After all, it is quite difficult to learn to program even the simplest machine if you have no access to it. Since the age of rare and expensive parallel machines is for the most part behind us, the age during which parallel programming is perceived to be mind-crushingly difficult is coming to a close.F.2

Quick Quiz [*].2: 
How could parallel programming ever be as easy as sequential programming?
 
Answer:
It depends on the programming environment. SQL [Int92] is an underappreciated success story, as it permits programmers who know nothing about parallelism to keep a large parallel system productively busy. We can expect more variations on this theme as parallel computers continue to become cheaper and more readily available. For example, one possible contender in the scientific and technical computing arena is MATLAB*P, which is an attempt to automatically parallelize common matrix operations.

Finally, on Linux and UNIX systems, consider the following shell command:

get_input | grep "interesting" | sort

This shell pipeline runs the get_input, grep, and sort processes in parallel. There, that wasn't so hard, now was it?

Quick Quiz [*].3: 
Oh, really??? What about correctness, maintainability, robustness, and so on?
 
Answer:
These are important goals, but they are just as important for sequential programs as they are for parallel programs. Therefore, important though they are, they do not belong on a list specific to parallel programming.

Quick Quiz [*].4: 
And if correctness, maintainability, and robustness don't make the list, why do productivity and generality?
 
Answer:
Given that parallel programming is perceived to be much harder than is sequential programming, productivity is tantamount and therefore must not be omitted. Furthermore, high-productivity parallel-programming environments such as SQL have been special purpose, hence generality must also be added to the list.

Quick Quiz [*].5: 
Given that parallel programs are much harder to prove correct than are sequential programs, again, shouldn't correctness really be on the list?
 
Answer:
From an engineering standpoint, the difficulty in proving correctness, either formally or informally, would be important insofar as it impacts the primary goal of productivity. So, in cases where correctness proofs are important, they are subsumed under the ``productivity'' rubric.

Quick Quiz [*].6: 
What about just having fun?
 
Answer:
Having fun is important as well, but, unless you are a hobbyist, would not normally be a primary goal. On the other hand, if you are a hobbyist, go wild!

Quick Quiz [*].7: 
Are there no cases where parallel programming is about something other than performance?
 
Answer:
There are certainly cases where the problem to be solved is inherently parallel, for example, Monte Carlo methods and some numerical computations. Even in these cases, however, there will be some amount of extra work managing the parallelism.

Quick Quiz [*].8: 
Why all this prattling on about non-technical issues??? And not just any non-technical issue, but productivity of all things? Who cares?
 
Answer:
If you are a pure hobbyist, perhaps you don't need to care. But even pure hobbyists will often care about how much they can get done, and how quickly. After all, the most popular hobbyist tools are usually those that are the best suited for the job, and an important part of the definition of ``best suited'' involves productivity. And if someone is paying you to write parallel code, they will very likely care deeply about your productivity. And if the person paying you cares about something, you would be most wise to pay at least some attention to it!

Besides, if you really didn't care about productivity, you would be doing it by hand rather than using a computer!

Quick Quiz [*].9: 
Given how cheap parallel hardware has become, how can anyone afford to pay people to program it?
 
Answer:
There are a number of answers to this question:

  1. Given a large computational cluster of parallel machines, the aggregate cost of the cluster can easily justify substantial developer effort, because the development cost can be spread over the large number of machines.
  2. Popular software that is run by tens of millions of users can easily justify substantial developer effort, as the cost of this development can be spread over the tens of millions of users. Note that this includes things like kernels and system libraries.
  3. If the low-cost parallel machine is controlling the operation of a valuable piece of equipment, then the cost of this piece of equipment might easily justify substantial developer effort.
  4. If the software for the low-cost parallel produces an extremely valuable result (e.g., mineral exploration), then the valuable result might again justify substantial developer cost.
  5. Safety-critical systems protect lives, which can clearly justify very large developer effort.
  6. Hobbyists and researchers might seek knowledge, experience, fun, or glory rather than mere money.
So it is not the case that the decreasing cost of hardware renders software worthless, but rather that it is no longer possible to ``hide'' the cost of software development within the cost of the hardware, at least not unless there are extremely large quantities of hardware.

Quick Quiz [*].10: 
This is a ridiculously unachievable ideal! Why not focus on something that is achievable in practice?
 
Answer:
This is eminently achievable. The cellphone is a computer that can be used to make phone calls and to send and receive text messages with little or no programming or configuration on the part of the end user.

This might seem to be a trivial example at first glance, but if you consider it carefully you will see that it is both simple and profound. When we are willing to sacrifice generality, we can achieve truly astounding increases in productivity. Those who cling to generality will therefore fail to set the productivity bar high enough to succeed in production environments.

Quick Quiz [*].11: 
What other bottlenecks might prevent additional CPUs from providing additional performance?
 
Answer:
There are any number of potential bottlenecks:

  1. Main memory. If a single thread consumes all available memory, additional threads will simply page themselves silly.
  2. Cache. If a single thread's cache footprint completely fills any shared CPU cache(s), then adding more threads will simply thrash the affected caches.
  3. Memory bandwidth. If a single thread consumes all available memory bandwidth, additional threads will simply result in additional queuing on the system interconnect.
  4. I/O bandwidth. If a single thread is I/O bound, adding more threads will simply result in them all waiting in line for the affected I/O resource.

Specific hardware systems may have any number of additional bottlenecks.

Quick Quiz [*].12: 
What besides CPU cache capacity might require limiting the number of concurrent threads?
 
Answer:
There are any number of potential limits on the number of threads:

  1. Main memory. Each thread consumes some memory (for its stack if nothing else), so that excessive numbers of threads can exhaust memory, resulting in excessive paging or memory-allocation failures.
  2. I/O bandwidth. If each thread initiates a given amount of mass-storage I/O or networking traffic, excessive numbers of threads can result in excessive I/O queuing delays, again degrading performance. Some networking protocols may be subject to timeouts or other failures if there are so many threads that networking events cannot be responded to in a timely fashion.
  3. Synchronization overhead. For many synchronization protocols, excessive numbers of threads can result in excessive spinning, blocking, or rollbacks, thus degrading performance.

Specific applications and platforms may have any number of additional limiting factors.

Quick Quiz [*].13: 
Are there any other obstacles to parallel programming?
 
Answer:
There are a great many other potential obstacles to parallel programming. Here are a few of them:

  1. The only known algorithms for a given project might be inherently sequential in nature. In this case, either avoid parallel programming (there being no law saying that your project has to run in parallel) or invent a new parallel algorithm.
  2. The project allows binary-only plugins that share the same address space, such that no one developer has access to all of the source code for the project. Because many parallel bugs, including deadlocks, are global in nature, such binary-only plugins pose a severe challenge to current software development methodologies. This might well change, but for the time being, all developers of parallel code sharing a given address space need to be able to see all of the code running in that address space.
  3. The project contains heavily used APIs that were designed without regard to parallelism. Some of the more ornate features of the System V message-queue API form a case in point. Of course, if your project has been around for a few decades, and if its developers did not have access to parallel hardware, your project undoubtedly has at least its share of such APIs.
  4. The project was implemented without regard to parallelism. Given that there are a great many techniques that work extremely well in a sequential environment, but that fail miserably in parallel environments, if your project ran only on sequential hardware for most of its lifetime, then your project undoubtably has at least its share of parallel-unfriendly code.
  5. The project was implemented without regard to good software-development practice. The cruel truth is that shared-memory parallel environments are often much less forgiving of sloppy development practices than are sequential environments. You may be well-served to clean up the existing design and code prior to attempting parallelization.
  6. The people who originally did the development on your project have since moved on, and the people remaining, while well able to maintain it or add small features, are unable to make ``big animal'' changes. In this case, unless you can work out a very simple way to parallelize your project, you will probably be best off leaving it sequential. That said, there are a number of simple approaches that you might use to parallelize your project, including running multiple instances of it, using a parallel implementation of some heavily used library function, or making use of some other parallel project, such as a database.

One can argue that many of these obstacles are non-technical in nature, but that does not make them any less real. In short, parallelization can be a large and complex effort. As with any large and complex effort, it makes sense to do your homework beforehand.

Quick Quiz [*].14: 
Where are the answers to the Quick Quizzes found?
 
Answer:
In Appendix [*] starting on page [*].

Hey, I thought I owed you an easy one!

Quick Quiz [*].15: 
Some of the Quick Quiz questions seem to be from the viewpoint of the reader rather than the author. Is that really the intent?
 
Answer:
Indeed it is! Many are modeled after Paul--just ask anyone who has had the misfortune of being assigned to teach him. Others are quite similar to actual questions that have been asked during conference presentations and lectures covering the material in this book. Still others are from the viewpoint of the author.

Quick Quiz [*].16: 
These Quick Quizzes just are not my cup of tea. What do you recommend?
 
Answer:
There are a number of alternatives available to you:

  1. Just ignore the Quick Quizzes and read the rest of the book. You might miss out on the interesting material in some of the Quick Quizzes, but the rest of the book has lots of good material as well.
  2. If you prefer a more academic and rigorous treatment of parallel programming, you might like Herlihy's and Shavit's textbook [HS08]. This book starts with an interesting combination of low-level primitives at high levels of abstraction from the hardware, and works its way through locking and simple data structures including lists, queues, hash tables, and counters, culminating with transactional memory.
  3. If you would like an academic treatment of parallel programming that keeps to a more pragmatic viewpoint, you might be interested in the concurrency chapter from Scott's textbook [Sco06] on programming languages.
  4. If you are interested in an object-oriented patternist treatment of parallel programming focussing on C++, you might try Volumes 2 and 4 of Schmidt's POSA series [SSRB00,BHS07]. Volume 4 in particular has some interesting chapters applying this work to a warehouse application. The realism of this example is attested to by the section entitled ``Partitioning the Big Ball of Mud'', wherein the problems inherent in parallelism often take a back seat to the problems inherent in getting one's head around a real-world application.
  5. If your primary focus is scientific and technical computing, and you prefer a patternist approach, you might try Mattson et al.'s textbook [MSM05]. It covers Java, C/C++, OpenMP, and MPI. Its patterns are admirably focused first on design, then on implementation.
  6. If you are interested in POSIX Threads, you might take a look at David R. Butenhof's book [But97].
  7. If you are interested in C++, but in a Windows environment, you might try Herb Sutter's ``Effective Concurrency'' series in Dr. Dobbs Journal [Sut08]. This series does a reasonable job of presenting a commonsense approach to parallelism.
  8. If you want to try out Intel Threading Building Blocks, then perhaps James Reinders's book [Rei07] is what you are looking for.
  9. Finally, those preferring to work in Java might be well-served by Doug Lea's textbooks [Lea97,GPB+07].
In contrast, this book meshes real-world machines with real-world algorithms. If your sole goal is to find an optimal parallel queue, you might be better served by one of the above books. However, if you are interested in principles of parallel design that allow multiple such queues to operate in parallel, read on!

Paul E. McKenney 2011-12-16
perfbook_html/node73.html0000644000175000017500000001754111672746162015574 0ustar paulmckpaulmck 7. Partitioning and Synchronization Design


7. Partitioning and Synchronization Design

This chapter describes how to design software to take advantage of the multiple CPUs that are increasingly appearing in commodity systems. It does this by presenting a number of idioms, or ``design patterns'' that can help you balance performance, scalability, and response time. As noted in earlier chapters, the most important decision you will make when creating parallel software is how to carry out the partitioning. Correctly partitioned problems lead to simple, scalable, and high-performance solutions, while poorly partitioned problems result in slow and complex solutions.

@@@ roadmap @@@



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node76.html0000644000175000017500000000767111672746162015602 0ustar paulmckpaulmck 7.1.2 Double-Ended Queue


7.1.2 Double-Ended Queue

A double-ended queue is a data structure containing a list of elements that may be inserted or removed from either end [Knu73]. It has been claimed that a lock-based implementation permitting concurrent operations on both ends of the double-ended queue is difficult [Gro07]. This section shows how a partitioning design strategy can result in a reasonably simple implementation, looking at three general approaches in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img237.png0000644000175000017500000003705011672746066015325 0ustar paulmckpaulmckPNG  IHDRDFc<WPLTEb``^\\\ZZMJK# hffommmkkcaaZWXXUV856iffKHHC@@wuv.*+~~vttXtRNS@f IDATx%]x(x9gED.:Jj5ZV(!NPufT~Efguz]=df-A)ͦئՋPnEM^v\b3rGP*jiQi x\.Stʨ4oW,TR4Z֯55\\̏*vwYUT8%vݧL-isP_9,4kL*Rec wP۪4.M]ja4BRjgsz\{}tQlKZ6ya a 4$3LN);ruy_CR#[+ծGk9V9{&=sۖsS_x|߇Fusv6IGbr?H50M᫰Һ '>:A }!dJ$9ld!ٳ-]$_Ubˊ68R!T$*i(QρowC;A=e`]2`mn455d4u_n N}r􉗔;dZ0{7)zzkjR/l:W8K ^*:/Z2S٣/D '%pPil,jcܤZv&ihWw5^osʤ`@^6Sj}))웰j JoU*@1Y*e_\-({ F;|cYZ'NRQ3(F *^sghYTCj sx}?7:X }*.Q{J!0Ռ2%Vhw-Ht ZÝ>^hc5վ 9W{ؿyIaģÆ(K1 j瀣[kH[Nr,KV;]I/~Yd[Ga=`8&VN^Ñd{(x2@7+TᒦӏB r|.6S(oVYzQ^[6E>}Q6dWЈ]5}?`Si; UadM =xẏ:-; RMTF6t0HtwcA&-/| 7b8o/ei+dFYrвqU[(h$F@4Xu˓W<־VL"hCm2_"j%e,Κxg꽩;ސ>R, %$,;ׁy1r,ZAZM2//Y(8"JScH<b7d~Tj>Z-*X~ȯBx,M''*g{XإI<5,N؋hva;!Ɉphƹ}$Ozh)e=(WUv1Z܏^J^ݏEmzNJz -! YH@rM1 fBLD¤W JNFwudK`[h1+<;{pxU㗼-۶j9Q0$I_}X;秱"*߀L'abvnIpm0&r1_b@?JƐ(?RdC+:=HXddܤ-T0f)PgKK)o@S#ϩ6ؚ+^ .qMp4הJp,?%LS>.nRʼnˊ$mSRJtG@~*CaA 7M\Zv,p3ETCY#ﲯ*w_@^UKglhWRG&YIS7 '7OObLyL}Xc`GNN@,d ?[ob*f5x rJVXa z5_`GQr2j/V蒁BS ]c^]c<1 +Z7K#'(JeIs NCZ0!P$JlIDٟ.?oFǧO,~y>"(I,{D s)( :F#4,rh+MPx#W% c:=NQWÒ ^ךsI]ͳס6GB{EnVYO_)-0 d2H-iƏm8-Fץ⻒ͩ% A&Nt$0b\.Ey.-u.x;@d-`243%XIk<ŋ-}H046Nʊq3skJ9+Tڐ7[7r(] }(CD;Wo\Jv݂MIކj_O|}92|B|.! VO5b͎vg^%f:M;-0^emE;[ZdKRѷQEF-"crOGc 9D%貝F׏ f{8V#IFbAkC&5 Ɏ(KC=6JL!ZJ1;̒;(Ht¢ -k3%Q6<¿&k_/ A`JbCWPB@,@9 +`c¨QYG0{KOL]7PWpaX_;㐕Ut3LΏUԺ?`l׏Umcsfhu*e%e$ح R͖=b\%}}`0,cT5O#Yv|N/Klw5FWfqs@ʺoI?4p\?y11Z~xA~X+-'cRjݑͷ}]~[*:"P Z Wu0vhܰؐVUH2j'^רV:m \2A~ (Г2PA }}>!x`PkL٠! 2+vG3Q(2fpp0e(&)Ϩ.@\EXq ~,59 i~):f?Kˈ<;1bՋ(= LQѺni=WZJ0iY$MPV9vfA o{ؼ1\q)tmޅ0xmMM^ vO*V?\Clֵ89)kp@zy0YfG?9jp"VMGHF ̓c-x((6`$#vR٭: 䀿^ad_5pͬ:1$6!/ކ䝐C¾}-M<߅oZ݋6-K_o0i 58YlHrP#?_h$(|,ͻ>AXۃ!r`њhe_ Kߵ7:XfvKӕ/ 1@Z}ٻqR*ǒ^e.ʋ8IgIҴ8ut):?&L,9LQ'L ɍ?72rqJR^`5%ީN7xSk&x YT[dSB"Arg7<*{?8v>ǩU?)c3(ߌOCy2AB% D %rc@1[c̩,d=?QzDy6H}C*aΎa* u'@LajeK 8>BȾ쥧oP=).3Yӡo/-$,G}B#K:`nX7`GXEȇm7Sno}*|0h$a2̵MfGnPc'=@q3J 7[^ R 򘆸 Q^\ِ{M| *\Y +O"!ZYǂI\)Qfٔ $ 5zݠUZwF*J!|e d4;)26<jT*Ơ/5K;BGb5dkDBpT&n<. <4y1@{'ӬO #d4,iu~7P_M"K3#~ {?YסO:p%s6X u ,ޙio ;آ-7,<)bb֊8W!@FB~1HD# JDGamy-,S4I--]!){ٴLgW0k5)bCL]7pbD.~Bb2~rb2~#!l<-zXӪyuRoέ1Q0x#f'׎ogLFASfҠVBZuŸ {#֮**lM rPO[QX:Hșxŷx+.j=&F\֙g^םd\ ¥j^U<:<n<5Z y=N#WM3'Fnh##-s:nRto伢\XTN(Ɉ@D.#f[BQ V+\x:)),- 싙I\nE ̇PJMaB]W1ώpG_:OWrBK[`,^8B WŖE '`lEAM=k581Bϵb]Mc[?> A E5t)/2IƪFTW׳qS'IJ>mۃB(, W:.Ϝ&j{I'<Փ;]wbTE Uq&}z+@bMH _k!0-l4#]OP5f^Ewp|ʚ!F k3̀C!T6m/r'sIDATf 5 =nX?YLxQ y1 ޟ >npADݘwlB#*vc>_xQ<ňEpmΜ0ޥyvx=qsf܉ݸVqwiWvͲnD9L|>`pnjŷ qNq |0_yKpYsZƦ 0BJOq}#_v0wݮܸ^2$WaE ]Gef-! ,t9  r$nZ<[-p1|V5`!Y0?ƍ`E%I@>`җ^63V>!Q7q a"خ!V 5' FX''AY@iㆮ5<! 5P; 6mRƑ {u#Z_yr cp*_<[0I5YFwUn,R`w8S 8j(r$ y)Bn QNQң"9 [oKeY0X˪DeӮl'z봱&R ߙPha <:]+#:uniD%BxA:=aP+b(%˸/< 7S %D08K1Ƥ UNz^:8frձ"PA{DOkِ#7p'ИdWrUjl6$-7#<@FCUD堊MMƌ4&8VqJ<P<2: qHE<q 74Bhc8oLB H|{3/Nd OFٜ2L`8$ MwGٜ͑@@3QHG Pͦ@$<. p0_{B`v1KbXqD7d+ Ra)dw@c _JTS|T~E㈁a¡I~cb3Eqg2i '݉Bيo=1_;i-av.✨f3" BU"KueޝR uŞ ;VS!%1:qT<dۅş$iJ hT,eE~,ء;+`EdWN??rs`<0x6)3t Ny}dNFh=aN.03ON^,)񽡍dZiG@=#lYfBP{!cO a$IHXE:S:H8 )'O2՘ j|oFt!2'r"c3k/ +JEp|Ԙj5k1ӡ;3jԸ5^53A8U*w*A?2KO 1Z?6@xm[o7p nN`y,㼯A/-9Hxrg)t)`k1k?:H=Y]SZbӭ*հW}vkxf:_S^ײڟ>"PBBu7җధWoҴ|( W:4nF{KQRg?$!*G9fOHm-0'R׳[azv㧩n\NrO~cPc1E׽Z9x`p^z8tK;l]PͿk`ǀܵ=04H[oؿȃ{ՆF>;{ƍO'd3@0BK)DA (P"#8 BK>Có(fC{&4Sai=&4}@Ba+bF|@ւun oDh'.N m^=$ RZjѥ)=Xb }„IHZ w)3W6JfbBO" c!$=0ӱ*w% LJst硓iv1R(@<Qe  TʙfJT#BJY6i g e{?̲\OԞ6 |Dc ,}ݸygivUl8YP;o3\=v4}my-@]/a/1\=/Z(Կrp{g+RM95LtΊe{h -&f֛ЪQq#(Lڲgi`^D VF(\orqŃ,u/- 26\DhWSO\3XYj#N ӰXo-5"F@惤-{E!9u6(Le~ڲoy`'~~;B՜E~ulO|AHDy 3E*;~kD".ğ+R=G5' 6'h ؑ>% 1=LQ.׈`_޿GBXX2KR[rgD0`Z!}X2C!>-w,Xq5sf ,w@,_|7VP#f`Bhq|ugD Λ; lŷWgډ {?l!K@cΈ ˀ4ab-EF,o\vQ?b>_,*= 2PҮMCkѷ ,4ZN|‘>* UO:/=~8NCH fq<3ĉUO"'8te$dsy:!pqH,q(pE8.OLf70+۶&ٍ D?1n 7n|?qmFYĀ \/Q0, nʂpS8 ,xuI= x`zMЍ:uh{(m}ω7n$=_ =n'? Oynܸcw 1bxԃ/$q#C).0z 0t/+s"2$Fte@D2K 8LAtB}"8rju=pAXnƩ!QoNkYFsa >~w[/W>O{ hQu/fki a ]qPwTo#=gȅ $2i <YC\aM@u9אuJ2e%M OS< #nWU v/:u0c@L)X^)Xgx8WHFD@LczV <i 2 n| 'nѺ#ov&'o’!CVzb)M} !p'= /)eыNJylǦE[_ R۪tНބyI@. +;(xq,d !5|xefް"rSC/?508ߝ&.Ra 6ci|QaaUH[$gM1@.!ϙ$b1@&v Hhb$quǗ WSL/uF( nu)^%vkyb΢A/Tb,FHչWpIDiVkybNAwx)6:sK:3״5"-Ŝuxp.F~=i}Iֈe<=齸 v$;A;>d7n*=8prj:ۛ(<мy7n8?0t lzȚ}(6lSxՓvry t hzkkmw6tD1p\`ЈHJMu&SB d.38񨥚L [GzLG tt8y08ÀgRQm=g=xfHM_:[77Km x ߒ/ Z[=7n&=` cQd!>^ dKm3YiJ}a~"t_lDm̾`^xe׈=81p=q?_sxo>yYo  b ml3Y( "*xI!vT^ɫ@@ YNHȵT.R'1#غONj<ç~՛T|L6{;gec;"W%Ofy,`Ve˩ǜcDp]WoUf]lϙ?d̿e# E59PKҡu` ",Q761s% 聾q}#0;z>7Up&ե10 BK:*Z,hׁhD<-8_D)T+(>!q+ŭύG/I'UԈgJ(v|i{M="u Z!. &2F8u⠙H}*}P91ʽ4:X 5h1Вb蓐jۂe}%7-!POv{+cXdee+w !1@/ P9pAxSaKzRf SUB$2Lڲaa z_ CfX(vP?D?A/}_1y(W'nb_Dڸ[ JXb~3%~aȑmM懡垌O^rOd}pŐiқFDht =;Ɛz&.U>s^Olftf:w YD3[a2j‹jT$x h' FcH2B % v|Sh ˆ_B_$x=M0JH2zd{c@a>b[xF$D?1*"i "L # d1ȶ lp1o!BxͲqǀ3S @n[pxZ9XtI>KπS5!Hp,?0!Xu, >aapcx#=K\zU =oM{p3߸S@Dm6L~G-C])ҘZKVS\mcBaEMdA~# I&ۙ_V@K@Uf窪[1K=x5 tfy|G CvK>4nu҈t $Lf̀ c -1Ɨ0E^j7ݝD e׀;/r67:gY'Cm븍?!OGV?\FN'IENDB`perfbook_html/img256.png0000644000175000017500000002426411672746003015320 0ustar paulmckpaulmckPNG  IHDRcX_D;*PLTE""$8D 6SfDDff"l̙̈3''ݦ*3-EUQ}cD33U@@fMM"33wZZHoUUZww~ ff?awssuݪSGatRNS@f IDATx] c8MƛyMH4UϻH⡷FBlX a  o^Y_w6EZ;謽.vw=gMƱ7=WZD&kkMs([W ])6k] 2_iVXtٚc}Y[ PjW YC ֲMkܓDAvkU Zh{*kHtm5exTA̞^{ e-oA%}.򜳦7"E - >8ͦ ͕,Vo }1u%`CS! H}1F<2Wڐe4 r.Y07ĘX!6CX>-Dxr AqȽ=CH]Pp4ƸKzÌة%B׬1@^tp2W~r9Os82yfxkjcXINjTCJ2՞A~!eu֘giLyhO FEjϜ^HR*9\Ӽ3UEg2ct;<{y?g3̘#gxV"TR=cꁆWbrSc'HZs/ݙbLR O*ޱ8#@;m<+)Y'#سTp6٘٧mEV"g> Fgp_b限zBD"Gl#\ӍZr296gFTϤ[Gvy˨唳2g"cF ILԜA*\MZ/3]cR,:<23bw,hng;•-kmV )3ȜɹRyw&΄tL_ddhzudz7䘈|= Yv&+u\7jnE kk. ּg} 1r6}Uu P6?t*hr@Kr2{V^q)/I<ּAmNl3ݖQ(grS3rg\oQc?[yx_W♶osc,뛱kʪN38]QRxV ҙDdc); !~-u1 \)=C֣?Lg.g=&79f[;;LD{ =Z<= yTD{S}6`f3OtH)֭N(]]e0μ(c%잣Sl' 7WWhq?*D赣L!i B{b*/D;qQUU]g5e.(i9Y,k^቉䗺̜جG&G BTm-yNFYBN|7M229@)-rb{N2vfIS"G6-\Ԥ.p)ƖfF`2z,kE>1n% 3.-pi϶X{Z eɠ$L$/5a]ρ2 Z7FgʜbsmZbY~u Xef O2 #ɦ ?13$Fb 6;J`VxuL$4+zE'0||28F e},s Udf+6k e}kCj9[\V"TmB۵22⫛lkӬCPt[QSYüo$6&1Fxb@ې1X)n̹֒qQ)>zƆ<+MK>kOݿrc[q WW;K!Q c%97hؿTd1Ё c֥ ;zeou+*`ƕ f/1BE3:y)#E z$ru nnn(ГJ懂~r,+9(ܐ5u){0hP2Y;"c䞴-*PckPѸ奕1ɾ&X$yB`*hs=0F?-g8z/e8&q%2;c)΁1$ ƺSc6y@we{}QFu `)Ά1LB'(Έ1΄0׾TjqI<$ft{06WoA;)|bJL\(L/3flHc*3@lD74xjJcgHK|7d\84BN hEkmBѶ[y0&03=c {>w?bimʏ3g/fqߎ {xx{`%e/?~<ǪW6rrr:P0u׏oW 0ĘP~=1ʋ\̂`O.},Zgfk,eW3f6޷X*Vd~͙1eE D 9v(]I1jNɋ `?`蟳Wje}D&dleWkeLن?cʠ7.Ɓ(" tI e2fBbL#^Oʋ:$0tCJcg˘ 0@v$9pvq{ v~ߩ3V9یNNflW26pbnf3"NR,p y񸦳 `̴笱A6)kt#_p(no 41C1>I<W^gseL@u |ک"0a1 15PCb~q_ wj&6ĘE([̖1<2 caށl :cb) 1&&#4\S,FӺ+i[Ŧt*Ņ1aQcb\5c ]*[:ct%zÊb|[&!^G0Z\:3]e%lpb0̱ (<bc I=`a9Ņ374v(^ 1Ĝ/s ,!! $Lpy"wA[惝 il~!fޟOdG1NHcVzBN7T{?a;i `STXN?h@ -1gR1v0+_XrZџˁ:+^աl}tyvə r`\(1ƾEX.yW~9ԚМPTQbV=1DƜ` ]\ 1'6Da +~_av_wO8n=ti&[ 6hs9<,8ثZbeUm+sVY15Vjܼ/p {'P?+N-!0Xyo!_R[q7j}l6"ilf%F+_ű;Ҿvqm}q="i rX*OҘƸ3 4#1/Jc po$AXЍ< hH&8S^[ ,R,=tXn>] ׅ̆h t_;}Lպ bJKP(D@/\fhxfyXcPOTcTϙO3Ɗc/଱`]'6~ Vkl+Yi,` kLXi{jјv4㌻ppI`~!;-XiYj&zQ a @vY$A>cæ7p+D+"Ơ F8u|'$'I8")g۩#R#%+Lܩ.=V-]e4Ą%A2S)1Ic# 7$!sh7^x0% 4 rM#+iQ21W~KbJҬձNjH0<ܳj͌0jDZ>ѸbM>Jc3^{ 4X}8-m`PhӹDc_º=nPL3<4fGҘBb74M0=iXXP_cMX;֣?Ic1ӀZ&>_S8}$9}hֿIQcGoĵ1hpX N>ү6f f $1}7Z4Alj쉨|ek7m\ 1S7yhԗtS&mkYZF$;叇 _>]5flTF];+a. "7$MWhqFb`vnqtD  4+ҮRA4J,iMYf*c&+RD@qKseW-z8?FhbsIcBnИ~xKI0'04kC6Ƥ i䐛_CKԝ_NW lX즾%8lfX|O;9xV_yRN4vjg06F9i)I=$e cIc \BD SIc f"l7U֓ƴu pIn0KkqW8I 4McS!i yIEWwZ ~&j*VTbΆ|34Y苃mD`%m^VER*2pIDAT K/Vc5.u55bR1OcHsм .(6Ɯ,0QczIca<J,ȒB,t'VH, v"p:KBWk|zbid6i,,f1b,il<AwS0IcFIca.=,AXm&wY-@s%HO!uK_(k "b1ihL/iq63H,l/Hcm?#;y.ji ƒ"]0sxRUby~>XAw˪Ru]lDx],ͪ1Ăj49+G՘jsYc@4VPE4D$j[?LSZV5]KH,Ȓ@3bToҙ 1 15"i$0  11g1B,ii,ȩA 11Ic>& 9gS֘Ăi f4W٘ƀ &1*eV¸ 4"i%h:nj:a$1ւMQ'vliaxدg$NQq81il*c7+vkXL1\aNcgaWX'CZp̀aJ,,zĮIc,fT O/z&s3Ҙ:D 95u9XvSTycp i-,+OFn5=ܼH+iYhY^L5V=ܼHkF_6g1ĒƦ@??F6# l qL2;,owʼnH 4"By,N"!1 +UEb*Ic,fvaS]b6SdK -{M.kD!u -z+Ikfalj 9OɰmPc8 9HLYu9ae[/Oc%ƆILNu(ҲsK f4& 7.1.3 Partitioning Example Discussion


7.1.3 Partitioning Example Discussion

The optimal solution to the dining philosophers problem given in the answer to the Quick Quiz in Section [*] is an excellent example of ``horizontal parallelism'' or ``data parallelism''. The synchronization overhead in this case is nearly (or even exactly) zero. In contrast, the double-ended queue implementations are examples of ``vertical parallelism'' or ``pipelining'', given that data moves from one thread to another. The tighter coordination required for pipelining in turn requires larger units of work to obtain a given level of efficiency.

Quick Quiz 7.9: The tandem double-ended queue runs about twice as fast as the hashed double-ended queue, even when I increase the size of the hash table to an insanely large number. Why is that? End Quick Quiz

Quick Quiz 7.10: Is there a significantly better way of handling concurrency for double-ended queues? End Quick Quiz

These two examples show just how powerful partitioning can be in devising parallel algorithms. However, these example beg for more and better design criteria for parallel programs, a topic taken up in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/node240.html0000644000175000017500000000436311672746162015646 0ustar paulmckpaulmck 14.3.1 Simple NBS


14.3.1 Simple NBS



Paul E. McKenney 2011-12-16
perfbook_html/img95.png0000644000175000017500000000057211672746014015237 0ustar paulmckpaulmckPNG  IHDR5 70PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(Ւ104!qդG88a8Gl]f.Dl] \?nVV`5M*DzioX%Reg,_^uߑ Bc0 14.2.4.6.2 Mouth to Mouth, Ear to Ear.

14.2.4.6.2 Mouth to Mouth, Ear to Ear.

One of the variables is only loaded from, and the other is only stored to. Because (once again, ignoring MMIO registers) it is not possible for one load to see the results of the other, it is not possible to detect the conditional ordering provided by the memory barrier. (Yes, it is possible to determine which store happened last, but this does not depend on the memory barrier.)



Paul E. McKenney 2011-12-16
perfbook_html/node457.html0000644000175000017500000001714611672746163015664 0ustar paulmckpaulmck E.8.5 Checking For Dynticks Quiescent States


E.8.5 Checking For Dynticks Quiescent States

Figure: Saving Dyntick Progress Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 dyntick_save_prog...
...et)
15 rdp->dynticks_fqs++;
16 return ret;
17 }\end{verbatim}
}\end{figure}

Figure [*] shows dyntick_save_progress_counter(), which takes a snapshot of the specified CPU's dynticks and dynticks_nmi counters. Lines 8 and 9 snapshot these two variables to locals, line 10 executes a memory barrier to pair with the memory barriers in the functions in Figures [*], [*], and [*]. Lines 11 and 12 record the snapshots for later calls to rcu_implicit_dynticks_qs, and 13 checks to see if the CPU is in dynticks-idle mode with neither irqs nor NMIs in progress (in other words, both snapshots have even values), hence in an extended quiescent state. If so, lines 14 and 15 count this event, and line 16 returns true if the CPU was in a quiescent state.

Figure: Checking Dyntick Progress Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_implicit_dynt...
...8 }
19 return rcu_implicit_offline_qs(rdp);
20 }\end{verbatim}
}\end{figure}

Figure [*] shows dyntick_save_progress_counter, which is called to check whether a CPU has entered dyntick-idle mode subsequent to a call to dynticks_save_progress_counter(). Lines 9 and 11 take new snapshots of the corresponding CPU's dynticks and dynticks_nmi variables, while lines 10 and 12 retrieve the snapshots saved earlier by dynticks_save_progress_counter(). Line 13 then executes a memory barrier to pair with the memory barriers in the functions in Figures [*], [*], and [*]. Lines 14 and 15 then check to see if the CPU is either currently in a quiescent state (curr and curr_nmi having even values) or has passed through a quiescent state since the last call to dynticks_save_progress_counter() (the values of dynticks and dynticks_nmi having changed). If these checks confirm that the CPU has passed through a dyntick-idle quiescent state, then line 16 counts that fact and line 16 returns an indication of this fact. Either way, line 19 checks for race conditions that can result in RCU waiting for a CPU that is offline.

Quick Quiz E.20: This is still pretty complicated. Why not just have a cpumask_t that has a bit set for each CPU that is in dyntick-idle mode, clearing the bit when entering an irq or NMI handler, and setting it upon exit? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img180.png0000644000175000017500000001416611672746016015320 0ustar paulmckpaulmckPNG  IHDR,KPLTEӧwwwuuusssgggeeeQQQMMMCCCAAA333111'''!!! z|zvvvtttrrrpppfffdddbbbZZZDDDBBB@@@444222ûmtRNS@faIDATx] c8v6ų%3NYqsڳZi3]_U `}sDZGґFujW]"^HhJZS &IXMAźbdSPm܁Ĕ#( wC0X'+va0\]ʘ]2)R.ՆJ żQ#_2:msǤ\(FHb,K꾉 PMHH9瑤=/uҚ\!tYy-)1؄ӝB0#UT]) $!y֍myD^% ў,J9i_X#qXTJ\;P&$ W?W rYNSn l)\)Ly$ra1M?}RY#' i".I|/ -q]m . |::xe]b;SŞv:卾0R.% D*sy:T8+$ 7[:$^.cJbQSN8RQ#5+^HR页ν( DKtԟyY6Ua. irwZWc0-o $y(ҽ.\J,BI~`E纄L-o—5(5˗&W-4]irUQ8RhM뾋Eo]'u.Mt)ʺLO/Wr{҂.kxAUduamh#Q폧kOXx-02"x[6r ]K*ĭ"iǺdB4 :!JQl3V^58"Ec ˦MvG\.(g}) tWN PUI {=M׻鮖.\ãG򃴳\zNRݠB)uS?*_'"1E?-U)|{J]Qq L]r7 .cxE gtAa 4Ce$'tX%Izznu=Rܗ" cDnQ*ruYe ]$ҧ6ɏuHI$ ZjtKʽ/Ւ.U\e2dtKI cE6<*,>"fA|$D(\SB>|&ոef[//N#p:y-,! i2?K}`L >=z'd,''Deez)rh#ehKK?G H), K@^eV:hEPri([43Gp鐞8gs(5jqddoJ*l;{62O]. " -t깥]ጀ.1 d /!^#>="7[DhB.=(HrR0 BO֚YJroTͲQxИ%W YʙbQRʔ[eK?]-dfI"7jʀH!)7A+|#g-y# ? "~Yi`By?|qW&÷?ɷ%@Tڎ&qC1BS,kgBgX)ae{')3 iA2E[@ ,LI SaA%ӟ"`{.43osxf)g) R R%/Wv@Ą%F12_,ؐl1Ҳ,_l>e$WKYӁ|l O #Ԓo,jFFZ,OԈgg{!_,Oӹ5 /Lk@&} m!dfQ#L 2bK^BlLts=Q !_,R3{`n+>՘BgOd/dM,^`6tfc:liztfr_,T\ĺ,0eLYbCOB^+3LQ˙vl0 Ɵ,974_%#Q7R1Vi>'LYJ%Pf ,jZh!: 2![h`&MDLp#\@'jD33:[\Cv#<Yʮ|]=>L}>_ ϳTnYLcl1ȶbKY|XEI v!L.c ͅC%%ZO˽xȰĂeej, R'2I5 ,*/V",Q$ϓ!UrD¾fWy+M&Og2 r,Fû q]OJJQV XD(UpҰ|, #~T[h3"@<,"O;/NIE/Ҭq1PBrfIB|)Q!k3,8ХqXˬ /mϖf3uT4 \{U e?Y.~H, Qh葞VEAˀ-%*̺Rb"s5\@-_ DO6V\, W@xY2 RK0DH4Kdٯr&7^}YG: RjUHQJ@-p<5,H%l4 1& ]GP 7]1$֕A|R^@25 7D44 ,e3EM$85|__5lhr[[ ,ʻ&E!3K2|TMJvd 4EđE88XÑ,zY 9Ay4v4qd:? Y1]FMJG.`Ck9 VݳX߯&,WH<_kIOe=np;8 'JntF+)Pf'MYzY #+U C5Ԏ&,=Coίw t>N柼 ~>a<qd}%#wB)_3G#ݒ%W9L󱡣,`4h"͝!X%7OgJݮP fɑ=OgMɭ ~:rx4MSg3$q|8|ͦU(xO kɟ#K TyWUDd7672 d`qJa췰@Hxt47#KTFђD?&OHKaoÑhn*eBs#DS ?,#K竔SAx5D?{7*'S|{ė*"97n*5HS YiQSA$T ultnd/twp^Ô0DH'kycnG.aeP4KhotEA>hG{X ҊY4?G1hOaV"l4H@"uMʅ<.Q7,! [LEMf"$ڂIYFũ #)ZP&e>H{ h; ЊZ"B=dse.)K8??Vp ZKHz3bг O&2XPœDG YfeQ r*s>=g,e59,aa딞Z 4ˏ6 # 籐r=̽6JjToP)QnĪ?%n*{ K3i SQφ1~$1ۤװh&pI̍ÊgJTrEt2hY, UAs%wW!kxђ]% m5S!dnX\+H!C'SA.,Eխ|Y!!)^oV<ٳ{}֧`[M"5UTlIS>Kj(#QJ{L"P.Y\AcSANiTBb40|.VCT~@!#QF\㠣]A&h["#"qѮ ZFɂTN?Y5: r)wp-gO7F pSAᦂ8X [~,Z?vK\-{Ć̯(d>-YGCE9%ɻe-GY<pWQX{.{ZŪN4'c!X!b,`,G|"+\l#K_46,JG#W" đs|\Bl#KrJ@\ૈdK| 㱅&,G|؄đ_⫈dW ڟ -5qd=Y. RZ akMYz8Wɮd t+đ`*HZCA\ul#K# ~qx/E—_6 I9_ة$a}glo (^[/^E11UƼs_q 2NN`KY3Y ǢJ}X*_e,\2`kYz|`[MYzQ>C[hn*H &,}GT]q*,=G70$$ őU. Dpȑh}*đh}*đh{*H誡 a ]7qd mwt3\T8]L#Kɮ Vpd=ڞ bGޣ pd= bGޣ 6h,]TYiIENDB`perfbook_html/node403.html0000644000175000017500000001333011672746163015642 0ustar paulmckpaulmck D.4.2 Overview of Preemptible RCU Algorithm


D.4.2 Overview of Preemptible RCU Algorithm

This section focuses on a specific implementation of preemptible RCU. Many other implementations are possible, and are described elsewhere [MSMB06,MS05]. This article focuses on this specific implementation's general approach, the data structures, the grace-period state machine, and a walk through the read-side primitives.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node38.html0000644000175000017500000001255411672746161015573 0ustar paulmckpaulmck 4.3.3 Special-Purpose Accelerators


4.3.3 Special-Purpose Accelerators

A general-purpose CPU working on a specialized problem is often spending significant time and energy doing work that is only tangentially related to the problem at hand. For example, when taking the dot product of a pair of vectors, a general-purpose CPU will normally use a loop (possibly unrolled) with a loop counter. Decoding the instructions, incrementing the loop counter, testing this counter, and branching back to the top of the loop are in some sense wasted effort: the real goal is instead to multiply corresponding elements of the two vectors. Therefore, a specialized piece of hardware designed specifically to multiply vectors could get the job done more quickly and with less energy consumed.

This is in fact the motivation for the vector instructions present in many commodity microprocessors. Because these instructions operate on multiple data items simultaneously, they would permit a dot product to be computed with less instruction-decode and loop overhead.

Similarly, specialized hardware can more efficiently encrypt and decrypt, compress and decompress, encode and decode, and many other tasks besides. Unfortunately, this efficiency does not come for free. A computer system incorporating this specialized hardware will contain more transistors, which will consume some power even when not in use. Software must be modified to take advantage of this specialized hardware, and this specialized hardware must be sufficiently generally useful that the high up-front hardware-design costs can be spread over enough users to make the specialized hardware affordable. In part due to these sorts of economic considerations, specialized hardware has thus far appeared only for a few application areas, including graphics processing (GPUs), vector processors (MMX, SSE, and VMX instructions), and, to a lesser extent, encryption.

Nevertheless, given the end of Moore's-Law-induced single-threaded performance increases, it seems safe to predict that there will be an increasing variety of special-purpose hardware going forward.

Paul E. McKenney 2011-12-16
perfbook_html/node199.html0000644000175000017500000001121311672746162015653 0ustar paulmckpaulmck 14.2.4.4.2 Pairing 2.

14.2.4.4.2 Pairing 2.

In this pairing, each CPU executes a load followed by a memory barrier followed by a store, as follows (both A and B are initially equal to zero):

CPU 1 CPU 2
X=A; Y=B;
smp_mb(); smp_mb();
B=1; A=1;


After both CPUs have completed executing these code sequences, if X==1, then we must also have Y==0. In this case, the fact that X==1 means that CPU 1's load prior to its memory barrier has seen the store following CPU 2's memory barrier. Due to the pairwise nature of memory barriers, CPU 1's store following its memory barrier must therefore see the results of CPU 2's load preceding its memory barrier, so that Y==0.

On the other hand, if X==0, the memory-barrier condition does not hold, and so in this case, Y could be either 0 or 1.

The two CPUs' code sequences are symmetric, so if Y==1 after both CPUs have finished executing these code sequences, then we must have X==0.

Paul E. McKenney 2011-12-16
perfbook_html/node355.html0000644000175000017500000000553411672746163015657 0ustar paulmckpaulmck D.2.7.6 NMI from Dynticks Idle Mode


D.2.7.6 NMI from Dynticks Idle Mode

NMIs from dynticks idle mode are handled by rcu_nmi_enter() and rcu_nmi_exit(). These functions both increment the dynticks_nmi counter, but only if the aforementioned dynticks counter is even. In other words, NMI's refrain from manipulating the dynticks_nmi counter if the NMI occurred in non-dynticks-idle mode or within an interrupt handler.

The only difference between these two functions is the error checks, as rcu_nmi_enter() must leave the dynticks_nmi counter with an odd value, and rcu_nmi_exit() must leave this counter with an even value.



Paul E. McKenney 2011-12-16
perfbook_html/node282.html0000644000175000017500000000450411672746162015651 0ustar paulmckpaulmck B.3.3 spin_trylock()

B.3.3 spin_trylock()

The spin_trylock() primitive acquires the specified spinlock, but only if it is immediately available. It returns true if it was able to acquire the spinlock and false otherwise.



Paul E. McKenney 2011-12-16
perfbook_html/node131.html0000644000175000017500000000634311672746162015645 0ustar paulmckpaulmck 10.3.1.3.3 Discussion


10.3.1.3.3 Discussion

These examples assumed that a mutex was held across the entire update operation, which would mean that there could be at most two versions of the list active at a given time.

Quick Quiz 10.9: How would you modify the deletion example to permit more than two versions of the list to be active? End Quick Quiz

Quick Quiz 10.10: How many RCU versions of a given list can be active at any given time? End Quick Quiz

This sequence of events shows how RCU updates use multiple versions to safely carry out changes in presence of concurrent readers. Of course, some algorithms cannot gracefully handle multiple versions. There are techniques for adapting such algorithms to RCU [McK04], but these are beyond the scope of this section.



Paul E. McKenney 2011-12-16
perfbook_html/img202.png0000644000175000017500000000024411672746134015304 0ustar paulmckpaulmckPNG  IHDRo$PLTEMJKmkkXUV856C@@.*+&YtRNS@f.IDATc`(!a]d-b7 C+Y3001X7IENDB`perfbook_html/node433.html0000644000175000017500000001367511672746163015661 0ustar paulmckpaulmck E.6.1 Running the QRCU Example


E.6.1 Running the QRCU Example

To run the QRCU example, combine the code fragments in the previous section into a single file named qrcu.spin, and place the definitions for spin_lock() and spin_unlock() into a file named lock.h. Then use the following commands to build and run the QRCU model:



spin -a qrcu.spin
cc -DSAFETY -o pan pan.c
./pan



Table: Memory Usage of QRCU Model
updaters readers # states MB
1 1 376 2.6
1 2 6,177 2.9
1 3 82,127 7.5
2 1 29,399 4.5
2 2 1,071,180 75.4
2 3 33,866,700 2,715.2
3 1 258,605 22.3
3 2 169,533,000 14,979.9


The resulting output shows that this model passes all of the cases shown in Table [*]. Now, it would be nice to run the case with three readers and three updaters, however, simple extrapolation indicates that this will require on the order of a terabyte of memory best case. So, what to do? Here are some possible approaches:

  1. See whether a smaller number of readers and updaters suffice to prove the general case.
  2. Manually construct a proof of correctness.
  3. Use a more capable tool.
  4. Divide and conquer.

The following sections discuss each of these approaches.

Paul E. McKenney 2011-12-16
perfbook_html/img33.png0000644000175000017500000000044311672746037015231 0ustar paulmckpaulmckPNG  IHDR k^^-PLTE# MJKmkkXUV856C@@wuv.*+DAtRNS@fIDATc0``0d`0H`23a@u Ta@;QֶU : ":-f6 zg]8ꀢ8c4a\@@bt:(KC \ |vL<0peM("$bvIENDB`perfbook_html/img221.png0000644000175000017500000001727411672746151015317 0ustar paulmckpaulmckPNG  IHDRJm!Y/EPLTEb``MJK# hffommmkkXUV856KHHC@@wuv.*+-**vttD%|tRNS@f%IDATx}-bcsAjSUh38dg <9`OQ㿷]}K;jK~}`L6L\}fd\7\rxFu*uJP~L0\U0+ N&$a629._R}yOvn(eĕ2 bWql/>E h>K;;);6^iJ@y\ Dch.px﵊5_\6NZ;s_?Ifk|XUv>רUӰZl+Ļht,MW^DԞFZV(W5G悝a#|ݿL؅ {oYklVV03&ya`sŠ/ *V 'onWegWֿsBO-WN{@rU0:(XtvhզesW#;4k^W^}={">APf//?6z5 @$p jjsh[rM@^af18Iإ {L]Ozw1@!tG(E=k[5/2­#j^d߹5{/1z9SLFx- Džf`$`Rю6iPUӃP"Gղt8guJqRG=QGʸmN[|-|\gQ(0ۆK!Zaha= ﷳT9JNxϔxQ0IǪIjx{'ᘚĽ]/4;|Q^8MǏM@#Ճdw۾-L0kPHxP_v u3ZiyGzUu^r]1x^P"2O2WT]2^{/ *23;l"@r+c:%56 Z!>w/G3jV=BUk7VAZ(cO>Fj9L/0g oІU]upE:Nj$ ~1oI${+O_!TrkDkŕA/3ǑyY}1_L^'s}|/ޓL\b|IGA2<=G/eOE2^fR׿صGߔ/Q;?at[>;!us5{ p'_._rZ5!mkswZ [/Y4JcdC`I{ gϪ _s?uktѲ45ty2U"xk5ҝLa 9H  =]<@1PCP6HٻoԥY^`2/}VW؉\-+9 u̡G/gKm0ˏ|%o?oOBD:70ڀYW2/tq+P^ J[}&@iiݿ|hd&!Rΰƍ:#/SC#W뻌4ܓ=c@iy3K0_ #8{,Y@ }n]gDѢnv<]x}#Vտs=vG{_k֝4p|~-D:/ Z`UC9"ކ7y|qӆZO4ѭYq[Q[ aH'wZ:=O!)kp2=^h<B[PX?G(OCrBp}꣘%!|/2l-GgmLseV V! !_ﭗI'숮Ig@N0yf"zlYy:P}ZR3hk.99ݏ۩430v3=jT-d'@|bKe"heeКseTij\ѰTCƞlܪe"oIHd #yk[&;AǻX\GD,l+[&E}XY+L2Hfn4HcvX5zD|1DԵ_f ("E#Cfm/4}1Ar.z{vͿA6dPnp?0܆ۼ$ZB#v u1pEXv  X;5`&s XV':K|*ӟ2z|a|^8pc]jy]wZ^nj8r K`i>^:7ӽ=os[咪E>sClҸgGT5 q­O.iCcK߮U@suMz Vʹ[ԴkC*∜CA@l Y`4| ܛMto_˭ ?_|uywWqb'[,kuQﮭsDN -sh:sX%R G=r^y~حRҵS_u y&f[/x4h>cnpx**b.oe צ% s.'Qb% CgGf-S- *?)|E:DFQp*I^-p0K!{9P) HQi0f/0R&jەnr;'eC'k=qR ~?9fO%)-E+W嬚!(uz\˯c<j6MOcF?CP ?#M `BIW{sW{j?최ĎSl2my}#:,.w)r}-s &lz.9U# A9^X%qVuDͱ[K>l$ΰ#U~Y$%젗"BoVqwi/ ('q-1/6^_r,&f` ~[#Yi\~Wu ,u%hLKX? )]jUvbtcP9QƫKA$@M2Hn$%4yܶU8iC#t$K9Oa+QK2d SPr ko0̥\|{2Ի1cX*!),7hSS`-J! R0k ڤ ̵ AkN0,_\ݧZ`4?i;+0\g+ GF;(g tb]h !?>1m`T$jYiנZ8 C[7D.\-WE%.&c#OADgՎD Gb^HR1f;eθ_;ƇSAQZ]5(>۶4SHsoY:.[^WlzvÐ56AD;Im@ǾDU =1_gQ#ښ^f?`V.貍cX87`Y`gkfIWٸMp/f,rN-_0KӸfQFHAn9I]R>FZS2EZY_Y`Fo3_ VpW K]5+/m0" hcŰb+jV}sf4l% +Bfk3lY9K"t!ҊM cptGA$/$ ?C>]O?ޖQ %Xۮhds4ΩY0>Gp(fŽ%g,ECWW03 lj1dklcWWʵ7gF|7ԑ1K6Gꀏu[zTgu6t+w<*LsnhO*nRê8GvکZqcWS>h׆ OaT>w pkpjE|劉jC\)ک6x/OաmT.ՠ;_Oq+nG AKuIxr^gAM+ WP97?)*Y99Pym'T,]T㳡.3Z]h9~UTm0Dܠsa%i\t}sn4|6Y*5%^Co2/xS\*lx(.ΞtDZ:TjV.o8v*j'H;,wniş-nHAS0:+&cE"IΘoϢ1Wx]/dSPU2<`:[]rC byy}@F$^y:};!&!mpN8>yUmUp TL:'&þP3~^2Xn8'^Ovyg%}3Pbs]jVp(g[حx77E\r QUmI۔g{3rxCAAA05ZqcQ*KpAAASJ)fz]tJּr98Z.8$<6BFl3ה|1BSރtᏰa9kPG8 !Q7pss]pn+w[lަʘ4! <ХxXoך8fzuGjJW"cO(qC [IA2?,z3tغ=ҼXDZ jGdڈ,bWuTf|KX&8ƈaY"JĻE݋MLez'Z9FGAhVfOe]VS!pTooJ pb\?.#WސT,Fm"h?]tbY-htd!W([7ʐx-,`i$^WCtkzR#) WQoMi{ej&ȅ& %}% P9$Gj9$DՏ}o!"fs6;u"B@fQq[pdjQi(N[R$dΘWƈ o!m>e'a#@:F&FS, C[ӗl?ŰE=ь! sa)'biO ha R_T!U [7gm +F+fx߱ńS.B\l~8m]# gr+xeLj Zzk7;\PdB)XWark]݄#K [%8A7^SX=w?:ϰZK/e-P3FB!1)~ګ0CSMY9$f&eNw"IENDB`perfbook_html/node171.html0000644000175000017500000001214711672746162015650 0ustar paulmckpaulmck 11.2 RCU and Counters for Removable I/O Devices


11.2 RCU and Counters for Removable I/O Devices

Section [*] showed a fanciful pair of code fragments for dealing with counting I/O accesses to removable devices. These code fragments suffered from high overhead on the fastpath (starting an I/O) due to the need to acquire a reader-writer lock.

This section shows how RCU may be used to avoid this overhead.

The code for performing an I/O is quite similar to the original, with an RCU read-side critical section be substituted for the reader-writer lock read-side critical section in the original:



  1 rcu_read_lock();
  2 if (removing) {
  3   rcu_read_unlock();
  4   cancel_io();
  5 } else {
  6   add_count(1);
  7   rcu_read_unlock();
  8   do_io();
  9   sub_count(1);
 10 }


The RCU read-side primitives have minimal overhead, thus speeding up the fastpath, as desired.

The updated code fragment removing a device is as follows:



  1 spin_lock(&mylock);
  2 removing = 1;
  3 sub_count(mybias);
  4 spin_unlock(&mylock);
  5 synchronize_rcu();
  6 while (read_count() != 0) {
  7   poll(NULL, 0, 1);
  8 }
  9 remove_device();


Here we replace the reader-writer lock with an exclusive spinlock and add a synchronize_rcu() to wait for all of the RCU read-side critical sections to complete. Because of the synchronize_rcu(), once we reach line 6, we know that all remaining I/Os have been accounted for.

Of course, the overhead of synchronize_rcu() can be large, but given that device removal is quite rare, this is usually a good tradeoff.

Paul E. McKenney 2011-12-16
perfbook_html/img14.png0000644000175000017500000006735611672746124015245 0ustar paulmckpaulmckPNG  IHDRXM|PLTE֡alۯiwXbVbzc KVI|540 ١Wt^o|,0*ɕx~ ^k]j?C< agl{NPJ֤P\O ݵ̖𐲊Ν8>7 ]i[\g}hvGIBꩿ ۧÑ"# 惰̏œ 683ϔǘgsաԢ߳ߺjyYo[ݲ*+&''#HtRNS@f IDATx콍WY'h7S`"u =ZR=MuЪ̣ZInMR-LFH6dNkfNj[ %:'+}R$OQv/nI!*?P7_{Hӕ0g^ҙF\!ZCkXk<%IX՟QQ&Q0Z[^}IWݺj_DfUCpB^I% @=/[T"&duZ* HE^j9ʇr`CE gKL`q(1_m+1)&b/d(oLuFR!7 Y#TB _:p$%/,ձx^:L^qgR@R}:,BuƼF%;=:xJ=ˢ>3kmEi:rB&d<$z6Fs0z}n3厏-6WcfT/BN{ pzr9>'?::Zi)Q@ R9w 9 {NoЛk^6+p7y-Ӻ66nhvG軗rӾE/:pmT6[zM;k[t>& +^"]kU]S,AiIē"$8d(C6VYt,,鮇(fp]K bPeI{u[W]zZN8,,چW$;G9o auĘ:y4]hW$#k)DH)<ȆEbB~ns`C3&3l_չX+SYit•$۷ 39kmKhhx=4NhxRt<9n km~<r3ʹ,/zm+Gs̀lsAKk}[藅yJ:k݁~\wKR{d}/-CY7Q߂+,y|GX Us0n=orؽIM!"l.ߗ59?f^{*uޖ%rz_wk"!tz JRUw=e{-ON'\+َۣg${6`@0É/`[Nm>}3e5)\Tj YË[Glb)ZEJ>ⅇ}> 's6RTsΰu)FNC,|*M+,6oqNq7tK!V)ڨ*.Ya1k[wPH%'(hTqTgN9BfPR_cxnILdِ8[rCd}(*$a iI\&?*-!%dQL Kڍ[Wo>TRF,`Hq+4PdaLcK~I-pḱWxP:1Zu7m~}hIKǤ 6ZF>4wX>uF?4u)i!n1,ˢTA}LH$gƊJkɋaԖN?, }Ae"85Iulj8BDV :-zs~We5>f1HO-[OB'}X`'] 6ɛmnzҽ6Yg٭ڛu$/u`&K9j-RYNt.JOm1W1vɏla_}96vӢUWj?N/3lg"@tL67?(TQ^t/>l:2YXךD'4谆PT\ֈ\#R>ņ`]K]g"ÎTA\pzOd w788IKu`&&d!h9Fa2S܉ yl0!|alP4±-WqsP0iXjh#&u,39U)TؙyP .]|}W,~N*j{z)n^+24fǻ|.Q{Huo><λURЧ>IĢ%lM&Q Zj9q׋#/ IĊM…<GDò XX1\9agh(3ҟ;itRش')vM{yҹ+etR=Uκ%յE)B4 fY^ {ti.{b9Q'x7b8i5"j {EJFd'vYoߨCq8]JxwR(JaE*^d3P(X\}V4ЅD/t5#0௯~gH r,>,2>ҕ[޶2n%eރdz!5,}[xUri/Oa9bbj<26xoM0m =y$lyOO͓S3Վį$Gb}`)<ߘ^LՃO U!7F# ?}aqR'}_Jr# imccMҦW)C˸U(^#g6clO-5[تK߽3|٣[{0ܟ,`ʖPc]FڞH@5mx,?%6=kfn- Ʀˠ3mTΚzo@O)O˝ laΞwKI~%QwmaL74'/o1Ț;cD]8Q±K 1s3,˺B_ j_OtA D73] {M[NŃ}$YWkd7aͫkOO{k'!ş>q}4j8k 2pKk$E} tRi;g9aA$l+!%TVøYanu+h&;8ӖbD%5\mo:DEŢX;&j)*McՈ+~>Zkxͷy"VuwYfϭ9μ*"Tnkϥw[oovsW?O7d5ǵ%u'c \r)KX%0b6f#x)5@P9ST@BYuCz<t!4`|M")iFKFz`帍@GԴoQuS?C btmMf'_ !{^hfr}}Qg0ؐ%dfh:Ns8YHn Ie '.aYeA|,JB>E -W c٥I;]aq=Kŵt:>z׵ϑe;`@Qd*geE#m&Ӛi**ѽ:7.ozSD:bWu6 n/X6p3T$Й;xEIQ"CC*9.y"9Sv)j""0c ћ:Cd.}YyM *Akcێd[Y@clH=H7_ `}hy GQThpug"t(q^I,˶Bb}_"?"`A$̀DD]ޓ+[p.xKƔdQ硊VF.֬U_W7'38Kf#>e ,,$BQnvZS32g"bk8h'1,FqzxuN:uq'bq["o*&Ƴ &"f'." f: ҉0*cW0O#sّ}5W@KQwA/t-* \ x||V_ 8%Cdz8!'l\u a[kX:..( Iw>q1ΙM{.=iML0H@hٌq q2qJYfre7q~J=Ky&MsL`v1$ܻD.DQξ5 B>=2W5_r\dttûj],Kq,+ o}$W,݂m3jn&e E)|J6j_ً04,煹n;i\}{_X [Fq| &b  JzF b_(XֶT^m9ޟW6b; `3Fk$lGT#v-"&8/3T 9*f) ˯|J7-G5'o?Gڣ`pw: Fw h$#otAch1 ~)QU ɣI[3z!5 ĩG;f+ 93 wt7g=^/ ,H.>?7sgT=KB])fS ip;l#hA6-., z>?o`*Ӄ.9뽷j5(`ÍGq/Y`omo/A2z1'=d² 4xwS/|>Vѳ9vL$ÈC~<!'9/(;Q g*ƅ'[IA0Sk;`thzLKp}co[/^ڝryv_ƼA!lɟzsV/fys ĻC$QNoG-r OL G\Xf?ˁ^_Ȁ~*>Ԝ R*$4xzX 3-,-U½-qQ˹r3ߣS+ͯNMM }**vAsZTѧlŎ|3S;`rvEX?a=7K')k9J=vS{] yҬGQE#l>aiF|j )8_툏uwʁ>Q{Q1wR:L8u0̭RF1tdﭱ&o6!;777;n>xEˎS.ѻylaS G|'^$9[Nqg{7dӛ -?>F|v=4#].ɣ{V3c\ڛY=FW&4OXM0v5˪zzAzP틡{/ڪ(}e7`_NZJ7`_}=63  zr@_|Tȁ-_0y*9|e%Ȉ3*';Qm֎#T[Ͽ{iV-rFTk'!,O{"ۃUO.'j4Y=_]ܭא1,sI wf(h)`УJKY'iSh풯'0F/D(klEkdEj 2UIEx ٕcJj&ý=ȉaU᪱:(/]YLVQm3P Wv/ Zr?PX3!*--T6ibRHK{4E_G+b`dRKv WQ*3hԡ3U=KQ'n#2UZG<%2(>o \:hD^BH it޳K3.jZ)D9{yW4"ąch]ݮį3D RuZu'[TEhn2~B67+okguF7`a#8١`Hz,Z9s82PRd+w翽`2H .]adomrb*&$~؀ʺń Y֬Uf? v1COɄWnoIt#ܺ"ٹ@"dV鸺jUqrY}Ret1ZH [?̾C[w! |i=a6It4ar ??❝oAYZIFhLl2X!z8-YtVélMWaaؐ_8zwZӲ9QݠbTju*靇g[S:\JZCи6 AzQu:3R0V֊.S1(ږIײ!Ǵt+t\ Z49Gy#JO}[`5kÈ+b*YE˚-!Q֌G|} 3u`h=ySr2u ΢КR!=K Dz(=ϔ[gfʥXj%Fwy֪VW`q!`Q5b2\)-jrr?fN.5Z%'&B$5 $F&0 \ZM*ῌeͤ#]K<$+|N_s $bpm H%rB歉r:@%Cϗ8Xj`Y^߆;^fRΕ~lGuhᥢb56cIu ,Ś`2[Xq|0[AvGA\]BԤ`Yrqy7UUuBtD{nQgZIG W0v~[6B!a62rt3*֥$"J^vxFmFc9JxDb @]?BhYiN׬;)%D"R Z2Z2jr%,ۣ1Bȴ 9@Dh)V6ZmW]T/0Dq.2 "ݸ)ջÃ` Ӵ-7w~ڌkYςq1*xJ1p0*^Zہ\BDY-[V&Ԛ҅bD奈>:P •ӄXyR:ׇ)[аӹ^9g|lnrrb׭r"Cj%tZJrY| (kCwp:iiմR(RxCzt}Ӡ\=lj]D*@:޸|J)yuZ*;>W)_̴/+Lfw~Ce:ޭ[pynv8_ v=%I.z ' WTƯ.Mt(Y!Lӵ1eBkCk("/F]AMi]xCv)JAKSn‹ chD4[OLWP1Fc+΀Q\SzUq./م#EˇBkM/ tx'ui( GM-IR4lƃְUkm8TW~d7%,PhEUZSg% _4<7ڐk2Rbj.O5Ͳ}0Z}>NVQFP,4_i_yA h²̏F#Z[ZΠZ.R .4@AZ4`ARbiZ\S 9 ڠ;bQ%HrXS΋05t<^5牐1?gG0Ͱnnq 8gu~x- 73VhN'ep@fyd&NjjFv^)u\*QR~L$mHʎɔɤ;Sk))W Jp]]$Hې?qf 2;WH{84:ri:Yħt},7V4v]$bZD\Ө?YAX>tuF_nfLA#ԯJr<΢ BZȯ; tpAxپ/![0EXr;2_E}w2$U&8K#?h)*h%WG|7򉭄f`~ʘ ײK J^-j’u]b`dii^oHr.K;/7uJ\WMig7tUD}˂0$9T˳ `Oڷн kNqs:1P-%r;/<}qJѠ%8>"I| 6O?7](ArJJ2|bX:䯊Rхb?!֐JIwQ97+o]eD4go 򋒷]VoTR5]/U*Ə)Zi} DJc5bin%'{$pwUeSr.S}`y~&D򘧋 "hI6,{}YLZSଽA1 v"o'Bkfvئuh +Vh,W0Vb%_ӚxZT+: <|0mX;J~M(],-TӴ>#r:vbLV_,Wqv,&B]Mj` &˽Xd#ւiװqZחkդ35j]^X/SNܪbUS~Us.68I͕$d( Lv6PK+ؼl 6[ϧks݃W(ggig,6.],\&c!ٿy^/=ɟ>1ΛǙ VZ+QgAoO;F)Hg@"(\v+UCV3G8SF 9ZnΫ#.U@$mǮ$ʿof!̕1B[Tq1D+%"xh~&Ŧ.ybԲyT_%'Bh\ekC^*#/n'^,^d?d;kaYQ}X{$ϕg.#0al O}2 NJ'8ږIIŻoc< ־]~*)= yyƕ>z33oefڥFɰ`΃_܊ϭr}Y;ZNj6'l̘.`7`6o&xzMv!+.f=o:y0hQ{_. 9_b-STc UlG@˽}f?K~Jj3/6};ciM򲐐hcMTj}yBJZt_,- oGvd\ߌlMMS&o.Ժj}Zl5/3U%$l?b 腞1T>+0s%.00rp\-?llh>ڜHΥ )0@ lngP@ka|ȍ.qgnj"NU 4(ofgLKΗ,|GOGzF `D]ژk …Qs``S- : rYAU5--vI!xCC'Mo$*I9og)ܞuI9DZ1ۃӿܟVJvf+(Xն])_G62X-s7U?anEyp&&0ZEz7[/',U `s~o{AqPi$< |f BWf-s,aji9PQoe}|mG-W>VrG^&Hj{?(Z# `rϗ6UpmiH;׌R˜rcy(-Oiݮv#(~OuSSO.*2O}6ZQ]3u1X^?-A* |}AxQ*-wKҔdzD{<0%EAFU(7*O7 j~~ڲ[VWOjZշBgycL%ɦ7pu:?M ּܞ#r*7iW_Nnf7&G>CʴG.z?y\M|o;ڟ@[f$j7){ }6=6'7v{s=cc ?x9W-Fz}/nn{]͛9sځXhzRJP|~{A]@*^<'x*`]y=Nü?@|QR hwM69Oy_C^0qK~%Ma4,o ͍BD'n3 C~{FS;^z..=c ^\ž[9[NB$rSd;D_6kb5j#\ǘwwfhS?nуfbT{[zv{K?50`kdoCuF 6;ZG}o+t|qާp~Kc3,і5j30 ,*j 2o,IFOӼ\c+\Fҷff)\ߛfas`LөZcZ{|=eWulvUfGG/ &QMD5j>_)Vz#=ZplwtzR͈ ;ppYAkmrpUgqv\.S_~|0r{~eʄm_JSКLŪazы&n\4@ۛ0'kYb;WcW,g6\ޱ\6[ ҿd?eąK\>Bx#*(Ī hy+XX,#2x_zç4N9BM-J{xc#ڟHZ}Q{?=ԋJXI;_JQmƲb$ kEҺm?O{TouS֧"rK й,J?HS}CI&vK7icղ:ry%6ObxoyVfd*wvC :і|xq㇋RS%K"sSd]uZx3X$6mkyN<.UӦ6d%̙NC"BvGl lΟy]1@=aZtc Vɡz"zI8|DdĆ\2LG}.-V4T}L垮AG !jb%}͇SdFs"&+"i.œ]=v7*iwFngctt[-!# "fv|D65IH~Z~9yO$;n\Wc%*UZiN-ˉV5{k}! g&xXձ*[#i1}DNuJ\!`0'8. KPjYkVy:~Y9 ,FN70f5Z* IDATô U{+}Fh/~*SRjo֭ \VK3Tkd+^i_<o!ĺhF ¤fnEyp2qEeSp P7D5/ʸG9opN"e\e]jDBa7 WfX_6wh+ F];~V/Mc9tF ca -?‡E"ٓn80bLu]D._& /Z1k[2Eu=ƴq"@1"d$ȭӁ,k;;. ȦJl\ͯlp 0ٸiq3{0R)n W~<ڱ%f*]f25Z*3Om޹N̈́c=DKt A`|^˫2<U|wܱb0ZvxO# U:1#l'8h7ڔ6R>T{r}o,?t܆~:l]fLNd<$!a3$yI#f@ܰE\\-D*m֟V }ɇNp Ƿ+a#>a+Qq!c}oDfYwgf )FL5>4Ja/nʳ{N h$mQ+J`E;i|x-w&҇Q`wR#CAtF{j[bRL<{~+H~93w%.[UDT੦JlDXju`?h?EUyx} }nU׷|'\%1.VyT^g0ScB;ĸ*K\w^<DF|Bt:&8~K1Kp񺘚>ɢ-+i}-<?@[տ:ͬ2qe5b6I1If`4!38aBHWû[^ܬ#q< LUw#$L.vfP{IiC/{",ʈu̵ vv>4D](t:b'5fJXQِt]j*2zTAFw5~?804IyTt'ǕǽZ+eQ2n#?|f6)aQB$ u:>ßAY0[,2~N nqc=A`;0E։$] K-rRe&c"iͨU e[ A㑌5t8%Тo%e1gЭo9CNO.KtT-F.q3O^^RYF ˆBoOyv%zPs<] ^[ 9^D:r\&:;'2 ]ɮg6Ez' ,u8\`NUٚY=!8JěR-.xŵf'uVK*nާ5ڇf811u:f.'^E5fP0ʹcHWXZsN&R]HS慈-v g;j&ECu#4 ԬΩ=| JZ&[Ihxmv8afIbzѯfy8񑿴ҪF W'~W$K5 knAAsF)Fݕh4ƓS{|C4qZ,\ջ }EU4B,R_ :r. L Uulm:Ab\M4ffItDKI2{,ܮ i 3kFԢ V"՚dT|U L Uh$R;iS ?TaGcN>BT."VM[ V'*8.ߩ,tC@pgTr upedʘ ZBɴVX~a*TSV*Tw(Jz\:3ml0-/6Zq )&$v4m(EԄ)HiZsn-J' j(!KM1Eo1a*_ k[A|asWT꾳UBe4s(r`.725Z u ]_şwZӔ錋 .WғpJT :z\VS[~nT,. jBpm]:z J=T]:j;IJG6k`{ i}8_ yV3ճRaXXufHb]^^^ _v P֡fTcuL/|\y>q| < bN^DoʭTÊi7#X]Pج"ie:N={r1I sքT^MhJ >QJQ;۷k8$Q]* "X&fGDݤbaxHS[b\&v'hrR;o,JM`HybdEk~um ˉ 8'[v_kZDZSJJU d|Ra3yR&Uƪ('}ȕwxNq4znq:D \ݿW+Q\ԕ,܆A-FeMӥ$i Q6;Ro߼VyYH; :}cg$uJ&;龻^ѶT+X3?Am>цZ褥gxK9mMyxep ^ZR_Qq9lb_cMFqKw 00:ܚD:lmftOCi(yXEө4kF){(^1`#-`.͖>M4>V UǦ8dH[oٟX:\5HWݱ_1B\2K -5{̬" ۱"?v4XpdY䤜D$LrƟx>N*GrjZ\:{efmuˈn.,Bxڌp,3~{|vd\YK"9 Z ?7$mĴz5+Y}$=eT4bfP"^BWBLZOWb?-ύQgvi4 3MfY'FPv&5=}GI{˂%=R\ {[K,/&WE#Żnu9fFuE ~&M\Jh `1''Ю83AOY4}YI{_NSF˘7}YO>aQZeմX((a0A?bKH,uGfʦ,Junvo ;iv "*R/fNa,\8KKZXsg?$҅tvn3堉)mDM(K @]jptajL_FάP8Ol4}D 1, n@˚Agd˂WxM۔7=3ݻ7=3G*jZ jId,o=.{vƖ0rRt8C S&LL&"5UGiQZ^Ų}Iiſ h9h>kT*޻oң hޡ\'p(BO }+iS;l<)l6vc;IO+tA=K, Z#4[Z,+3LFVVi';uu{ wl @8~~}dTW4ց?P^Ju: B#wQxcsC_oڹ7zdBxxOMw\{%Z.b V[S^pT t|AJB :N\0^O3">=q(m `KNf|3o~Y!ySotK?0vXlN6Yl{8;QK?>͗{ѯ0]2ӻN@{>t*{yRxGDf&;sW@m/=^>k>m~X@ú.| $Ro!%mIgpKiEPtt4#5urr͎n 15Z V6%XXǮ7!WpX4`1}˯5w+PQT۝.!=Cbn|_hodi |`Ǣ"kbw\{^|k^^W_3gp͢.l{t.Bs+9{>FODAt[b%gx(u?o,&jX ;pk%=-Ao㗏_!%:{Eq !VW|S^AZsyjׯG(_~.q^2/ lF`^ [8 rmn XM'߽wkщṟl!nlǙq=^~J-bs^ ًbŐ,Y|o/~ȷO_)O7޻=aT/ڕ <*V0rgd-(קE%8~/;WC{y^6lAz$ҌVDܰ-,Jl+RGoHr}w~ext}ogcJvYЭzĊccQC=z?%Hi/>:^]H wP;NU\ciRuA2E4.WȚg k4{)diS$XSY} ¢^q:*'/pA,>H[p8IZQ,xjs?z' {_z55ҖܽEѵ?ʎtKl#K) XG#BKO%[]ឦ^]+-hٸⰘzǿ\ SLb)^LO;H?S:>Pe#cޚ'b_o᜵wҿ;D.NZvW8^!7<ˏwǎlJ `C UI5(]O)[)kW|Jc=%Bknf\/e2$Y,Wp,.Bf#DSo,Ԑ7 uKpD$BiْYZ2#1΢ӎ. Xc3@L(*TCoMkd!OA5dm?^Jb_ϐ-URDд M6   lSRY2lfړ>6},iSq:qTHϚ,]e ݝɈN矿FBY$TuB*|@1 *cݒ$;ۓ9#D3Iu˧Ȓ@ψ8cNq:Zdତ4K*#Bv ȥ%֢MYB6HRU{O9HȲy|U,o{ᜱ3g-;~B}K [' Qbݶ;? ԲSggt.48AUNƏD$lPDR ht( Z.mX^_ #`gkY"dˌ4]2bZΈjUF3i.+s$Rkq5:4U+(~ad`}d$k8!9 %/ 4C72xØ3Tψ979CSCH pfO<q#8Oؖ^{>ׄ-˿:\en!@)HU#6KH-\;{U5CFOVY*IE}s'SC}ß;fB@!^/"Iܬ_(}{|:)[@bfs?< q7\n#dD2D"]i^sFx23|?웟ߓBIE:&x-dZMתTIyae(kU׹8!Jp3| άxOVY{u=}qD|Y!j뵱@B[,]Y4uqM.HoFq=h ౾Uΐ V?@"Ń>Þ?yvqyRۃAT!p~ gk\~ʟ;4TUK > AADS` ןZ,Z;-],㯕˭Ҵ,5ة4 df n[]Tr NCԏ%sl$ q#\ݠ7O"ףdRTj|s찁%pMk ~yg B'+*ja3,UVe(v9,.pzM S ئ :Vs,drx̧#9C /~2X=/LѼ0U>d 7M5{[=_G +ނpO¡kSȱQ6^Zj.7OB?kÃ)ƹq?M.$aXwks,x ł3X~ L,D 8s@&{*~Y0OaM+9&Pq!*O^AW9T YUCXcQu*yoc{czPuP- EԋQ}>W,U̾06̢56BeL a|!0Jj[б yl8dPx3+ PY50N˷II43t&!ʹã[71ȏ^+uGvXa6b`K20SEIKo0K&Z# UR&YFHdT-Ch ]v3 IDAT!^lɐ(m+vM]$& F;33cPkkrV2gDXKWjg:hqеdӐLN*7L&Ti}eT^!PDus?.lY{iR`BWClxЭ&$[&fGL3`B0A2{{O|[Nݪ(p:y {=ʰa͇^}`Q侵.įr;לF,u3pN;Y>j"K3Wƞ}5r S0lq*q U-s@l(j2eny0(IQ-2dH>+ۅW>;=襸刬>)K9ATSm㒞qȞS{ tr3SX$'b+H:V3'OrV:g[*o4V5O2$z[^De1چT ߀A|6-%n 3R0ql0"#2-cX`BgaynQVfb܍% p6Nl25) Z3i{S TG*pﲬJ ^i0"<$eᑇNuUSV$aR LpeTfYRcoBּ0^t38G^4n"_uY IJoMUV'XXXc5hȥ # !@iv4y+/9湂"+6:NU* C> `Y d, Ry2lF1yHsSZժѕȇ n*#|z>K_^#84kT7]4f.IB룵 -V= *0g:$R`; ~k@(}n+ZjN*Sz3LT`\ (PgT9_%`J&)-/q$2֝{g /,W7 V}ڕ[ ^p!TLHڦ@+ちQah٧R%!, w^݌"MRHU/֔?Z60$LbPcHʔ)b6y f\&5lw%Ga.iZңx )i3&7C}Xq$uu.3Hl F+Bn޹8py4cVm4㬙M&eu&wٝ"+LvU/݃4PmMNȳ߼\vuß:];XEgɈ\JDv#;}ۇ{]J4Y( {V=v»UC_\qꖱ'C*sk IÖ%3$YGeob~b b-S h# Y) h/F7=_5CN6TFT qT[QCEAldYR E^dilSK"sL \ 0"G9օ7>UAa6 "Zy}c1 27I|fEp:_fx fdO )ªbUK,c=[Eh|I_R@(թ\8u٪2[3; Z*>`Wz)qcZ%ķۂ [ãʘM*7DG¡h'm` 7,ϧ6L%ȿpi9gژPhYS\tg1mxS]Ob J:( ׂdu$V#Z"!eĨgIO5nkJ(n>- sQ׎AX+?ZR#0MwY5kx4U"-c"5m"F@ryup#YXwc4r9DӪPHdHlaRWJ4mp&60Ez`&&wm%3Xc΂$D LuVV(2"&T~ME!”KBaXXO9D5~cn|L~su&`x£XR)q*tu r3@FpN!NIakl8fAѻ}Gj' n։@@;^NꋺJU/wܿaf O1J{2Ʊ?D0bu9+enEuCG )$N7o*))rgiOH͑ nL+So\%#'`3Ձ{/mJŢ;iSY>;d(1Zփ|08r bMxF -j YH?,b/?7`V 'IAid씖<;hrJ̬&]iv7,f7тkư) }vr%3VV2d]*'\W.@$1nRr?vtd\ ){` qXC^0s&.JBkumH=O\)B<BT~c=]`![TX9컺v)ɱujH}Ks̈{W(L҃CId q|#h[OE*mqx-AQa;~A+&5P+1tJ edL`PKأ^a$/fFo3EXa_EGaUVưqdUc_ԲଦBiTwx4Ɏ;`ɾp( ZCk]FKMhƆ-')7؞<;wZfw@AcIENDB`perfbook_html/node344.html0000644000175000017500000001275711672746163015662 0ustar paulmckpaulmck D.2.2 Brief Overview of Classic RCU Implementation


D.2.2 Brief Overview of Classic RCU Implementation

The key concept behind the Classic RCU implementation is that Classic RCU read-side critical sections are confined to kernel code and are not permitted to block. This means that any time a given CPU is seen either blocking, in the idle loop, or exiting the kernel, we know that all RCU read-side critical sections that were previously running on that CPU must have completed. Such states are called ``quiescent states'', and after each CPU has passed through at least one quiescent state, the RCU grace period ends.

Figure: Flat Classic RCU State
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/FlatClassicRCU}}

Classic RCU's most important data structure is the rcu_ctrlblk structure, which contains the ->cpumask field, which contains one bit per CPU, as shown in Figure [*]. Each CPU's bit is set to one at the beginning of each grace period, and each CPU must clear its bit after it passes through a quiescent state. Because multiple CPUs might want to clear their bits concurrently, which would corrupt the ->cpumask field, a ->lock spinlock is used to protect ->cpumask, preventing any such corruption. Unfortunately, this spinlock can also suffer extreme contention if there are more than a few hundred CPUs, which might soon become quite common if multicore trends continue. Worse yet, the fact that all CPUs must clear their own bit means that CPUs are not permitted to sleep through a grace period, which limits Linux's ability to conserve power.

The next section lays out what we need from a new non-real-time RCU implementation.

Paul E. McKenney 2011-12-16
perfbook_html/node54.html0000644000175000017500000000565211672746161015572 0ustar paulmckpaulmck 6.2.1 Design

6.2.1 Design

Statistical counting is typically handled by providing a counter per thread (or CPU, when running in the kernel), so that each thread updates its own counter. The aggregate value of the counters is read out by simply summing up all of the threads' counters, relying on the commutative and associative properties of addition. This is an example of the Data Ownership pattern that will be introduced in Section [*].

Quick Quiz 6.11: But doesn't the fact that C's ``integers'' are limited in size complicate things? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/node91.html0000644000175000017500000000732311672746162015571 0ustar paulmckpaulmck 7.4.1 Reader/Writer Locking


7.4.1 Reader/Writer Locking

If synchronization overhead is negligible (for example, if the program uses coarse-grained parallelism), and if only a small fraction of the critical sections modify data, then allowing multiple readers to proceed in parallel can greatly increase scalability. Writers exclude both readers and each other. Figure [*] shows how the hash search might be implemented using reader-writer locking.

Figure: Reader-Writer-Locking Hash Table Search
\begin{figure}{ \scriptsize
\begin{verbatim}1 rwlock_t hash_lock;
2
3 struc...
...}
29 read_unlock(&hash_lock);
30 return 0;
31 }\end{verbatim}
}\end{figure}

Reader/writer locking is a simple instance of asymmetric locking. Snaman [ST87] describes a more ornate six-mode asymmetric locking design used in several clustered systems. Locking in general and reader-writer locking in particular is described extensively in Chapter [*].



Paul E. McKenney 2011-12-16
perfbook_html/img188.png0000644000175000017500000004143311672745762015334 0ustar paulmckpaulmckPNG  IHDR[<WPLTEb``^\\MJK# hffmkka__XUV856iffKHHC@@A>>wuv.*+~~`tRNS@f IDATx}*s˱r[,3y]N0e?e+K>W ,p0iōp̥wkuXdfy!ʬ[oD]:toq1~;VUXJ/eVH[_ş;B0=+7Y[֔ \~Q Doꂱ^ lq^}(Ico.+P Yk02 @G6n>g*kXW\7س$4,?Ζ9r'D8ڇeXK_0nj#7(%bUULȅW/H C; &볎 8.&j=NTWmoh }V/O@O9vkEV1Y_B[Ľ'K:3z1]R\aCз3G"bg4 8}w󌛪Zފ\1(-t/ױ̚*NǁhpfyV+pd1`{E5~컪RwSrY5/FYP6Y -ߘKe؈ZT9ieK4ϰus9m; 3 ԁduj$^@AzrwZ|N-pY&NCL33W&EkϭX-Xl)m|)L5Kjp&# $nCl.(x O,w DA.<rIc`lU]2©%Br*b~% Q+g\ >+G"WÃR0K21k~yMVp8O} !VuZDԆ |*ڈ5sfQGj{w9Ib%2 LMU\Jѳ=y+ǨF/(Ԥrv7aS%2YT [xz݈Q||I^䃭PYsn0X8`hdAtpxL>xށ<$ΙZx$%j 95}&X3%_=71C@X5-YWm+G} t_g%Lz3< o؄M Ph3p.q8Su,E 2՗t\;UA RtX1 (72&,D~K]2Cs8_ɼ(P|Ag|A;ÀLgT[` w-Npt<'QT5J;d'b <;iAz FoaLUjg̈́J#KJn;LwFt&#.kIRHfX$OPyAxϻƠ*goj #ЬWcUUg<(ҧYy}s9k=;&|XsJb[4v'S~耆c'{GAo9 o:"V98ߊnXKxZЇ Q``Vˀ)dQHUqVa8I͎[B\辅N~8@?!@@ dP\ 8:@-9">Ă-1}'f0N?ي20dm*=4>XS,*wmf؂̰<6{J}CPѵySҫGh6S?IJ8M/ K(jtmUnŵ4!TDCFk 1l^4p d>ou,VmK6=ݣD t8 /|dyJ$90&`i}FeFm\J !D> \AΘ <֪cm Aw%>9Lſܙ1S xe%+H s*d:^ĞQm,xlUPwOuD~ 2$%ucU.!jS1mHd|p }|b)c[YK@4N/@4˲;x%)KԟM\`yz/" =kH8@"m OdU-wׅ4.?Aln;MP|3%5#DZ ޲Xή~*©>G灉`"Mhf=gU{ǘn8xAfq1*&QIqph Wl4Y#w]ujTyY-E/adh l K/ӿni&=9/.Zna1/&PqVm0Iw993f1 Yua$Oe{gs~][F<F*,W/PZBe!gaZkm:~ wYj*z[u@N=(]c8誶EC-t@UK$ʇffn?"cԚYiyi8c#e~o⛒ 3[ x\ LPbXC4]pjcss>YnXMﺒzяhuJOCCi<1ʋ!+wFGs*yN0Lb\?9r z0s<`vUi6<{A?w)n_81\jo8F)e D%#fzog6 ()T# <GS$+7!_p9 >H[XT?mK#Yqo@]!.Z&-å>iC]s޸*zuY3׷LdD꿄 <vՎVs\(ѽZi;в\&'IUG^p3?%X'^WGkO6cl B/~FO>P=5h-Hb#=&,mc0Bs_ Z#gB{:wS6Т5jsSmGTE{Aj|JWv]w7yɧH2 Ϻw]NwTr/w`v4>Q8dnЉ?} @ȹmJmY1"1]a:YPt|ՙq6Z LYJIcJJW$MUJmBVQ,Uw P|#6BW+B-847_y*+cO.~DA\ɽ"UOvs5q҂Fq[mAw[)FS@D,<5w?ʋ{F;ۇm>}n>VE/<[‚3=E.raIT?۷6ђ-!$0`)?H*lg6~]_?g jd Sa'(X sϳlLeLEkq?Ug%3Hx݀\Pa3 o+08ZLCU?I[!G"6wvhޭD f2v : 뭛d3yf'Qi;eRޯ1> tC!]B^o0bO7L :^|kF\ eS`&9oVm.\Fi_zwO&o|MNWj(`@7s5la&\Mf jW\4 %{%q5+POx*|Hf0[yA#4OX0c&rQίD>>?Bg{ptU-1cґ__(VK5ޅ-4. <`ӉԶCֵ]!b}W'xώZ r5 םz 28!Pj2ڰ㨤%%s)#۸V5\d ^|ȍNO깈2GY1m3]#cy&"BRAscC#E-29h٠ +ㄸ&;jl W#1Ph`q\keyO'άX\gX h]Y^(=Zf @[&:Q#Xwʹmfo\e?ϭg ZhZ52rpK3u(~&Bre^+ɨ֕`\cn >HIN\^(PL.f|bijUc4N@&蒁iBJЄhvy;Hv&XI'HMD{lVK]9qқtV!R6rFsz +r٦tgtr&-e=W)P{%r7% .8%;2V;N;* + g IDATr\4O#ؖt|LfuЮvgBC$jo8 4l6Tt`=Qn(`2ʮӆ=|{bW|n[E3daM&Y?bamjѕ7^< s'8Y\]UNFY30 VgIda'F;NfT ozP43tf?~:Fk{o3;:?TLdT:q@lihrџQ|F} Ot :$,E>PalQ'$ZQgՊ\acԺpBW[ ;cD6Y@jkk ch]SN߀ 1(_!݌ *fE>gH ;H|Jҙ TMAHxW+7y첬+qd"E +\3/x״1'}s+7Z[㣸lpo!*.}&EeV;J#Vqm/ؠ^"C ,1cQS;(+j)`yGqCO5Ib5x[]v6i㨋wh=:/%$7 FTK8U[h87l:h9Gԡɨ%D?TOhPi:OncK?烮é P82c^FY&ұdA!ED.PRu}a7U+w,BAp{u 3}%쥖 % +P?G[߭IṌa#\e|wc OA2I>ixHN$7Kܺ'jhf_mk$܎Q֝%{bpɂu|[mk󠵚[?JpБ!ۤLhnn#ĒjP(`LCWI!:x x-;а1R (QlHxWtE6#82@ ` Hm7,쒼(Hu/hj!Fi=9hbN@pl%,;J+Џ.~*g-Bx>dA4qF\"Ɵ)oϱ?ͳ{EUFMQlQ6cE< .z~l:;nyL|% O@1& X·s[V[eX$Qy0<\4.%uEvf/D*:RO^q#$KE:Dǝ7ʌj]" @s"hi7έ'hD)0yffv!+ff,Vu/[hrN7Yjo=\0G .f?W]R`hE6]m QGqVa2C;B5:a`B썽MU.d}k8wSQ|?ؑg&v~<sF GPfcذfӾo4fA5מw¯Vv|J`nmn8ZzO1=t'x re Zv c%̕Aˎ#|̲$yF٠eǝۏYvaQ6hqD p Gu:)4gs̿Sll%2hnm<>)I?Hȿ|Q ke"Ҧdfz$jZz2Rr\C}J,WANWP@N\i@w/t?~+֎{ =SO=#lN+֧(1p7A=><%[VgrY;bi( p K𰥊xp=_8pcrl0erLbyr1:Bf˛kӉ8X&/b+v%wyl:b(*=X䕑Mggd!E)h$^8Y8˛kq4NK}OL^hGOMggh̖̮sIen|lvDyeXvPĩ*)ۣ]hL7\ܿG&{|-(Ķp/K\9BZGR:[Å62W]D#):j=Gva:(L S ꔲ-d+N)X )iŠ|0'+kў30MX^4a ѼU8LC`؈|@[PW% 5:ApU;ZUt3.MKI(I3>TK_`M^ Q HPLՒˑe 5yc~ b = JJ?C[;-iriއ&$u-|) :6:ZH-i`)1^Kԯ0 W`Y]ܛ|ƛ>OBZFHC WAB ѵ_JQ(p\ agI7to`haZS1} jcϻ-Qo/vIj*&lB&}+]||\-󄄇b<9ܝ=USN/Nheu\E8ޭֻiHzmX-~Gg$,ݬ{K`H Yduh_O@&eOK'>aP0K|W" 8O8JԼ ȅ?o N!M}eHBBBsta%oUM_J`lfR\@M#|`1&rPA~&$$|0k< R ˉQ,[Md(Y׺0с7^Eެݷ 0qB}acեa%;Egߒ <(ڰ";899N4z V&YE?Hsyߡ FN,*Kv7ZwLy*N`unӺ MHk$/mhVEbMf2(+@QFj mӡczݐg6@]ֽkePvF-5bjڔ6z ͥ!H65Qs}BJͬG6J:V1grpN^ھ LFW8̺FW11f=V 9&aŽgp=z}}8MAWcuj7m=zzj rY}b h΁ wdF(ZӮIXz[)YhӜCzD W@[sؖ,O4V`zӭbv Q9#w#{ 5B~1>dCjit S}H: OZ$]MBƒ|Bez0Mx>a<t2s6$>!!Iq:&hT$-t ,g.z>+@9Uj.R6\L3:臚{>ӏ}e2e|_I]&CPB=@] /-_+\FTAK3n-eSvHwWHm7CTA 3nͭΦVgŨeTQ_Ԅ}RªL M˃6!+]Z;z2",+x3[UIO( K{=a( mڲWxs[Oyqh;le];<ŤBOʴ)e1al{|ܴiG0rlh;lȲs: >'|)׏e7x)Kh=e^Xڙ=Ӛ!ow+0ݏ ImI'ҺK:\ lK1e¹DX VU h"EH8iRɰLCA>13[ s۱YE[r#S2a݆LCzcogҷwۋ˱#.b\/-쑧Ņ ]eof͐voո>Ι]͇L@&CާaѺϘHWvX~]ͯ&籠9Xσا1Z^9GͳĿmbWneOT1opZWpqzjgV[Fc"W ;]9a"'m:|. H|BB NUkXkl:g0ڃWqQ(3tx m:׎3鬛n=x_‰: Ӹ/b8Gqڦjqnֿu[E 'l/#f8a_a;iκaƍЙt6A=h" +p"Rzq*h\dIHffw[҅|[;'è>~% ʕ6KA) }HiP~' Nf27O.=:'lmT|Mv0$6$#! γ4kGB@L,/ʾdE#vL^{Rh>3'S11Qȵ<ӊޚ<BX9-zd[;֕ǁl:ZFG<$m:'S6HW[E)V7LN/?}DOdӉiiL~h$;t* M含y__dSjU'Lz]!m~XU˼:aT!Φ6N2E\ғO"'L q  6 @Eb11m >AGba+;Hu9NSq}J-Not})q^s' a8MdtIΥ]=I{֡m:E>,l2Ý$+6LAE6O9I`!ZFȩByvQ߀ɐ?4N#yʇHj;4 DCkidO4Kor;$aY](dm¯V΅(SxX|ڱCvdA אil==?O7EM |^-`kBy6)Nz#Pg;"2ΦBRN#:',N.pVwC\^s]9RG54+4~31,\k뙤5avPlHT(ʘP3~NSycř[j8)M չ'Q3(gnn A> %*j!\ Tkҍ0qcLHh|GS\z/tzK)Q~Y%wrjg]WDI&(wu (~,hfzo9HWvvAeސpm;t߆}nj ,s;چmvI͂wm m1"bɖjc4OZl32&gV4;a#a&-0WV%˒^ԟ1F28n Zunw @s n1*5WVkPҽ<3+F6dЍ;e+p cU*.OrV7{xv3G4'pľS/dKYl`8LǼcFHG#t >{0PEmIt4 xsJ._yjӉ<=p> $;ud_t[%#A:'jϱ|3s+OTc¿!MEgn=aQ;#IgVљԁQ؛ LO%O:+&ecb4[{HrdY!&> 6 w㚆Fa_e  emMc\3dKS`̰ۻq4|U_7 vy ={MCH10whfNa&'x\ qE馋I^ .euYwE]MLcu!i.܊Y]v|u/l*o щX]R\رݫ ׅP" =ʂ8*VS˺M-ȉ[T0[|6[؅.f,3y Z X9'i@ɺtc0v":vNÌCRQ⠟]81ZF[Ť0BN}6T;I r|֙^naYжor7!>`xZr}BQ7m72̜*d蘝˟!":fgAcvtEs`Y0]oNnR*%^>a5<}߫#> Br:h6q7gg0whs䣪eaUkxPT)8ǺRYP[ ͤI %5Fw>ɥbNi̎l9F?ul94'K>ƚs:@͈_ʨr l?:n)N[|Rϟy[1;ptZֶ ى`j6 NN;}gbvb:c:KSf쎧hfshYmni$D9Vxt5ߞ$̠jhۈGCGBu]JI,:0o``wn 贪e` )_GDP-N>ȟP-yDz]|1c̤y]2 V2'41L5d\ -OGmu$>!$tεF m*-uzʩr(}]U&qaܛ4^6?[X+sKΩB-dcc?ޭ,0Mnl*?M!SsP``:V2n qn2igПϞ,4 etHݶdݖk ]MֱfIL.N/0nwIENDB`perfbook_html/node137.html0000644000175000017500000000562311672746162015653 0ustar paulmckpaulmck 10.3.2.1.3 Realtime Latency

10.3.2.1.3 Realtime Latency

Because RCU read-side primitives neither spin nor block, they offer excellent realtime latencies. In addition, as noted earlier, this means that they are immune to priority inversion involving the RCU read-side primitives and locks.

However, RCU is susceptible to more subtle priority-inversion scenarios, for example, a high-priority process blocked waiting for an RCU grace period to elapse can be blocked by low-priority RCU readers in -rt kernels. This can be solved by using RCU priority boosting [McK07d,GMTW08].



Paul E. McKenney 2011-12-16
perfbook_html/img255.png0000644000175000017500000002350011672746064015316 0ustar paulmckpaulmckPNG  IHDR\S5t]`PLTE^\\URSTRRMJK# b``vstmkkcaaa__XUVJGH856iffC@@A>>wuv.*+rppmjkڛ#ptRNS@f IDATx}&=qhO[6uAAhYf-v "bQT}UÈQP_t댄|UMݘ}WV.6Z!:Rh#]; R1pZ)ߚ>M9|VH{EzOQ}[WR&n:ã觛1MYLmu x";fh#&оOU]h*X ֦2E 焫:;cT-Rj+OXx|~\]kEՠl7f| ĀGUW(j??-Eɷi7iC$}~K砅0!Z7mK|ih߸^nĤ1_=Nn]p+a^T}D[8&aDj_ݳNV3 j)?tM%> X)[{ЛD+".l+BBkLC;Wh?֨RTBQw.ϺDCmXؒLƶ}.d MJ=bhv@ kԡ|b3-Yz Hv y-Su('G[%ܪp6ԴQCBֽ"xEڃ{P0Ϋ f]y6b}>նGKH$GC7b 7h $}'0?_3oedi~I/lQ^k &1Дk; C `j[hO~s dl7?)xVѿc?jV{֡:yh>DǛSBC7mOxn8k`^lz_z!Pp*黗>mk+ ''5߇wZúJ2׹Wc)QGQaky=zLpNzG\k`~> ]}TrP(84^:F0AzߤY+B6:nM$3x?fDK(o+(5L/ฒO/FJZJ3--mbhgJk""2R M\6ebtHq cߡr4Z8pOہf }hu/NB7 VC saE_y?2J]#DeQ{z4߰$.G3U_K:^p14A&Pq~;j{0z~ (pPY^z@jϩs<SIs^5$._,7,J!F;** @U,SRRL/(I{ Z' eF}L;4uKZV$HGuo. E̿fklИ^_oLA㗡N"t=oA򹅘b8;(O֗* G=ҁj*kǡu5eY>KMXʙ8o^s^EV5D,)_{"W54/ eS=Յ^EnGw0Ŋ8*b(t>Ku+ XzŦOi/Po"g%* 0 P6ZdC.kn Bi:jc`瑏Ft^g0-Në[av  q/6dqBsa⮺II aEfNQ`VacѺ=3rK TT)Wijwѕ4ƒ͑uq#'{JC`)ISlqp$WFP6@ %~jOn^g֚+!縯! L Ĕ4RF"%!qEPv4Bt.[yRF[k3Ư!cQ J^|S ȸTOpnlbwKv)A[ ю]2.GBW(~Ibq %"#}wE,`9ҊDI>N}78yMײ6إϭ!ogmϢ;0S7=%|BӒ5L7M (iPu+y=snunMduJM@ >%}EhqoJ (E 3&- p)V/=*B {_JyMx{R.A%V 7X PvsEOW 4z?Iex'}S J7-K_?ORcOlHӍxPK\V .!R]+R'.& S ]k(hHJ>Tc1|cq/!zVbit'[lrI۠SCng~qN u(OLRB {Әk3+η^!rN= 8d7n0h m!O~NjAi AMnNS' &;z"SL33\ ( @Kd C:^_X!cߝ#`sH\URX.dX<4j c x>![ g\?èǡoQΤOѦPv&q=u n OM镅qhOɻ@~¸\<) ѥ*juer&`Ws~h=MR̡Z &CݫJf<`7]R?9FY;&1BM]k׹qH=VbJ1YPHl`{ƙTׄPK k5QкB)o~_ /t1= Y2ٺ~ .s/s!F 'Пb *Zt XN@G-OHy~b[!ס8٥ 7fY`Ӷ!|(CNS7Udz  LÑGa"TƙA/qjEA}77TKɁ&22½ZY }YDҕ E`q X[^\MS/GpUznd&*X Ml+0 ]G5 dDvc`]0{㺴T]U4;4p] fPDB1 EhǁhI.Q~ Es?pIHbHM7ECXrzbP]u,~i8xhȜO1U*W&LXeC&jX`2IJ.G<cҐ."c%ϋ NYA`Psr] ?,ti qNu:O;;3F|QY~} +O0^cH0J WHO.4| =;kאKsvVAFyݮۺKp7΄K]ڕ:yْ㘚hgkZsy=.w^C5-w)35jGry=,Rw^{ jϐjߥB9QW95zssr?6r6o6 z)e'7$~crL~lvYB,74G\ fR/JGMoh\( {`G,PU~+}1?˧ :ʳPf4ǏJD0`\M W0 e #%;d9#VPSPʝ5nf-4BE~M"f$&VafRCϖ؎0Oef&He3g,3>t-\&[oWq-ah- дUݿxgqc@¹;M(uL*Jҫ5^E\%~ﴊkש=r-ml]xۘ?u3@82O1QU:SpF~y`$?aƼ>Teͻ;AXj&M$֏T2 4x44OVhiH a(&0Fp4@V_e =62!K8cV{DKf^[-7R|hH'\SI07ddTܺɽ'?4qI&EQxNw1M i4/8L#6/b Hc?3yKRҶAqi!a1&ϸRbG{H=?JkBdǥŠ۔9=O}NF!Dv\Z@HK:sh#=XCѩ*W q]BK H7@k-\a4~G|'jHv^$A0%nZ ㆝O V?fj |xWߘ"n\ woP8 r'j<\rvn7n<Ƿ,~H/(RryVelDYc֐9@uPIj퉗XE?y=! Y knA 7SaǗBm&ވDQ?N`f;fE,M||j(:.i~لeRp)j[i$LBbQR" =\-y6a"[/Lz#jփo0vGDzPt9oI,[БJUHfօC!MXWG؍Vn)VbY6Ey`nʹ-7Z/j uT׹c:~3F:'%k֊Iis8vv<$l~'(!jl& I'*KVtU(ѹeNùdcHDsaDᙲrø-J3=GJ}#Y3A)jeGa}Ea6]5+xX&}r +9ĉ84\sTIWRfxm XݮݖCNKR.XjZ?z,(RBP&^io{n@Žru?Qu; qYl5÷BSϷTr&@Úߴɒ Q h` 7h m 9Dv2i 314Cf`}@lh`h6d m 칉 8æ6EuWSfڽn&Úh^]nHH0wסбp7RF}^7nNh闷z'n[݈v vt @fv,#="b\H' (2nݲ\` A %ĭq_ؑa.b^wBy1F#$bϬrgWP6 W!nnSZJS @19RFu=.Bf5.VYܩC_reHro蹯!vlrd A!XwI{>Ca5㜾'2EQRM,7G#f-Ăeʫ tٔ Q\v 9Ie0c B$l{z3sіam/[93W«5@}jʴ  7;Ae,32m2R\v#dlbmDMGU avuCL95( 9J,X2Õqac+nͣꇤ[p d{z3sv:2nOI#{S3X&އt{RN+OcP3_;:GgD=!6܈!㇓T] P%|(Wqo|/ YݚN`6*l~5PlxtMgGRls{ go{@blI8Vf^.N71ͪ7nd^X/AOILdՒ?髇=72̜)A8_žȱBlذ~ҷb=4s2?Nj @JRC`L)`Es9sRli`LRs8CnN‡H!BcXKhuɞL&\rkq?pKIPI7T=vxD,Fe[?Ie.&q{. PQn_K Rܸ`^}.Dž属u~NKy٢Er2&q{ιsQrO]L X8иP^aals\fnGT+Xwi%~ןr\UIDATNvZqT! hEڟ,<8ߌ8&Ч1fk焰SHoO_y $|%psS$7p}o~nRv޸g@\%nf. 71bum )~/eY˟;"fY16`!0y9ÌU72s dύ1hcƺ`!ᄎ73U̙Qg9Snύ5`xje}j,'_s?&`^*eMoՇߔ؟x6D&,%@Ǫn[XňCt2IB[I:IO4db4ª@LFtH]q00cv6οOim!U vze-ѫx}n7nͣ6Gh j++1]izk x,؈.Kցz3ÝƍQH޵WߙjE2}ڸ6]hNn`*bƍSG,F59II4q4K_SԇSG,[&SoSϢwSr ML#Կ9*p69 [%~0]ۖ X(z7>Bp@s~ӵ̟,{Vv)3bo94ZIyœՓC؎W% rMf|P7=J3†œՓ0 .ZɣCN֊><[Hy'.-%f/8Y*Y\kuAݟULZwꕷ@|ܛp˟{^yhs{+7nEfWTjv$Xyydɟ˶dg%h;\*u*wiAF#̗9y\0d璵$6vB8.}Ǘ4n~8k m/G;_&d#NBJĘeAsk ;0f`F ='a~ $jcx0GљL4"N=-!)BC"tY^ N:|KBI0ڙV6惂-бgbp8<-?"c2JĘ%FͪB;I#asR=owZgDy1 Yۼ' c~ 9&`~.LwJ0u|-Ay}/dn) f⠛očK1;..a\sR?t42ӹh A7v (8&t%Ip*46!׎.08&սkn 7i;A8:⮓o1sdS"7O*{ EX! 0c  Y^,@R̔}Hx@6n c{%IENDB`perfbook_html/img196.png0000644000175000017500000000600211672746046015320 0ustar paulmckpaulmckPNG  IHDRV$W0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@f IDATx͝ϏGkڞrв` R({ B" *٦!qXJrK@\pF!V܆@"/A(?W^Mnٻ3]>]]]]gV!5"^^-?ߤMX* {Ko4o6Iѿ@jFC51IhL Ւ&{ |"-U3*o[G`Ȭ#4[u=0jo<FOhy#Fb=Üu`"Z,X0ts=J9#ΧEp@$2 ru&s'DRUAJҨ󱼰9j22 y1)wfvo);3sMW1$,[U#EZ; }D2e;EB}!΍<,z/V׌XȔ8I !M%vͰVU˜dx4Y,/^ϷaҢKDz9jď(#}=HtOFD2}fg;Ip>![h)EW4cDp $,2DM5?fTlGI%nK*DUڊUBWo_dN!!21 E ̀Q_9Ḩ[A|[` }WP׎g/\'@Wh7+k:_~* 19M I(@BL Wh Uc^cCs9u5쾇 2Ӡ I{lCŽ">z d$PFM:RՎ]Cz\;*nvJ1 i%hW=%!<;Ygr$P_ a[cIP %dI0, •rw/De.olRpkN-V3"%GOMBy#R!]ev$6R_EQsd,GaqnW91ΔBTjȅݥuړr8ۉ-„z1.;RpA(vJ ~B Ҽ2!x qajUS P)0@ [?ER` g@ <m!:Tl%!1AuK:g2 KNafn2 jޯ}yNK\5ܗ:99wH5"P CTP !"dJh% T ADV TQb-)Sh"H?Y+:/pJ)0 I4B!"8BtLYm (LnIX~qkWk>(48d V8nw[W~n!켺 ÷,$\dΓv_m͐M@d' @"!d2Y D*Bd  t DtBVa׀B*H@n 3b200> e9 q#2r h |B@aG 3&§@xO3Dc"}e"<98 \ۆA`12z: H#d0$J )r$Ca >S "hw?  #` EP0l Q`%)CX=A!0AFdAa,AK aLAyu !!G$js 66G'>"@1 $ھD ڿ&75B FAhG/EhB?v{?#Cx̯i(KFȏ8i>êaIENDB`perfbook_html/img207.png0000644000175000017500000000024711672746133015313 0ustar paulmckpaulmckPNG  IHDR;iEmPLTE# MJKmkkC@@.*+$4tRNS@f=IDATHcH`>( V ,0 @ey` '0y%C( j׼Bq~IENDB`perfbook_html/node372.html0000644000175000017500000001772311672746163015661 0ustar paulmckpaulmck D.3.2.3 rcu_check_callbacks()


D.3.2.3 rcu_check_callbacks()

Figure: rcu_check_callbacks() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int __rcu_pending(struct...
...(cpu);
44 }
45 raise_softirq(RCU_SOFTIRQ);
46 }\end{verbatim}
}\end{figure}

Figure [*] shows the code that is called from the scheduling-clock interrupt handler once per jiffy from each CPU. The rcu_pending() function (which is a wrapper for __rcu_pending()) is invoked, and if it returns non-zero, then rcu_check_callbacks() is invoked. (Note that there is some thought being given to merging rcu_pending() into rcu_check_callbacks().)

Starting with __rcu_pending(), line 4 counts this call to rcu_pending() for use in deciding when to force quiescent states. Line 6 invokes check_cpu_stall() in order to report on CPUs that are spinning in the kernel, or perhaps that have hardware problems, if CONFIG_RCU_CPU_STALL_DETECTOR is selected. Lines 7-23 perform a series of checks, returning non-zero if RCU needs the current CPU to do something. Line 7 checks to see if the current CPU owes RCU a quiescent state for the current grace period, line 9 invokes cpu_has_callbacks_ready_to_invoke() to see if the current CPU has callbacks whose grace period has ended, thus being ready to invoke, line 11 invokes cpu_needs_another_gp() to see if the current CPU has callbacks that need another RCU grace period to elapse, line 13 checks to see if the current grace period has ended, line 15 checks to see if a new grace period has started, and, finally, lines 17-22 check to see if it is time to attempt to force holdout CPUs to pass through a quiescent state. This latter check breaks down as follows: (1) lines 17-18 check to see if there is a grace period in progress, and, if so, lines 19-22 check to see if sufficient jiffies (lines 19-20) or calls to rcu_pending() (lines 21-22) have elapsed that force_quiescent_state() should be invoked. If none of the checks in the series triggers, then line 24 returns zero, indicating that rcu_check_callbacks() need not be invoked.

Lines 27-33 show rcu_pending(), which simply invokes __rcu_pending() twice, once for ``rcu'' and again for ``rcu_bh''.

Quick Quiz D.29: Given that rcu_pending() is always called twice on lines 29-32 of Figure [*], shouldn't there be some way to combine the checks of the two structures? End Quick Quiz

Lines 35-48 show rcu_check_callbacks(), which checks to see if the scheduling-clock interrupt interrupted an extended quiescent state, and then initiates RCU's softirq processing (rcu_process_callbacks()). Lines 37-41 perform this check for ``rcu'', while lines 42-43 perform the check for ``rcu_bh''.

Lines 37-39 check to see if the scheduling clock interrupt came from user-mode execution (line 37) or directly from the idle loop (line 38's idle_cpu() invocation) with no intervening levels of interrupt (the remainder of line 38 and all of line 39). If this check succeeds, so that the scheduling clock interrupt did come from an extended quiescent state, then because any quiescent state for ``rcu'' is also a quiescent state for ``rcu_bh'', lines 40 and 41 report the quiescent state for both flavors of RCU.

Similarly for ``rcu_bh'', line 42 checks to see if the scheduling-clock interrupt came from a region of code with softirqs enabled, and, if so line 43 reports the quiescent state for ``rcu_bh'' only.

Quick Quiz D.30: Shouldn't line 42 of Figure [*] also check for in_hardirq()? End Quick Quiz

In either case, line 45 invokes an RCU softirq, which will result in rcu_process_callbacks() being called on this CPU at some future time (like when interrupts are re-enabled after exiting the scheduler-clock interrupt).

Paul E. McKenney 2011-12-16
perfbook_html/node228.html0000644000175000017500000001723311672746162015654 0ustar paulmckpaulmck 14.2.10.8 Read Memory Barriers vs. Load Speculation


14.2.10.8 Read Memory Barriers vs. Load Speculation

Many CPUs speculate with loads: that is, they see that they will need to load an item from memory, and they find a time where they're not using the bus for any other loads, and then do the load in advance -- even though they haven't actually got to that point in the instruction execution flow yet. Later on, this potentially permits the actual load instruction to complete immediately because the CPU already has the value on hand.

It may turn out that the CPU didn't actually need the value (perhaps because a branch circumvented the load) in which case it can discard the value or just cache it for later use. For example, consider the following:



CPU 1 CPU 2
LOAD B
DIVIDE
DIVIDE
LOAD A


On some CPUs, divide instructions can take a long time to complete, which means that CPU 2's bus might go idle during that time. CPU 2 might therefore speculatively load A before the divides complete. In the (hopefully) unlikely event of an exception from one of the dividees, this speculative load will have been wasted, but in the (again, hopefully) common case, overlapping the load with the divides will permit the load to complete more quickly, as illustrated by Figure [*].

Figure: Speculative Load
\includegraphics{advsync/SpeculativeLoad}

Placing a read barrier or a data dependency barrier just before the second load:



CPU 1 CPU 2
LOAD B
DIVIDE
DIVIDE
<read barrier>
LOAD A


will force any value speculatively obtained to be reconsidered to an extent dependent on the type of barrier used. If there was no change made to the speculated memory location, then the speculated value will just be used, as shown in Figure [*]. On the other hand, if there was an update or invalidation to A from some other CPU, then the speculation will be cancelled and the value of A will be reloaded, as shown in Figure [*].

Figure: Speculative Load and Barrier
\includegraphics{advsync/SpeculativeLoadBarrier}

Figure: Speculative Load Cancelled by Barrier
\includegraphics{advsync/SpeculativeLoadBarrierCancel}

Paul E. McKenney 2011-12-16
perfbook_html/node142.html0000644000175000017500000001735111672746162015650 0ustar paulmckpaulmck 10.3.2.2 RCU is a Restricted Reference-Counting Mechanism


10.3.2.2 RCU is a Restricted Reference-Counting Mechanism

Because grace periods are not allowed to complete while there is an RCU read-side critical section in progress, the RCU read-side primitives may be used as a restricted reference-counting mechanism. For example, consider the following code fragment:



  1 rcu_read_lock();  /* acquire reference. */
  2 p = rcu_dereference(head);
  3 /* do something with p. */
  4 rcu_read_unlock();  /* release reference. */


The rcu_read_lock() primitive can be thought of as acquiring a reference to p, because a grace period starting after the rcu_dereference() assigns to p cannot possibly end until after we reach the matching rcu_read_unlock(). This reference-counting scheme is restricted in that we are not allowed to block in RCU read-side critical sections, nor are we permitted to hand off an RCU read-side critical section from one task to another.

Regardless of these restrictions, the following code can safely delete p:



  1 spin_lock(&mylock);
  2 p = head;
  3 rcu_assign_pointer(head, NULL);
  4 spin_unlock(&mylock);
  5 /* Wait for all references to be released. */
  6 synchronize_rcu();
  7 kfree(p);


The assignment to head prevents any future references to p from being acquired, and the synchronize_rcu() waits for any previously acquired references to be released.

Quick Quiz 10.15: But wait! This is exactly the same code that might be used when thinking of RCU as a replacement for reader-writer locking! What gives? End Quick Quiz

Of course, RCU can also be combined with traditional reference counting, as has been discussed on LKML and as summarized in Section [*].

Figure: Performance of RCU vs. Reference Counting
\resizebox{3in}{!}{\includegraphics{defer/refRCUperfPREEMPT}}

But why bother? Again, part of the answer is performance, as shown in Figure [*], again showing data taken on a 16-CPU 3GHz Intel x86 system.

Quick Quiz 10.16: Why the dip in refcnt overhead near 6 CPUs? End Quick Quiz

Figure: Response Time of RCU vs. Reference Counting
\resizebox{3in}{!}{\includegraphics{defer/refRCUperfwtPREEMPT}}

And, as with reader-writer locking, the performance advantages of RCU are most pronounced for short-duration critical sections, as shown Figure [*] for a 16-CPU system. In addition, as with reader-writer locking, many system calls (and thus any RCU read-side critical sections that they contain) complete in a few microseconds.

However, the restrictions that go with RCU can be quite onerous. For example, in many cases, the prohibition against sleeping while in an RCU read-side critical section would defeat the entire purpose. The next section looks at ways of addressing this problem, while also reducing the complexity of traditional reference counting, at least in some cases.

Paul E. McKenney 2011-12-16
perfbook_html/node285.html0000644000175000017500000001014311672746162015650 0ustar paulmckpaulmck B.4 Per-Thread Variables


B.4 Per-Thread Variables

Figure [*] shows the per-thread-variable API. This API provides the per-thread equivalent of global variables. Although this API is, strictly speaking, not necessary, it can greatly simply coding.

Figure: Per-Thread-Variable API
\begin{figure}{ \scriptsize
\begin{verbatim}DEFINE_PER_THREAD(type, name)
DECL...
...d)
__get_thread_var(name)
init_per_thread(name, v)\end{verbatim}
}\end{figure}

Quick Quiz B.3: How could you work around the lack of a per-thread-variable API on systems that do not provide it? End Quick Quiz



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node321.html0000644000175000017500000001615511672746163015651 0ustar paulmckpaulmck C.7.7 SPARC RMO, PSO, and TSO

C.7.7 SPARC RMO, PSO, and TSO

Solaris on SPARC uses TSO (total-store order), as does Linux when built for the ``sparc'' 32-bit architecture. However, a 64-bit Linux kernel (the ``sparc64'' architecture) runs SPARC in RMO (relaxed-memory order) mode [SPA94]. The SPARC architecture also offers an intermediate PSO (partial store order). Any program that runs in RMO will also run in either PSO or TSO, and similarly, a program that runs in PSO will also run in TSO. Moving a shared-memory parallel program in the other direction may require careful insertion of memory barriers, although, as noted earlier, programs that make standard use of synchronization primitives need not worry about memory barriers.

SPARC has a very flexible memory-barrier instruction [SPA94] that permits fine-grained control of ordering:

  • StoreStore: order preceding stores before subsequent stores. (This option is used by the Linux smp_wmb() primitive.)
  • LoadStore: order preceding loads before subsequent stores.
  • StoreLoad: order preceding stores before subsequent loads.
  • LoadLoad: order preceding loads before subsequent loads. (This option is used by the Linux smp_rmb() primitive.)
  • Sync: fully complete all preceding operations before starting any subsequent operations.
  • MemIssue: complete preceding memory operations before subsequent memory operations, important for some instances of memory-mapped I/O.
  • Lookaside: same as MemIssue, but only applies to preceding stores and subsequent loads, and even then only for stores and loads that access the same memory location.

The Linux smp_mb() primitive uses the first four options together, as in membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad, thus fully ordering memory operations.

So, why is membar #MemIssue needed? Because a membar #StoreLoad could permit a subsequent load to get its value from a write buffer, which would be disastrous if the write was to an MMIO register that induced side effects on the value to be read. In contrast, membar #MemIssue would wait until the write buffers were flushed before permitting the loads to execute, thereby ensuring that the load actually gets its value from the MMIO register. Drivers could instead use membar #Sync, but the lighter-weight membar #MemIssue is preferred in cases where the additional function of the more-expensive membar #Sync are not required.

The membar #Lookaside is a lighter-weight version of membar #MemIssue, which is useful when writing to a given MMIO register affects the value that will next be read from that register. However, the heavier-weight membar #MemIssue must be used when a write to a given MMIO register affects the value that will next be read from some other MMIO register.

It is not clear why SPARC does not define wmb() to be membar #MemIssue and smb_wmb() to be membar #StoreStore, as the current definitions seem vulnerable to bugs in some drivers. It is quite possible that all the SPARC CPUs that Linux runs on implement a more conservative memory-ordering model than the architecture would permit.

SPARC requires a flush instruction be used between the time that an instruction is stored and executed [SPA94]. This is needed to flush any prior value for that location from the SPARC's instruction cache. Note that flush takes an address, and will flush only that address from the instruction cache. On SMP systems, all CPUs' caches are flushed, but there is no convenient way to determine when the off-CPU flushes complete, though there is a reference to an implementation note.

Paul E. McKenney 2011-12-16
perfbook_html/node268.html0000644000175000017500000002311511672746162015654 0ustar paulmckpaulmck B. Synchronization Primitives


B. Synchronization Primitives

All but the simplest parallel programs require synchronization primitives. This appendix gives a quick overview of a set of primitives based loosely on those in the Linux kernel.

Why Linux? Because it is one of the well-known, largest, and easily obtained bodies of parallel code available. We believe that reading code is, if anything, more important to learning than is writing code, so by using examples similar to real code in the Linux kernel, we are enabling you to use Linux to continue your learning as you progress beyond the confines of this book.

Why based loosely rather than following the Linux kernel API exactly? First, the Linux API changes with time, so any attempt to track it exactly would likely end in total frustration for all involved. Second, many of the members of the Linux kernel API are specialized for use in a production-quality operating-system kernel. This specialization introduces complexities that, though absolutely necessary in the Linux kernel itself, are often more trouble than they are worth in the ``toy'' programs that we will be using to demonstrate SMP and realtime design principles and practices. For example, properly checking for error conditions such as memory exhaustion is a ``must'' in the Linux kernel, however, in ``toy'' programs it is perfectly acceptable to simply abort() the program, correct the problem, and rerun.

Finally, it should be possible to implement a trivial mapping layer between this API and most production-level APIs. A pthreads implementation is available (CodeSamples/api-pthreads/api-pthreads.h), and a Linux-kernel-module API would not be difficult to create.

Quick Quiz B.1: Give an example of a parallel program that could be written without synchronization primitives. End Quick Quiz

The following sections describe commonly used classes of synchronization primitives. @@@ More esoteric primitives will be introduced in later revision.

Section [*] covers organization/initialization primitives; Section [*] presents thread creation, destruction, and control primitives; Section [*] presents locking primitives; Section [*] presents per-thread and per-CPU variable primitives; and Section [*] gives an overview of the relative performance of the various primitives.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img153.png0000644000175000017500000002263111672746022015311 0ustar paulmckpaulmckPNG  IHDR(ԋEgEPLTEb``MJK# hffmkkXUVVST<9:856iffC@@wuv.*+WtRNS@f IDATx]ګ,E3sz:$ֶmYϻ[$$0G{eno08cc ml ~7xcUO I~ |t׳ >7_W \?k V@s(}8=]OGqPam} MkĬ^|> hKo:b:ܠFۗ@5g;iq<`a}ԫu{fPTApSn ]yCٹ5ס?O >ttBm+uק{i8Lx1>۸k_iUڷ==:po'rꍚc64R&R{Go ouz$v'"aRl2߬Gg7TXTwFI/DQkx3s~6+-LegI3Eվ/K}I_!nܢIB^xMVOC>y~[)DFBXK5#6n*N{SWzxD'2]UJE:E„SQzPT{5TMj Alj㔊'+sv2랗kL2%i +35}rm/n t-]8dBw2nnH/p uJ3g^ ŘRc<*]up9Mo l{S@9=Pӷ]MoÜ0NucEjT@Zp~ sT9gP5`ě>Ȅ5KhDf/AdA it.WVif>¥UϙywsA:>:m"kGD{ ~vϳJ/ڸmEg8' qZ??lk`~~\k?$nΪl]|Lx ay7j_Wp]4Xe|8diE:[p€=wcV-@RЮECA[jhqLPIg㽂BAoֱH'| ow}YePdDY^X ab-N [ MLtm>mnylf 12FJQZ| @LV r%u{GqЯnR}dZy3q<eQ p4Uq+Hx[EHpmZKIȏS:,܇9Z)?+ / zo>⧂Z.˥i1u~gŒ^>Լk^I7'I[>U'm߄B,gwKVp"o4yKnӯ<^ju0*aֻaCWJV=v-#C6Z굗6P^ hߗVPȦdlG I70p-Q`IF'&_ƓOT)O_g~ʭs+YbMgX*tvX0<E`)jU.KX>1{KN Gn2f$P Ͷ Uo)@%|`MIW(vҲE?m 5)V+.f9[ [a2y< !7 m C7L&!7 6eH@~7VTq5Rc }{P5%uPj,S%1GgqL-%nxP>o&ÓLGb9,ᜫe`'/bk*BK*iQԄz 2"s oW$ W@,TU+Be)\(zRjȎ'iޮƫBn%H- 'ۭպ ~A,694l={ICNQ[$xP.iud~LKHnOnRqiז- #}r5^TSISY͖N7y9\Q- Ǔr7輋CLtմ #f.b  NX,Ev@z9 ~`OÚys2rn\6T`[ ኱TMi|ZR}%d]Qf鉶BDyLeN0̸MT(븦V pwMԏ$JJe;Z =+)&>R1.]poph'&ŸRSeoV*Z]1r\ R۞C 'n|l_zKkKnϥ_~IyBR*S`~ݏO;,AIhM*t#*b~Ǡq|X!U/ *vt~*;GQ(&LE% .T2D1T/UIӗI{V 7"lT.lCWAC/|VL+F lE>b>8\#a1L ܄Ջ;HL#6q+O+5)C䘪FuE3Oa5aa]-_87Зk"<]jjAuwPb]I$7F.k¿ (6L"C\':&̳D. @NQɩbѰ6 ky#ifY eJjj-T+(͒FG::lS乩8OxJW? ")|jV;y2]g-c ڟEx %g) cYmw識Դ.3r =tXmQXJ(vb%Fg[ $\6tHVGXm= 68ABo֛a8 m" 2Oy+DF?e[gS@)BT'>͵0)!=l]oYK+oa%܋3n+i)JW(/`R+L+ǫªۥc.P^sT;,E ʽxfNtI3g.Ryw:.^T[Fd#.&J{ .Ih2+p+b9\!:!˵UBpXu+$m|:]U&УSקȋ"թ"2Ν*"@O]*"/:UIޗOy(S!1;\ﰭ)}w/ ^q7@I ^oTS%b[QinZG436(WOʽ&]@"upK}%2(ŭLC}y^0}jÌ~ڏ#( >pݹ*x<qw |6^Q9Nuu> lz޴ea+Y5q_3[FДrj|/N'+tmAyxl KN2,k={ޡ~uzvHFwV)|;&yp'޹;϶Eֲ{Ԏx:S:d[ADŽ7aiK XK2EM[M$/k b>Ҁ)h$&jњu U^EEEQtT"VBy3&MdDuXQ}6P1LHlWh3/1ފ'v&ͦTl{I eԟsoRAMu_aILλUT) .*bŬ;_.0-ICL#V /_+UzoakC }䞣WWr9ȩ].t;~lP*D8><:)*p9z٪i;hx$M+/9 5k;y QJ'k{Bx !mþ=LLOտlaUfʯ׳?S[#rN@|צEՖeO&5CEJkqdraWK _[ .E~NǕ:>JWf8/ݚ=!Y"dFrn42L$w-.*Fh=rQ&i+^%,@-bMw{Zʚm׎#*ȓѠxãXa+QjK VxWҺZJ.v[g=[I.ҵ_ TKԤ aK wtt5aj%mHJѰ. dB2mq'HW fu LLE!8^IYT>C_ i Ã%Kᄪ4&Y1#Bd (̜$2J򰗆9aH')i[YNc%Ps+J^jb/,^&c<&.2ܿ򰓆ׅaNvclsF3>`Ibbi10C%@AYF vY0# I7c:?N"{*д U(lG-j&"?BUp7TEVs &7C/)L)!4r3%𛋤6gl+ kW ŷ*\"PE <1- d:N㢁HC>OJ"Բ{x|դ7ضʕQ9NhrqR]d8cNht׫88F5Ƥ<|1z%]o奵ߖt!P D=ԔI8np3=~ Nx"2Y똌[.l-Swx8Qml 5]cY|PY@hkκ$P޵R 6ߊ.l.rTp:P6UQEBeל$Pl ˓! kQ±'"3}`ĊI q\_Jk )w0gn}u3;Vh^>:Cg)i1"~1{[U&J(f' Wb<D@[k^h:g5[5k`'H]h3?վDKoR7^sۄ5)m`=mVr >Pڊ1fΗG9cUrF.x lޒ&bw8ц ^X`t% |H0~c\ h)M6~ɟb-Fn+ *xSϹm4Cd|\v:`:,7%i&|wm "?,0b r䍒 oJ F1.B5r;=\Vb~i>i+D{?{1>]Ey:?^v D^5;忺l{5d+*7Cj|'{ФKf1эyg?c #2c}9j37W }Kċi}Ĺ; ?}|qe9T+B8sQ!4P(z"P()9P(Ïz"P(%U7rI  D`'J,c+2ϼ.s $NA| ?!*RQJ/]uGL #<'p08OAz{4 jIENDB`perfbook_html/node287.html0000644000175000017500000000460611672746162015661 0ustar paulmckpaulmck B.4.2 DECLARE_PER_THREAD()

B.4.2 DECLARE_PER_THREAD()

The DECLARE_PER_THREAD() primitive is a declaration in the C sense, as opposed to a definition. Thus, a DECLARE_PER_THREAD() primitive may be used to access a per-thread variable defined in some other file.



Paul E. McKenney 2011-12-16
perfbook_html/node157.html0000644000175000017500000002053611672746162015655 0ustar paulmckpaulmck 10.3.4.3 Simple Counter-Based RCU


10.3.4.3 Simple Counter-Based RCU

Figure: RCU Implementation Using Single Global Reference Counter
\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t rcu_refcnt;
2
3 stat...
...{
19 poll(NULL, 0, 10);
20 }
21 smp_mb();
22 }\end{verbatim}
}\end{figure}

A slightly more sophisticated RCU implementation is shown in Figure [*] (rcu_rcg.h and rcu_rcg.c). This implementation makes use of a global reference counter rcu_refcnt defined on line 1. The rcu_read_lock() primitive atomically increments this counter, then executes a memory barrier to ensure that the RCU read-side critical section is ordered after the atomic increment. Similarly, rcu_read_unlock() executes a memory barrier to confine the RCU read-side critical section, then atomically decrements the counter. The synchronize_rcu() primitive spins waiting for the reference counter to reach zero, surrounded by memory barriers. The poll() on line 19 merely provides pure delay, and from a pure RCU-semantics point of view could be omitted. Again, once synchronize_rcu() returns, all prior RCU read-side critical sections are guaranteed to have completed.

In happy contrast to the lock-based implementation shown in Section [*], this implementation allows parallel execution of RCU read-side critical sections. In happy contrast to the per-thread lock-based implementation shown in Section [*], it also allows them to be nested. In addition, the rcu_read_lock() primitive cannot possibly participate in deadlock cycles, as it never spins nor blocks.

Quick Quiz 10.39: But what if you hold a lock across a call to synchronize_rcu(), and then acquire that same lock within an RCU read-side critical section? End Quick Quiz

However, this implementations still has some serious shortcomings. First, the atomic operations in rcu_read_lock() and rcu_read_unlock() are still quite heavyweight, with read-side overhead ranging from about 100 nanoseconds on a single Power5 CPU up to almost 40 microseconds on a 64-CPU system. This means that the RCU read-side critical sections have to be extremely long in order to get any real read-side parallelism. On the other hand, in the absence of readers, grace periods elapse in about 40 nanoseconds, many orders of magnitude faster than production-quality implementations in the Linux kernel.

Quick Quiz 10.40: How can the grace period possibly elapse in 40 nanoseconds when synchronize_rcu() contains a 10-millisecond delay? End Quick Quiz

Second, if there are many concurrent rcu_read_lock() and rcu_read_unlock() operations, there will be extreme memory contention on rcu_refcnt, resulting in expensive cache misses. Both of these first two shortcomings largely defeat a major purpose of RCU, namely to provide low-overhead read-side synchronization primitives.

Finally, a large number of RCU readers with long read-side critical sections could prevent synchronize_rcu() from ever completing, as the global counter might never reach zero. This could result in starvation of RCU updates, which is of course unacceptable in production settings.

Quick Quiz 10.41: Why not simply make rcu_read_lock() wait when a concurrent synchronize_rcu() has been waiting too long in the RCU implementation in Figure [*]? Wouldn't that prevent synchronize_rcu() from starving? End Quick Quiz

Therefore, it is still hard to imagine this implementation being useful in a production setting, though it has a bit more potential than the lock-based mechanism, for example, as an RCU implementation suitable for a high-stress debugging environment. The next section describes a variation on the reference-counting scheme that is more favorable to writers.

Paul E. McKenney 2011-12-16
perfbook_html/img290.png0000644000175000017500000000613511672746147015324 0ustar paulmckpaulmckPNG  IHDR#,ȯ\cPLTEݧwwwqqqgggUUUMMM333''' tttfffZZZDDD@@@444"""tRNS@f IDATx]kc8/7‏1ĮAv>\sd5E/@yBhP@7(#/≢_)Jɨ\o\/iQ(.QGIFޏRTuQ݁**t)zVHsUT9ױ|.Yءj;M{ך6gi(.4y82B2 muA׮uF`/͔4=r}ДO+%(/L 8}tgxPA@ Ww:>Z@55&)K$DŽÚLY_@KdJO^P_W͔_ÖL$֙I9 dS2#[&<3e3cJO$ U3m~1^q)./P\{aSr|3z"YP Ww Pk*]:ҁ'Zy`y&LR& 2D;@ T5T0F{%&)i Liɟ:y-T,hlRӰ-yBmt<11?=BH&e>zc*Տ?W2I`$l2SɔdJ;)xӘ~Iu1e~!kZ3ɘIYjLL`='٫5 BVhrW:4ZLnL31I+CcXD8Bg͒L')b,9ij!n^Ҹ>G%$ ]DiXKں$]&jQ!.|v%]l.%"I/.)I(^0$rۡJRk$Ar{CY/.)ɸ$r띔&W.L 1t'. УTR$Jx)W<_TndPҡvhw+,KH"-S%ϒ[̡WȒX,Β(,Β(Xß nE=TQOq"I5JT~h$/h#`JRtwQK*ߠTkm#6I%~3,DKB9"ӥ\KBNߪN|_w+㎛.B#^La~-h8Arjm෉z@#rE=gW X">|=!GB{<ڞ"##\QN%M=S4أ8M=us (ALTT4dvE,/Dn%GE睈ɣ6Qtfh>T 8]s\=zT6;":Zf Њĉ]HEiYr4}f=;Nѱρ("-gBORQ*SllRcFT\e\gGX`p֣jUS"rS*ŧ( #)yWUy}D?=;sivhKEqG{zDXL!8ߨGtc i=j9}G+F^yGB>6QկkKi{ADώdҥӲG-i]U|H*͇ eGHDYB<$ҥk̫!ضQX~t)!<ڤOvfH&]JH,pdtPiee6ޯy!w/zQfQLB3Y8"G'ΣyH8E8"^=‹p{<‹pE8"^=‹p{<‹pE8"^=‹p{<‹pE8"^=‹p{#37R`}p3V׾PQR73$*!C~Jr|x4$1P rxCj=_Tx7Obʡ2p׀HG֣;~kCS!ӽR+.?`Q?<ꑘr 9#_տ;n=ꑘr 9H=o*8Liwߥ4ӣ'ɈW2(5c? GGA8bH'^?=`pG8#{=`pG8#Gh8I,9VX#̽p=Xf푕G :IENDB`perfbook_html/node12.html0000644000175000017500000000617111672746161015561 0ustar paulmckpaulmck 3.3.2 Make Use of Existing Parallel Software


3.3.2 Make Use of Existing Parallel Software

There is no longer any shortage of parallel software environments that can present a single-threaded programming environment, including relational databases, web-application servers, and map-reduce environments. For example, a common design provides a separate program for each user, each of which generates SQL that is run concurrently against a common relational database. The per-user programs are responsible only for the user interface, with the relational database taking full responsibility for the difficult issues surrounding parallelism and persistence.

Taking this approach often sacrifices some performance, at least when compared to carefully hand-coding a fully parallel application. However, such sacrifice is often justified given the great reduction in development effort required.



Paul E. McKenney 2011-12-16
perfbook_html/img228.png0000644000175000017500000001360511672746135015322 0ustar paulmckpaulmckPNG  IHDRW~PLTE"" DDff"̙3''ooݦ`HHD33U@@fMM33wZZUUwwhNNϜ2&&?//%hhffss}^^xxb]tRNS@fIDATx] 6Ns ]R[حݶkKFv4ֺÖ?(/ Y!gC^+P6WuV7.(MӉL]Qjvjuj[B_\W=J3-Yn.k2Qڝ,Cyiݞ^ CSXu۞)u;YU/6=Xa~>c&WP {PwoVS5^%nSKέ2WU_[t;?;VC=XN>KK P|u2Kz㵣%/)E%ٗ\rKs9ˊн6պ<\DG!~_}_җV}_#ETW0JMx00o瑩RO.Xz>IxJ!ƋT'}hc~R?>$>|R~דd Y5Vvhǒ5i¥ąCzk*P. vvPi/iV=7g}ޕV`)UVukjC5dyRkg|4i6pM>y,t!Ag!}8$e_r'cɪ !A}i5)E,XFv2f2d[Sv)[\NS-z-^GXMb(aGnXvе*[`{Tq%!onK]_{iRR29`b^_ SD{k+ Eu絏;(ĸYʛ3la[jqP6=~pɪY ;]WɁdەHajw> Oo(lgF iq Zf>7uv6ؙ5R qaRa7{) f5lwŚo)/n,+]2ʁ-+>MO@!)b %1pa dF[%?7 ۺt~F=jo;Qu=`;хJAJ*2tVi ~:.W]tf2۴ [bsXb `1+L0uh=xynal`XCpou%69ƃVLOn?V~dqJ }v}`{p€SAnp0l u`C6ub|eTeg8UݿYتuπ3k(`H~wD"E]/ Vl HaD\]idb9u~,ld{&Tñk֬Fv%-t!#d9j [߷-x'NE# 0d ֌RD`Nf:,Mv CVL2uvC]̉,s = cS36 KY}OkWYA-d \ڜ:BŚpY`@֢բBO:Uhd^s=F\UBIW`EɎ*#_=ٜx݆z͏zSqzC r<bɪW, ޹Ps?ְ{p4+F֘UZS]FI -*fFD#kdOv;*5=n$E`%3/XkՃΒEdQW|M~Ttrp0ܚF<[JΛM}-ַq]⛀dÐ|QeSׁ69,u} ;2 nrt`-͈{[ F02a6 (cda\b79񤫁FJ\5#;(~-*d3FJ4&o F\{ئ9M&ޔ,bO4Ƿ;yrיTZ\ 6'[F@֬79tS+?Xd$YcNݢS.7H Ji!.{pF&{ s!Tejux|e\8m)^K>Bcv0de}:g Y vrvZH2Q&B&b{x EN Jv;5$q dv9 U\Yܖ,<{d-jP69t79t' UZ69Ms|3jcJ߳69&F6mrF6D[/Fp@5n 5(=fX=V5݀9!n\)+{}jE\e("lq1Fڄ s{&F3!^2pxC{UFA-g{u`kp%TDz,)󅴵CDSv\'0 /kQQW7 e[Z8-*U$1gZnjۊpՎ)ւkķ!_#̮-7RQs%@yS$;~5pɈ`b\o~lkf6w$܉X5p|'*^-j\Տe51RR#\M\Dzޒ5,Sߋ* W WhcYoVբZX[}F}׫E"<֠բھڿST+bUX5x̱`5ߙwa W3pڻ+YM^"oUes ,K؃0eqM$I$I"/?s\v5$}A \`/1bH>}%sagFݸƚ#W;b$\-c;.b,Ce0 \!69W̕vzs$JȃB0Ӽ+x+WdO&\=.ފ렼wqV-\"}HqГpeƐLOZ aS"1-\ /ġ^ +!2LH&W/0N$I$q$R6H\CrYb/Xk64CCN\s{8uRnۃvo9pM=Rn.H=[Z-.~Ƀk3VL :ru>"Vn{9!|fp!?p1y3,pe s{XZ\䳸R\!|*r{)bULf'vjLЅ6wq[IGuY\c!~dt|1DI~#ɯv~WxܯOիVƯr~z(<ǧt(~E뤥D7  䇏Wxěv^ZGjP~r!iCmJ7ݐ~(ʿgǺ2۔Fͥ5&mrs^7Wwg5ufi}6~uD9kQzNEо'|JBVXn<4nŠ Um*&aDh]/\e7!az?AQbVk/(l 9Z4|*oHkI~#UėdBd$I$I$I$ɒGO0iG_HkyP~z~z2{<_񽝨k `~u{;QF?7QF?7hEaiz]@[z|H2(@a8ɯm'H͌Wo{_m 3,5?Ưvh-ׁ3ٖ湸kƚƦ5v_i^H^J$B@\_p4~DΗ@ԹwT'յO@zoC*mFp368{%MEk+O#WJwU~XkFѮWw~y5ܯ5(;x+{<>d|(>~ D7L^F?7QF?7̍3h?wO8n_Z^Q_.K#q}^zB noMOvWK K |=nַmlfLQů-k K]gR>P:Dչ.~%boϴNd=JE'!q~uܔIn~u"%գv7m;%ދB7˸nʗqsL2R Xv6c-|r͕S͜_]Qw|U#r>x7i3/~h!qʕKB'#ڿRh%L+(1[1覼15_[<^ې8G_H/?t#DIENDB`perfbook_html/img97.png0000644000175000017500000002326511672746045015251 0ustar paulmckpaulmckPNG  IHDR;stRNSىH IDATx흻L4* @ 2 5/>{9Kե[o  EA`b5_T /jH;>68E$øFXZd%O 8((*k,͐.(2>,bRU 丮` BIj])kpr3{O5U`͸@歪=ZV7Њ(c΢K`ɖ71f5TauNĠ 9N7CvkK3(xZ㕮`ĉteA8xcg,6WwuxdŜװopg0)y^#'~% "=UAQখWYKğzq$Q35C%&W[8uhCZy% o=ZS0$\F"Su5!nB3S隃d2XJ;c5Մ*:"4S fRXٓ& Mo%x0Q$=X\cE B DZl9`xШf5R:#FRsI%0S2FW+~WspC ;㪖Ɂ9^”smݭ 0˽ӹ*~zB2]wz*w"zc&z"O0;&XZ3WXp(RR{4T5^ ș*XԊZ#"H+8?nd/**M!$ Ҫ=`60^箳(5ꜤŠeXd!%wW&WSHUN!#Ii0or9TQi2aʼ\'pnn7KTInpgM0Y˔Qp{ÛֶuA'kzim{ibMUWj<=nnpV=;Eg'P9Xbx yZøUh./€e!˒wDR8y{Q۰U`oLhQlnBנ4H Ьpie{iv󬊍!]o przyEQqq5ieI `e2? qҴi]Yb&IGdKpEågXQ>i<^>Lv{^-+ YwwW̹YC5&Tƒu>ZAK6`Byz<y/C9Ґ"@.pzj_Ak\mD M3o'UJB8͝ӢG!UU%{xW5xp#,6\/?-k:B eX83Xn+wrN=SUUKqٛ'-ufEK@rƲ=uqݒ 8,˘OFJ4@nV. k-VKn'gwQ[mqF=yif*(IZp]q.Nz+y$W dsZ8(pՉBU{g{Y̬]}hHM, _,S ںH-/YYʎ%( =ȴEh{hIr ޶=hgO'BHϕb^y)dS g7wT0c}^ ZD[A!m(=|jPbsw[B-sFufiKҥ"!G7U5";_9_F?= O7"%AكפƞYp$Oľ^} 5)`^AR};hϞ{vS\Gx aO< {Az+p=S00ټDp^&<\s=X-A$9=gmVl1o23AFG3{p N/xH yI͇,prAf#F x#Yɖ{B^0t/pQfAy!yZs鱕At&!l8cdz{qˑ )A n$?0$تiQ%塽[K)!+͸vɏ:WJ)#*-,3PdŷЎs&Tr^̏`mrUm6Q8uX_p7!hEʓN \&.yݧt[աL,w9Eg?Q5 aKZg&7CL]8r [YNz&<3t V <띵 #qLs^ט: s1 AXMV;Jߢx V}Ds;nTJW4K1'D'Yh=Y7nS(#lb6CC+fX-}X\hlڎ`M7BzQ:OtOz،v<|j4"cS앩lGt0YLQQП(4+ $5(V 8W1\OLHUkH}T)4QQnxw?EbWU{Fy˜g]LySm\',Kmn@հܮM _pɯj{02h#H^i=ElK!Olj eT.i= ֮wíQ0*屽^8:i=\x^d]0DZϨTi+6IiVCpOݤ8Pq[v#JwS G;gvĪw%ZO geXE%z&v,T4M`ˑ&zǦr[H]רI ʶ`!.xV٪<OY}R ZSEcT2ہYy3` p8,%W:+n;(9&h]0Om`8Sw'emoJ] kdşr>UU#hS3ލ";s']Nxlm9TUP$<#\F68p{2YPrPcG .z]OT]`ZTձ fL: !oݓt8@>">c\f7g2fYxJ*bDp?kY"F yX].+}7jpZ-Uk'MOXހ=ΥV;iT0Ӫ Dto& K+S5ŖdBs4=OJ2jh&sLkX#Z3z,>e,*_BGtzYHmKz}A^<G%K$VHMu #JE4:T]d ?"3RmXf C:LEBD8SЩQ r0>72{oVꐰݐt|巬R}d};V4Wm1tZS|vONܡ:l/P!Xo{OPv[DZ7wJO U]_5π96z@ԪdV,K\E-|y^k)޿Z+$ORv-d+KIW9#\._/jhm^bhMTj|OFuTj(zᏠQv[xk>QtqnNY;qwK)(K<|ATvǤ :OVu?ԶI)(Jx&++(As]Aujzw nǠq^h\PPZ߹???)܉F(uٸxkǑhMXSEev]Bxy5@{w{x~0+*eЁQ^xjoWL7>p FfSsa&yt[vv G}n|#Kv uD$Օ; {nXujUiZף5#p's>;=}?Lm;c0CUc#1b=}\hm@+@2̓k"CY&0V'az kQdL+g(kSv?{Xߛ#ٝ~Ӵ7+|Ʂ ,+\ԇ+ʛB(ƾ(*&rrQIyewy\vwd!6je4gS@p%+ g !@YgYQAI=QꝹ&<)BnЫ9VBо%>=YY _$CفiRc;ۦW55ЫZE&ﴶa5Vw51k@ ɝz|b7.+0ݦMo-x?vGsW6οowo_a:۩5?gD*Ksi1բSޕK=͞da]9=ىU.=Uw,Gr&@7}GHszi )}=ERKt ~ѨΣ[דY$l  Z`9s7Sfד^$u cMovh]-2j} S3q8 1yy(.BDg܃yֽ߾f:BUlݠ2Fw=f6$ Jil+sf׭6P(6,_-]ui=W' n@6dխߌZJUεwKSsmGe䇹6YYzzΰe'CurJ߆\[k: /%,%<YNZUF.74X֎ͤ;/xmE򺟏!Y ܎{y=ƅZoGcIc(VҡR{ϓ<x!QJgOF~A2S \k{+|/؛r ^jAz:vTek?WOAH!Yzy>L} Tގ/Ze r(XFMuk М? ȗ|.B؇L2<" ;6*2B;j<.by.=cy ȟcWW""qʹ\;)G/$7*T[QXJ۶hMx;˓|S W4~_ FTGuD?#pa$u`:鳿H(xP[G0޵|?@v<(#]ˤ߮# ߯:ʯwm>_ǿeʮ?sOeupI x[tU?7}0m]qm6u|90x]'꯳-Y[/=L9>@`a mﱻ{%k^Nv }y'8˸~DĔ{wtk4duۮ g{m#8/7+Esy`m4ښ}wgK{lG' ^'fX[RsS`+\ hKJKmnb0#B;t"9˻;#>k#۪> 93sW`=S'C+o̫mY yO:L)3Џcϋ9x}}G;i̞ 8=kr~;48(0uԲ,?&}3~6fs=Yh<7+'ps}c䱚x2]7qT^mgǧ he};ǯ0"V=gel*ݼqTq6qŜq}Z#qxBD+,[r}IENDB`perfbook_html/img297.png0000644000175000017500000001213311672746071015322 0ustar paulmckpaulmckPNG  IHDRL$1+=aBxx"O(葰{KӣzK)ëppvSbh5m*kVJ.O<#@z#ǥHr<ʧj p]4џ 0oRXqi${pO7DtFI,<]S̼=SEE}`xp&EXKa- u@!=:8Zxz @ڬO~3"8}$7ή>c<;=鎸3–v/ ]!L*Mmԡ!7`zl{NbpOٰdqw G"`iP( 0}qqN r*͉2Bo98 Awq~+4_/UBw@Z[[EC%W<88:37lFgθ܈Q6_13;}.p5Zl8&t]-tRrfFP)|Y5%ԦmˤC*.xmlPQhahƦ8{$1K/>'<vWg1@`_-d"Pq؃*ELI[͢FB!LTrFgA<`:)&8_U9Ioi<-'% }<(=>\s彝f}Qɾ3)$:GaKM-8j&N2% ޽G+:67zjg01iOX7v)9xyg 6yN+5*{ -xP㐧]y+}>Jöa)hy 'Ur:%#^!m=00JhR @iY5h@M5hJ;D< ܪaYzO:]1:dPJKf* 30*2`Z!=;:W V|<5L'd~zBf>?yG$6 .,ٶT1HV>3ߟ/;)z^ܱ5'|M?t gStZ_kY`Хm;putlⷡ+PbBduѧW",ںdC#qlCI&kԗV_v"u'=߂/49t[dt"R1i],%>IC. b DHl^5y{U)R :Fמل׿'*'?WNR7ڥu sÈbUFBEnd >h-_93tU7>Z+j79$Ӥǖ`U;.Cwn99FGX>ߏAZS֞վUn%#lGgm?ͧ`rYQG fܦ` D˜+{?eG}I? ^, D1-Q7^h]DZ4zQ 6U7WP9i!v+ߍ忏a`&h r5im؇#5+%=W ^+rSCnތ>ZX"mF>P\u'XJt K f呇m2\iImrY)na` kJKS8F@9ͼİz S2t!Jùx-SorE{Ag5;z+NPɌ0sD0X\{1`qg&+" d>Pֽn9R+?`Eյqڋ:~E W3+j.{u8`[^& h݅B^\|^0RYmfٻ;B';[1,_jXrGIu#J@HYlL-nWU8'6mi(\4f7p&P0{p{fKbKSjRTGx!#sq9WU 2ambn&cVpせ1P;hsIsЁdqD0e 40k}9#,R8>oCI<zW^pv Y\ ϓHQst/NaM3u moׄf1^uj3rb644{aaa;ZL51u zW{|a$H*2M91W0(Lk,^1עp[\([='٥8v,>1> bU>_zgpU 7} 8٢̯I赢T51L.%R%D>HuDC_gF(z/i읁xt}4h<2&*S'(k6ĂR3]kDQ6Q*%U8ɂ>7f e׏fΘ=R8Gn/(dvR<։D-u(rBN1Ts^iΨR`!͂>7&X`Io/Ǟ\ǧ8c=2$8ь<*٘ r͹{)-n:a*C[X ajw)3֚<3(z wc0S?OI+JBQ&꼒1%\s^1g4UJ1pH9͐jm.&#x[|@cz!Y ]^_ft#sJTkIWN.NNa6]MY!\b:)CioJ@[ܓRT3ʁ]ujr C;FŬ,rM2Owb9 0'%YJNMNa~N6g&xC|O+RRI (ONa(evfkʏŗY~YqA<'*ewŗbbq2'ieָհnnEi-Gw4 ?ѵ߇\,@y,sa54444|o>>d?T ܖtRuV2:9{nԨ.Wl礔Q\$\Pr`ۋ8(NdgJʟ4[CPŋ@Lt@!,StaO~rTq.H5/< u'1Av+^}glBCHpXaa0"Ǩ >NgLOv(Au bZ~$;Ys=nl"+W K(RYu%97GӁ^|'ϟWjZDrwJls SؔB&Z)>1<45Laihhh,&?mod}ng`PMMZe޵eh(d9W%lLn"fR82nRԻ 1}wCPiswdꨑB(/3n.JuEQ{p3JQ+%nƑ# 1!}q9.ˢԯH?*k; Sݡ8' 0R ½wFK2g<6);ya#×DcMu6TDYnɇqwշ H%[=^bF;sZ ס);Yt~kCCCCÅ{ {zudguVguWA3yYTpdjm&fM##y8K{IENDB`perfbook_html/img185.png0000644000175000017500000000047511672746057015330 0ustar paulmckpaulmckPNG  IHDR0 ֹ0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(cp```pAC2)a00@(<üĹd+956zpq\^= `?s*g!q2001t#d-@Dž+p IV&pYu!T[K@$ƀM8I10`IENDB`perfbook_html/node197.html0000644000175000017500000000663411672746162015664 0ustar paulmckpaulmck 14.2.4.4 Pair-Wise Memory Barriers: Portable Combinations

14.2.4.4 Pair-Wise Memory Barriers: Portable Combinations

The following pairings from Table [*], enumerate all the combinations of memory-barrier pairings that portable software may depend on.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img304.png0000644000175000017500000001065311672745753015322 0ustar paulmckpaulmckPNG  IHDR 0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@f)IDATx\}޼ݹ۽)L~(I8w2j93C9IP44G 4%s \ω4mA~0.QEHDJWd$|Vycg֗;3|߯}o@wϷ<: (}şE҉gB9ԚƵo8t])\f+nlF)X _ŔXȌR5=)hR3 0cb;`w%9S8`̈́j1ffJ:Jp緍Pޓ*0o+F%HKzkY6"}C F%>񒀔c5T"墂_/=_T'Cn {REZ瑦:L|~CDY~%0A}Bf%(ޖ '*vH.Vr{̕(<Ήӭ:dnmzA6i: E13K\^$jVj"}3mn6wBj”aR{L T]D'MP"v@V"3U+ꣻcQ:DuVmBt؅ wxwzXAZ'kREC[ }װ!9܅miVon*Bfί%P"."vbs`]TJ=tSq3A'nЇ1i8CYեZ9EX[7w2EKycWo -D|'i598&fNΉn;S*-R2R|IHl? <,tkcpcarkK̏{$cwt]II#]m>OI+`*U0-\Y5MS⌦ 8yt&z㖔#/:m'vẮ̬=(3GpjP\~dp#k> %R m]N!HVJhO PPo4ĕS"N4U:́h̒:Y*" ]N{{8d6PV?R./p>7NvUfLᥞ;ޞcSp s 1΋G+5|N<%w 1#9]b[|@ctga$HӔf,"?4mt+,}ѵV"*J 3:s$'9 G/JǝHfۆkN8=ju], i$f{a;}$BɐXw|Ib(|N ׿;2D"87s5k-~{Id2k30@ AJgA Ru^'+mE\3tI>LVe)I{n'{+*#pjdvmeF|5$ 'j7Op6U &?4vuv3v^ f5t" &]S0O#J(Yjwp֒ 2 icL!d0p Q"Reۗ߀&GH%#;+:~ܞ[kװ;:"3􋸖,v;Rk0d!VNtAqiBiH_wLy7C?6n}cy(Y~%K1^2~'˻dX_Pj{Oe?S(VD w3$#[u xvs!h\ {/%ljjբ6lBjs؇s x DҧO“< {r={y;.&][ lْU^x\^/B uFF!1yfJmSv*[[xޞm'ϴ d.l#i3KJZ-f鹂'Hl'/iPi{*|'$#5\YG1YƢKRxVۅȏawOݑu?UH;+ک٥;pʮD+gA33tX\?¥҃C&/).li +EqMPǽ1`aUd8\zYQ?=*­#q;<=3v==.e[i{& 8>t3,ff.f%DٵpiQ}+7 UXۤ &uh*3 ~Ya=0ĕgjs;7\BNKSw~?2Ù=~cjm/qZ7>LmA^Iw5?5DWafjN(/=FZvd~%68՟>JĘp?x!4aF^.~|U^A< fkXЋt^_]N$q48yP5/l ưэaw~ӓJԶh @;)aA*5:7;iJ /`1E."̾E0G+Zc^mijssu{ng GѓFW"71kXRZR|r:5K`F{/%9@edn( ~b"ְJЏk[+C!goSePL2n=Ǯ]lŁnh3;X҇Mǯg(hQhvE/q{WLq |m{g"efrYę?s.uJѥz#TN47sCf?y6Lҝ.QfFM!\ֲ6C!3 oz-v?<}f Xy^3>:4͘K>ٙ 'kmZqh'QDeƢP:ss8v \+6/p)ߊ/ (jC%+o '!f߮3Gko|#y1I#*Vgl`GMӭL\LHy{a٫Qxm7 Fްȏz-,@ n&1؁ޥf%A% zpB ӍĻC'^ ehY(Rn~W2ڹx#UQ0+wtxc,6xyv ؟/aIBXa%%]gʘj]elXR2S;iĔ8J_"s0HGy|fDܴG )EC mLL6,EL@6p!Qf__qVbp'[P #iNO(QGN&S3t|94rݗyByd=ܧ3[?kVl v bE>H@?j-ޕefD?Y"{f`q銥<ʌ2g&B-dIFdX'Z /'K*6%rJtp˲OIENDB`perfbook_html/img232.png0000644000175000017500000004720011672746060015310 0ustar paulmckpaulmckPNG  IHDRV$g*tRNSىH IDATx=L{?8q ,@ZJ "Gb-0HA䨃7|t"Gh$0ss/#T*TArGQVESV [a=5Uܑ/+AJgjˊLN $.RK9O\[Vdpp̤% j,$snutE7- lH<ʎ:)Ÿ_]Ve] [kX*_Rp^s<_ T6j6mn&yɞDF\-c߸r5x8"e&:ïuȌHlD8:A>aeIfɈ+r/t#y}S.[NJegx҅z:QFN|#S6y eoV_|$_yz"@&f].S 5ML5*nղAEFۯ>Z2 MTA\7ٲ#ȬóFo`6wYE6k@%<,vUXol{!8 ;?qV(pgWtJTÀ^}gWU9DOSt;)B"w) XYu ' 'zbW[ 烛ܥBmYwjz0*Sk> VB.? ı aq=} wtF'c=[VKX#Kl/9(c Il7BWneRUYͺ'k kUk ؠCY:oHLI(=]>RTK?c^o|ֹQ` kef X)ь&6|=eh@fi z?vQ%7s8>^d!!ȓYO,+q]-03w+kf`X/6hu{r[IHrkkizEpC"۔ P #c+W0,I MOٞ'$՗xG&#}/x}9R܁Dk w'+YJ6fQr'}fӤcd@Y{Q ˣb1!M'{1s19*_FdYnL'w,rJYB?: !9,׷ڀrϗ7z^?{5a|IbJB5t=F -jAOe |}iҽ/p*٨:1wbH˦ aX0,m8,'X _vNq>hM ZtUV٦oYUn&[6pI8f &Խ[ +]`{TBK:#ޏ,kQv9dMo&.l)q\\aP3_@##\Z Aj$()IVK%)ZB^CDQ'dLEٰ"X7&7ףYRfPv]| ]ELOV@vrhMV2_[4:G,!+!-h5 jzr߂<|ctZh;[\AcȊjs [ f!KuȏH5^CJS5DWdabg0=Ն ~*(LXz܆Q:bD'7o(:!Gf"bfJTE {ٳV1FEdV"n+^^3m~lp FMx8Yڍ&y=ɚ|I-Y/|3dM<'5׻,/6_Yq3^|]>2wV2k9 Z* n^岟+n5Ӑ0\ Š-cOv\ e*2gny#tv5~:hh[0o ]˚.tIh0MujPBsc+W!Ne1nJw `A]YQڵ.Oҁk4\}%$6+*v0?UєjדC5qWkß=f}vSjvw++jv }K2Q%nTS-ۉj]H'"*h@ѼsaBµ:S ( 9? BM-U}ݴ?mCU%QAҠm>ܚ 7oqN]56dQ<]xnt76R]w.)Q_.#! -\d㣎hGRS-_V5Lt٭{zZ-Cڈ4Mp!ֆ_i=gbUj<2#djNYԍMב %mEE}WQ낯6Ǫ)ʏU8-J@r2#CBLf˵{6TTuij04-W 9p6Mz\ ,Oj\KD dq]?E%`x(ĕE/up2mPY@K=o`>"v`I4_u(I%~BլT= /@ɾ:3AS !][81NU)_" ɛI∖eRv?$UWzEu+B&j_#)DugJ}k- $k]#Zڏz@RY~%a??5Rmҟ RY J@jץ fq@:t9 (0E{YzծCinjN} Gu% 4_p ж"',UeZΕWud;U@ʹJYБY-a'MkR]y 7RmvJ3뻁P-tmGUyZQXn g<+dPc;6_pK>!׸S/|:睜'|5?-"Q#a "ZjN |h'ZjXVn=Q Dk6%wdLq4^ }!5G6<5JYjK⚨:(e+h P7,_p[,Ue RR$?0߯/0 g.̸`[uQX6,IZ+uĚh6  {-(Ni VŔlk*FPV1iQXik'UuMmqS4F(`/$ 3~ט HPE-Ckw' 6۔%G8ݸI9aXӷ|k/wy<_. r-UA5TM7? f"9 [udD.dS(YuqFdWj$K#4b8ow!L^o_b(-v -qv-m0m?zo*8#{9&K<p`r666!fL],W=DjGE=$p#cԿҗ_o^S%}0n~m(.Q[GL ;4nYU{|"bڡ.d]0Z ~͵#yG:sf=6Ѭauy Fb]o W׏@}Z()[\D h~҄8wk⺖O'0x: U7]ro^ax^EvS5!Wݳyսk>AoŇ*u=x,aD~#y4C@x-vzAJ1 Ep ҵ4:w`^K"y)p嵬[m\pڙXu &톎eD"$S7U) \[Ti|q^c- m{`xk@G-pԑvyxM:D=l wz뚋o]]2E(n!$'t:ki%1]yoo/PP+HrONM(*ϧLJfWnPZa A! ).Uam.7(KDbHZn$|8ydp1?P`@`Ш) قI+ZbP4a`_2˷!ֲԭZq}m)HYcD>"2v?Xkg*NMw&Cİ~OxK@ :go: mC;N-)ߟ f'"H6v[>>G~d;68mwd'2paOJe~պhg/Gҹ#,y=# ؾEҾß馸LQ8>rl2n^9 jyYC4>&AǠ8jз~Z*4bbk{s$2k llO[/e2U8+:2f1@6CKqlI*M_߭h,Ufc!Oeګ^2hxa4QJ;/ t^A]d+h֓y-&Oh/L^ƹtʿ.4^t]?I^JWԵB*=ȇ/0etT ;m1<{3jbhގw %+ {ME'?wu6hHߥgaR>4u1\[Hִ5ZJ ?\5R]A Rg;4s[l48/;Ȝ(p!W^ϫ]/WV.jgz\[\笚ۘ ێʪ jT O]? >.q֘bt vB }\nC}i{<1͎mw,vpp,ܤN؉1l؉W}miX4 *5@;Ƌ@#~}/B3 [bʨY"Ԁg\P>{W`+j}Bq:_,i\\fys/\akW{?{=+^EǼ[bEܮ9?:6?6έW'L FnhZPF1aSGcE f@/s;ge/`=l XrGEW}7ao.s# w RݍAxPjVq^+"=>½7u<;{W^C3 x9i70Qtr=[Ut䚈x[t.sޓu ;c2ԅ.^#%l |9$`%].hGi># [˄ۯp~3kSXx_ۤ$Wd0.=#P3{(2KNdEz%fֻ@'a\d|֛hɉ£عqǫ$e|ۜ/]Գr6Ȇ$mʣ\ۚR]M%_u_fuu.(c%ڻ\@%56 b: iEޑ5{ml%sT3!CͪZ^3W9e{Y>kC}>a)sW_bp>au:`9sVg {6({ Vt^&Vc1v}!1g_uܜM\ʶZ 1"MV [ٶ7l "s+ q.=x]wS{:wzQ|9 ;mȵmu|tpa[=C$37 FdZ:1nh2Dd-E j4;jM`GfA|[5. BK^qXU>Nܧ X4`ܯ[V|qCc1fZ&MlLc/- ,3?fI?BYo|-`y in5kڌ7 Bc Dњ5u.͍G9]=|< ]xS]wMv YIuRâ0Bz NV+5//>b_E.TU&DaV,D9{:EhFGŨeߪJ,N[%)91_AoGy![5Ժ`9>hTSfEvA-!ihCg%Kgo)шEj5됬`Y= Cuvx.̿8Z:3;3*ho_í8qF]:Bm$\FC3ϣYVr ޙek 7_ؖt5|>R]o`\mLQ~M$?>WajQ>uW%TH5x:U׫JnӐ+ aaܨWuߒyť2Bv fV:w0̞ҷnZK՗|juyo^au  !KjxGm3|(va4JafOm]M02*+:{ D+2[Ԗ냛XC]t\|{rjXʳ JT >+fy&\^66!]76{auyo^@0k~yo^auyo^ >Aҷyu0NŮ ^ޭ憃o:uk%[]ⵂ]އZIwoq٧ H^3 >4Ы27`^Ackp^o̼ a:R:Rw,^'u_g[5O4YT%4m >Aҷyu}aV זu  IDAT0IRnvUH6rMw}j&RBu@]I֛a;/TuJ{+`g@OQLV+}?lwn*6볋 4̏q&|27KhGjwk3c3?ti4v҇nU*i>m243b㓏[SՆ(;9vYX'*J] @cH~o=wqE}ۨG!ӌ6(W &Z⽦n(W `é/Z^ `1ERO|?̇N\7q.-űm,.a+y\‡$-Nq02qA=~Ջjfs.[~ljp81`Z[%r@-@py7ֵ{Ϋi/iluyh^Ow{ixg'Z,݉>|ih]ۅ!9s"zU Y_M-AA_k犾~Rܥī"sGMrPzԧN(} -v٪z.֭ Ļ% '"ZW(by.)^x:E-v[p<Ν Yr-=K? Ch?ȫT.:|Y]{irmPՉIV?5>G}WrsVZjܰkkvF+4iR%z{RQ. xa/63l:$H/dRKJ+h@.$)c@)FHcTAao3*K=Y}\˯ X&]O;rwJPM۹p/Pdo:Pby.΃1GE9l.XЙ^K  ~ĻIbz%z׿[znWjsPy^+z:0|i?si)H Z#Va3٬@f'/il6z|}z^ fN#pf5шjC\kaa-Y#δ성Ƒks7רeܵy}j=hЍYmREfCO7W|Ƨ^so5nث2b~A/ {c¶3BH֮ iEjFhkߣފFջձv޼դ;Tr{f/5ؓE<ɗ~Xo:&Vi| /k#{hl<ۗZ5~yWC!b73cLvǢ-l0rgƞE+jVlgjÃ/ l WVl)kWWjo'@pBQ8r/ɼǡ^- gNd&E!hc9}yx]ٶ<6bLgp؎xpxފOTp];mSߵf^ IJYƻծX({"Ec?S[gSED2CW;L;Xgέ2|@Z@2:8D9,arbK{Ὶ.7)0pFt(ځxpx?f5߽`^IC^&yfk5_ЃZr{Cw流ۙ/ܪw]DaHqG^üf}ruʱז\|r+W$}>^΍l^w5堐>E~H*%kFXp=xO==Zv ۮ `m=hx3Ml'T; 0&gaVWk5DG|}Lk6=Sċ[|?UC ]ab=pW 6Q8TƝHѿQRqN?{ zu4{t@ZXg]ias_)5AgE 4 c{4nP#sq7~4S{7ٯ&ֳ Qco^5۽ rY%@ݜd/LJ$:lv]+WuM;"וu䬺O5p6ȸ@ gpTaN2^mc<.6jόsO]3J%擣S]Ϸ]|utfkx]>Xk>l/+l^WI5\ OauzR˜zĔf-3NΟ^vݳX3l{ ՘es"532G>O]Q /i|蚏N`c\=~ݜMf_e(-$=+ԋY/ de jL`jQ \CQǓ |l`,j m%wZ#`*$՜ɷfNЮ٨Ŗj|FT<N8`3 -B C;Lv%m"21-Q˹fv L9Cm9=;i0b.ᚱnjEf/(2jM?茬3@>k.|7L*.ʶ՘po8XmAFBlClx>pڢM(u2 3D5cK(| 'Yx;^oyX׸0gi`#뢩6p,1_ qZZPn]9C)tLBc/Uޞue5\&(cȿuk+i e< . dg̓D&̃Gs?o^aRJ={)^u ޼U7]|-%WiRr*Wvz>ɉcUt `\փAsڢ+` -Z9kVJBnվgڐUՁDLn$rݗV 3q]mS5'"ݥ R=ՙϊ䇵:u2b_Y4у8t|"k :osWi7]← Wb5w-=+R2cpw>040"A$󾞹+RX/\ʫ1Y|/EbL#k}u"e|b\\'h7f fu` vӑp1v8$f*V]*Jڢ g81-V>A.Ӂq1;.\EG #n%I9SjXxբS7t"s#MYrs '7٪lhb- %kՙ43ꅉ/$Cу^-!/zf$ڜRXgjxmq c͟cEL,lNUۖ3QL1h2l l:^p93'J,7"4] n1|1+3clzfjEuVd&|m9s}=ږ70Js|AYpXO;ZOդr V^̴el07xx^/uuB@įkzւ؆`ktڠVS/HOg9u';^LpaΔSN;w~K%~ xu:boX[-A QWy6ĪV|xm[-A xu:boX[-A Alڪ+x%b}4'@ V&*rJlDj ~XTy^JA=#UUTWUjR?HeXf=DeX*UWUh+UU:)TeX"PeXTZDdǚ"\+\oWPŏViTfBpE\sw+*WUL};U+Vo㵡xOA4d!CyBʯU<爐?O2pJ7XY5S0 Dת}. TmLc|ic;m3WaV)} ^ʌJm B\`eW;` 2.Lgɵ168XnNIeJQuL;hCV4熫:Ɨ=B7ѵK3+5?BBcVDƗ-srNŸXL@ˍUbJxrN=~{gۜէ?QG Vck?Pt/}OP7~ɥs| L''cO-sQ;@/? 4@_QЉWk %۝divO>\랿iQ&,%I݊Y-tiV9hC.[[ fakd.:. btыʖ{N꼃&-SU1b!DASJ7 1C>.5q>N6G6p3>Y9- Vv)PhV@އ2t+ }؏+ml>!VxnpW?UTvp(˛Wo3r_sJ2qւR}kybGfk2M'Gze,ąt#@ܞeoVZewzq3=}\N =`0_7h+O>}oV/+ ש5b[@t7 .FeG~X!_(VUVx0k b# ~X*+<6WXe&G7 "boX_&V?eb]tTa﹀[+xq6eܝuL fd(X,X/rx :JdԀۀ}wVAC]c-A,6́lY"vm;bOrlwK,gsXAwQ}/#YUo0b˙X|N>΀$+Ũ^h!>|PK%~ honu7/6b`;!q]W5nUȣ?Yzx&2m[WK{8jOAlZU^]Ɇ閔 +;TkY +vZTסXVVXItNٽ-5aeŎ@˝*s{[:tk󆕹;UVm{pmG]>ոae;UVmyCKT?tCxCN*6:v_3Jt )'Ȭtj1|/\WSi']*.)w?'l g3i,7.8qzl-6w ;Ssr]߁pwK;s:x7Zpi,.c>Gdʀ} Xe焋'J+w!9a!P 3|ep:*݊]Pͅ2_Nbր#/TTK~!e^# MsuP;9z }odݧNxB}xPC,}Oc+/Vm}nB;jr殷dvֻ4O]F^*nb'|tX)u}]J)*ExLKz/.Vf[+*Xw]7Jֵ+VẇSc 4TomJ ]{H]:w6 Ubn{*hm ZUnc-Nu;m51,l^PN̥lx UOMՉC$`k*/.ahݬQSD"cSeLQCuR{YmT+b݄[L\|׭N*~+"Af>wkRDZW_If9RM"ݽy5Ϻ_L$m;il ksZLn~X۩#jᏀnkg(ꌁp|E[YBe#?6OMmgܣVxXCM߉V9~L3-̴6*o[-A D2Ä oѫ0*5t?q`1=XD_;vg[` NռޟA x}L[PAV V&RHz '0boXA,@{yW9 TR?:gwS~2X&>=oDW]\Ļ0s=>=٣s1#'HvRYlf_ρoO֛WFPʻ(HwOcϔEu|.=ٯ܈얉.c%TN'k`-cyTdN'5*)m!IDATSfC _x y٩VdODuɼt`2%3o[ ,M +pXT LpE. يgU5LO:_+'ΧYܔ$*Q/s[ݔķ e׋o-kA1'`l6V*=ONu{:)VSO!z`1_yq~L| !\G~!"*$/+&V È@ǏTjCWln#VVvpEjW2/VQJ5KUzi+[6E*Rn|TGgsKU֜3I/y=X,s泉4/4cbbRhΙ/&ʗҼsKU*4y60|{o\7mש0]C"U1n&5eҭ:*Vq=>]3 Tw]6쓥ˋ\4w;X\1;íB:u`jpXV͵evx'+\ 5Y1\5+fڲu ۓjʧ 2+U.%M.9O \=B  AsOKr|7#=ܣ|oWƕT )~DxE yh#,1D8M3oY_*ᓲL#:joI~uX`fKW;zHߙwȹP3ܠDosϲq?ڢ#+O,,qbOt>_V{}fz۱UX,9SOc$rpe61& !]QN8v2M) WRѕ8Xycr+qILe<-wg3x)NwH<-tac@bzpGJ_?z*'wSE5xq#C_3K1?:c 44 ?j%1ԊSiM}@Wn`M݄F^T'1Lĵ9nUJz~ ]]ws)ۗ8Xf /~ xut5uq:2pZhR8A%*FZ狕Ţ es/m{(P`qm\+/fǵ*{=@bsX4b6'Sz0)gO ,M:ueҶǟKt=,ŵd Ա\fr.mv$rgO 6)ʤmrE^;W JwM@m \p{RN(̳S¬#RbrV"~9f-*m@N2i[!㐳QUZU]DۻjܤSԜ~ Q d*;^` @͂퀻Z8[V:v]9ɜnCÑ*ƎSRXOd|U f3˒˷&)꼃cfjxL[ve' ~JBj1b`sKàIRU]jfv0v6 sѿz`q*W|+Xt=`)I9X ]kHݱ4g}cJ"e0:Ǫ Y ,:[m۶S(Ƅs󓣮ĔDPKDѩ8V|ws}mk0_ cĄәh: YSz2>Vc|J4BϿ}`.FW^ htŁ욘P|d=8V}ҘRGn~.onWB»vg9ka+/',iϡ^֮/\30i/@WbM6[m. IUk W?RtڠPZ~kf 8\i>f.LgMWϛ 1Άݴpom;\>?ܺm*P4Ěnj;YPYOϵPMiUoa{s[@_2.&Rrg%zE M9cNfO _f<~N}U2xǨ$dF>`iѼ'sƠXV vqSm&%c@CЭi*x Z +K'U4+_b12M1ʐ/Udu%QʊG{ Fbgx(@?t飝+#yU43ΦW+!cH644X wq+^kA D.3 Hierarchical RCU Code Walkthrough


D.3 Hierarchical RCU Code Walkthrough

This section walks through selected sections of the Linux-kernel hierarchical RCU code. As such, this section is intended for hard-core hackers who wish to understand hierarchical RCU at a very low level, and such hackers should first read Section [*]. Hard-core masochists might also be interested in reading this section. Of course really hard-core masochists will read this section before reading Section [*].

Section [*] describes data structures and kernel parameters, Section [*] covers external function interfaces, Section [*] presents the initialization process, Section [*] explains the CPU-hotplug interface, Section [*] covers miscellaneous utility functions, Section [*] describes the mechanics of grace-period detection, Section [*] presents the dynticks-idle interface, Section [*] covers the functions that handle holdout CPUs (including offline and dynticks-idle CPUs), and Section [*] presents functions that report on stalled CPUs, namely those spinning in kernel mode for many seconds. Finally, Section [*] reports on possible design flaws and fixes.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node389.html0000644000175000017500000001213111672746163015655 0ustar paulmckpaulmck D.3.7 Dyntick-Idle Functions


D.3.7 Dyntick-Idle Functions

The functions in this section are defined only in CONFIG_NO_HZ builds of the Linux kernel, though in some cases, extended-no-op versions are present otherwise. These functions control whether or not RCU pays attention to a given CPU. CPUs in dynticks-idle mode are ignored, but only if they are not currently in an interrupt or NMI handler. The functions in this section communicate this CPU state to RCU.

This set of functions is greatly simplified from that used in preemptible RCU, see Section [*] for a description of the earlier more-complex model. Manfred Spraul put forth the idea for this simplified interface in one of his state-based RCU patches [Spr08b,Spr08a].

Section [*] describes the functions that enter and exit dynticks-idle mode from process context, Section [*] describes the handling of NMIs from dynticks-idle mode, Section [*] covers handling of interrupts from dynticks-idle mode, and Section [*] presents functions that check whether some other CPU is currently in dynticks-idle mode.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img15.png0000644000175000017500000012123611672746156015237 0ustar paulmckpaulmckPNG  IHDRZKPLTEpidܨ%a[UԠӘ߶Ӣګȵ~՞ߺ,!83,6/*˖rnh,# ]VP޳~؟A61җЖ |wn֠{Ÿʺɋf_X-& 'ު߶;-*웘՝yrmYLGќ*ɺjd^#ج#Š̕E>9ק  ݰ2*&NJЍXQKː!JC=ܫą޲ܰꌇ}C:2Ƌ٩{w􏋆ء0("RG@pktRNS@f IDATxsǝ(HI'e7pq8K41 0:96)ok7FV/ Fʲ3 ՖE#i TnI(a/C%i_b"H(6ThT6uc_ݿR~+*plW~r<"[3 WE ~ ߳ W/lCU_r$~$ |% {$"@~h&I lv مynQϥR99OT|*Ms紡RL}{b#Q&R#\YU{,xv bA 0r$AWfH"αjָ/E.UM=a[FՄTeUygp6k= vX!Qn1~@M ʂOED)oWJJ؀,}ec6v~Ѝ) 1}Q*jfZނ@3F)d߾j )ߨ*Ξj C"@ * uJs]3Fى+|E0NLwetr~-4BLcUT#z7wWRML E kdZ"t4[`^${uNrTdl0Z?:ɢڢ(ݠZujԬ;HenK8!xlz!J4"w`LAhyR΀F,-J2<1$Qdw푪EdJV Le0JU! $H`|%8DW0R%A.G=!B,#: ï0 ]nPy>X׵O,@ =H&@pmFl&X]׾!LjP&~㓦ōyݳM$Ć_Nҡ^q`s}&&XV)?\} ˳X"b`-k:IY$vKl?aR닫rW]ތS ->>}~(#;ȥ%u)J$yfR>+y`\]61aoegޒr%(x_5yI!eRJBX.D1Z˭IPkӐ>ISXT K!BÃor 97,bjB(fLjⱪyVwXD&o>tx^S3J4Gk-^yA5&w9q1x]ΕTyHK"`v {[Ne&dO<y_L&hN߸(B,0ƠrOw*`RV_i-8nLk$3fht%tYX:u'\4ͨBB4zGĊGfC(?įCCʪ0"].:ruX8k_ oD\2M1}iqIxY8@Mpc_F**.~7VV3te$M ds<6[F`RV$qQ5mcxZO_ݵݱPz^%+x=o"]xҫ}1FE~˒%j&a#gydմpRf >TOaр?{4S "QY-?uz[ ;``fcDJ/6<زWiR_'ԅdS,5f4QůtAAVOFu#a97{o܋~W `h=D-=H, 5/^+{kDLI3 9%7* uIR nx̳k!˷ܼL߃k+/S 'JlF-cf-- q> T+W ?:pە ^g`-_3TCnLMR$5bbo/fʙ@ʟ*e9i4<Х(ϜNdS6MmjAxA}82PY I:NY|"#7ٯ(VnP`Kۜ<ԜS *-!`Cq[$FH)sK":&Gn,hE33kq>Ҙv<ȪɍC}:~g0$WeNsd3UO|>\*%nia!5FЎxK:zc, Ź8pL 鞤$U ;vѴ>e jYgF9ل`!anX& !,_W7aғ|4@B4+B *⎮`7aJsBWFѣn [BNZ^ t`qc Cq )LLhVXAN -Ta߈04G3)p |%1zVR<=7F XHV6>D}0&#BRN]2@RXkLXcFVDx6)x#p ,wv!WU %B6y mih'x} J$P/H4ge_nb PGRzqh8qRDJ^ؑ!Hخ:]7X.{*&M6.`M;,dm8%-s h%L9^_Rԁ7U4} ӣuV뎻 pQqF0>axLtcsKQ9DU4l>%mB!a4 vr/BKd2k=xH֢MHc!V$ˢ;l?`&N.vסO TSr\+d3mSE 5or39)x}#畋x\$~pb qAbM5Ym K j X٬ַo:['x\7`A5QHwaEF"ߖh^ N@MJ֔0ψ(leFnhbz q*rz) &swF6"_z9b{~ vWǷY/ {|'J154\q* %!b.Jhwu[">Ԣ<ȍǧ7.ٞdcwנ~vYS?U'$ȝ )~;0$kUӢ3k(LNj]](s'2'׺ X|/&;l 2$(P#U0Cskd{RrsJ[Yf9ADVrv٬0L#)D3KY~55>xb?hՂӭ_WO,a%j>h6sJ}3qB d[4}sʅ<e^{GOLwHP*"ߧGߒGQDΠ?͗5GX;8-5dg͜\}1l[9\׳Ͼ&I /h\a.[PZ"=<62&nrW}zo̕z(l~…Z* f,sOZU-`-HBs-uv>!I*ţ ?7ޢ:@ eT.[Itu> bc Kh`B_r(oGDz!FjMxlw i1pD{\ N}r S",$sq+YWfz|VR[M)e24SnzSŌ1!,:+"b FB+U4 IS1rWXV2cO 6,:7TDn#?7䡾Lo(P"6bX.Drg7jbGrS2x&@[ elctSpn PprY @]*HL/7TJE RU8`9<]Aq>sωt7bn<9&|[凑HE,^`>l*\CɄ3\jnTr Nh޲xjh.^:"o"MeMٯ>l lE}?!˃}ŇZ }l3$X6-خT90~mN=~lMk( B @i>&_Pu>hɃTfBh%l"~6ېQc>1%"ԫԡF:3OqDn&f?W4aZ#=Nhуb~N}q/$:l9~CF0LҪto&(FҘ B3݉\BiPȧB q*? ,$CVX`f%1A85᪼ںKGQT4$:ق+3P*b&qHi4x>ғKFcANYCy,rRԀsL3< 1$'UUZ|#.Zf %iv$5ƺ_Qq&Ua&EGk,!cL刿0x?:Qpt2Fs4 jGT^@[DQ\iiuPiYfv`tůZ~I>QѡVB&`C!ɦvA9v1PűhOD9ڄDn81X%X@HuRZ\)XD\AzK(t%h@ 0pO(27 <|CŶfU-l0ejɚt'xCN$cj1bhml 2O9YOm͎\1\%J_Έɚ@]e!.< XO3Iv22:Yo ^]|y`s>pIۂ݃?o &SR8vNP^„?l[>y'HR@'"u>59_Zzy%"ij]ÙttQ >6K1g0jG!P0<hfBnSND_bF&EDZf6HqdQ U"gwT;^<<~r%"13+$ !7&k7]}WyëE+6gBY;^S16tvpހ'qsggeTU9tb=ݬy 8|T_Sflk MĂBXyWUfaXGx`8y/`jgF$Ie5΍^y_YQ1ĺ誙\\ǽJko%cљ{8ddy=|cneJZ*]Ϊ]~X%0pC] @x9T.',oMO3ReWp?$xN rP5ب D$ԁ.q՜ޛrɕtb}m;֗l TV^k t[#ᜂ A)|"{p(n~I}IVR_}\ NQOe &+yK=>d `v'+͑QoWi:Z0͍<QӹTkRkZ.6?y~c?X cRҽ s$l't_њ(nwWZhj|W?>V/ӧE[ПJw1^ؐWsqãbb֌uZ-"8܌t|PEJpFN `[&D3 q/o_HNA4*\B~:<^p: +kW' wU,5cnl1yjL|8N@y$7552&!BK듙A%|z.υ *?CU>"GA"1.k4mŘـW>^|Zַ_OE6.$$v_0 i!.Lrtmv:qg=a4 /b͡,r*A_i=O)H+ihA/}(flH)V.4,o1u!i&sujt?ӛ Gz{Pj+Bo8։CPp^6u/Bcx`9|k *Ept& 89$P`6T7ۏ.{ezF% ?<U 9m&.6Jy\d_ea~pfW8&b\iHs \z]AJ o,q_-@kL98Riv/Տ`"SҴ(bYpČG9Йo/}y |K1U6H=.*V܀yFN" dg\5 <] "_ʁGJ8HMސ^YJ:==Ix>l$(IHkߜ,wQ%*cAcI]7H t" Wb(1X7\.7X I3}U%hw唡Z`!AusHJ~a\2ĽhEP&|Z6u+ɛ>p_K_79E~} Vp \߃2!)?Q?DB "f!ZnG";n)I IDAT>#}2sQ/_7r[՗^:D"W~a&Ce"*Oɝ_D>ކ_fHrn䫇{xqgY˙A2|~x?l~8{l 6WeETSM=*[M\X@ ֋J>b Twe_MO)ѯ\.p.x1| bzX^3/}qLĂvКJ 'ZLGH3,~/Lj+oP-q*F3@f bd2~ڬ^>6p> UؓB uXlLjʻRR"PK i'Z['CL)jnYl*s⌎q\A_!+"'[=39㶝s8 +ԐNb~VP^B~"ffB־3y4аAy4FTY38O}L.5]-j;SS1׸ots^ȧWѱbtAY88aZa#egOj'$ 9wᧂqXډ4,{ձhSC7+OpA)48~NrEd" A0cpſ,痪ڛ)qXSlᡵ F _Q\-uvʚ63Y`>lAT10zu8f5je5H2u)BEKɱձ GK\ U~[Fnkl^BUO@<RQ:QCQ=21(XtL&E85< hgO8ݘ&[ĔPIqRaFCPʜDB\DL ]kyT8 VY:4q=<MCx%& "ս  "a$SOU΀.UG.]ֹ_* 7>Η&&H `:0#Ax8h(¢Q@)i}k b{ (hJH4t3Fp~@"0$蒻=n]В2t5Aa[i(7<E B2t)ۃxNPN Qͥ#PBz8kBwEi(Z] *4"KKD0<8|jX;ht}>L氚M0m]ea^.~ м8]aB#]-kv %21m>K Tgeq#3 BiUep)RP4 =Te̒*ҩ"(uC6,9K m#ԝNj>w;:Y¬tg:I|Ky9M>2@-mOKk-*U<5źB *a;wClϜh\s ;  vp3#: O}Vzh'":w 8UUg bpO[n%2mmdcg)=5uS\F'ñIv>%V>s~^gRIHHqAb?O#A'~_B-^ߠ 8jח/{M! l9aޱ"j+af?h`-0Kƒuwp^ Fۮ[`ocf6vРMe;_ad\/7oܭ"Y#z9Pvr}U`Ƌ^7@~^1.B>1ÄX5nDl\NW͓ `O4osu; ;tYA i\OwwS<4`г~ Zf cM@d Yvo.?j"ww׹^||-K<ƶk>k/-f B806s5W²Z)bKv=M>P_AS ˜B[̯WSTJWY-D7vj|$U".-vb;ܷ/׸C͗Τ:$H a4COĥ }YjK l0p=_ d9Еg0^m?R|B.C hc,%7G +ܺȟzs4$V( Z+PԮlg/_M)FFc-v KjΪQd5~ kNS!?VZԾ:-*ȧceǛxEΫhZ3$jxc}gUSRF q"aӴP"N+u''>q\![č 9:j0U9qfqb!'o nV69%ѠtЙ4"p˨t"hZ\ HR3+wh\i +Ch(/h{>xܿy"ZaK #az|d "׻V؊*}E^2}̞t旱x*iDw2uPI-2 ^P`nm+׃3A[#Lo;9<<ؓץe9eN_ޯt/h```ch>j6R\v&'O&˧?d0vw>ͪqNZz쑦о`# ڡC͹(995pz4=(-u3ɇݓ]?^(Uj8|}P9|gi&knab]d3#(z"X˲hk2Mo*ƾ]NבB _sNͳn  V!xRLDGh/vj 䡭/.2Ge,nqCŽE2zgr*r+D)FYE_Зq:"@:˧T6xjj]FR!oUizo9) /~B摖Ċ%Q}0--(DH|q2ܤ_ c%vt/_X|B ~pWRr ʴɅ_sG49h(ʉEDmGN}@m 'ӌ45}UP{x7,!M׶:-+"Dg?#AV.w' RP vЕ;!f.&m5R_&!T'`A! Pv_:ҏb1y4 Ef63(T65{I9!v`wU-9v1`4xt)A}!6rآl6JR9Zo/~XhVs8μ&E4ȔɥD&a% l.1d\ "8?0u{% {dƥMnT27.Pm geD+(ܫj̛C*8 k׎v%b|u df[L`- U'3}gKSGd_@\"'˯܆J0) IƤ2rc˰r*ښz"Tm$IYorA }~!C`F9Sp.uyK24Juma |z9^fDbq fvRA 1=L=7b- H֯4ڻP9têېkL/ Z_^nd3ct-l<Ŕ)WrtVYkY>yD#nS>O)?˭ 7Ϟ93}ڋ6: Օ?ևQ+ 3GF="Xi|<=7짖|hKbZʂbv&E֡~ӭ tF pq(4~QW4\6~> K̭ ^ w|!,^7U\pyUhWwW"?p'sIi}Q/obRnYgWʣ7ŭ>@9CYq>|\K(ku /E3 nO^~0p_ypϺ|/@p<#ؖDkZK9yϜ z A$R#RN緋ϔ߀k>oQﭗj֭~q/} G.WI!Hl^&]fiuO3[XиYܠ8TڻrT=i-Chn,3A Cc GPSN}qkD *@VM!W "O9yzۋF3Z0,q#W˰$zϖ;2'T7EdAHA.1|{x데?#/8|?{]}PI"'h'h`75APg͘5N& :|Њ^k` ef'e :5补.Wo\9dM@[k.)?E3 "AK+aHd;nŪG)t~k[g w+ Nl#HE#fbl<|M Gg2Pp9D ɟq  pKY,%v<~X}3gv{OM.Ʀ1cNC NF@;D·)S=Tsº@G;6RBps{^3 0ȟF4W_W53xhm,Mtj{:WnΥR``wx?yWPIF!sbY/_FGS ƺ˹\7/|3^{ ud2F IDATmGky=Q+ Q#V_;3Gev!00N*+ߚrwec`L*hZs+k̭A :3wuUa-99XA>٬Pi @}E",6$VX :=?57#ehnd4$8i3Ц B>8EϕT3PĚ-ڛ!BPu1kE՝ $(1Q>?U.*lIt!ʹi 5r\\.?SEC[?8Sjf٢s,g Y.]7D*f8~(BA;MhH ?GڅFN3Vᛋsjae?_ SA?oa̲;:9.@$ۋy>&^uubڡ$_"GE=!%e% fM @})!`ŽVǪy2hͶ# 3i>-˽<ťODJΡ4 $'PuD;eKN_O}՞mg;mBs+L%- ɖnEP4דyuwVbJfC429K:ͭU.HaA挘՘ T]M/u_OS 'ƒ$iȜ$6aQlBo`G$AFIg'+ہ1u\Ol:{~1 1 ,2PZ˚c1X`)݆#G:3:@N-Yb$LJ>5'ވPe/AM\% _2n-8t]D,n2"nmke%åy+c*tGP)dyJ . UZ(NsXr x{ 20m{ԬBI< {_~j'840$ I/'эh:ӝid c 5YaiJc5DЁW+?]͆(!iuc>lp^l+H]H T$YOm$K$4  S i$KzjAOPR+_ʹ6x4O)[[S"؊l_JRR:/=6Q!fKʣ}>*FsI@HgZpjCcAWis*,=\,F&zJZ ‡p+ C.qƮXw֡ }O#'9czLմu*%}ᆣ ]>wkq [lP1LovGx\C.-oem挂nyphtciI3F}_2X9٠ fUǹ+o"0]&T`"ڔ"BU3? 6D[gp ôD ohnat[ȿ-u;u薕$L 2OPc4UYK%h&##{!ɵՄ{} ۂ_F2 mu!.Y M6AB~Mb,O#i"]bf HLt2;(67@e*+-B&Ѷ"Y@CPx~L3矰%m ugfKՆ CZ%iWǫåz)`dmiMGy58W+X 58YBnAي'0йAKP1VwFtAbV%ImEzF;x$r56Xi]:XRL`ԙh;`.24WDĽګjwmI?UCiI*R4171yiQUp=8Kyթ g#Y#Hgu@u~!PC\ !׷;gpƗH;`z)MNs3vʃ`ek?uzMܝ%:H~]ۻexEq> #C m۝hXqk{zO U:+whiv!\!Nv> N'ցqcr[ \t(#ԆK u_d!zާ@@ؚΡNqA5#:p*'Qi6bHn̍,BL"Ƃ VW9Z{ Ϣj+2xڲbcf9M#!BPiNSB˨6ulp) <)fWL;I4N^i-: Tp6 ?q{Y ~7< }C]GLŢ/B i]OL/d>!n_eݹ[Ev"[o?iBء*qagw*4ϢqVR;w3m`/iuGY<Β晵;[eΌ~Fit+{HobKv'[Q.3f|p}C["HtvL-ubGv ~kƘ@׈Y]k༧̻mcfփ lơZ9 g )LYK wkt8|'BPPU_w[aY+)Pg{vo)AR$5I#v'tC ho\z66]?b =iP+diD{30@5]:3`n>XYimfNz"_oۖ1`O;%0&\uO2ŷ;~8HGPHB sɤd5Nu30 Z\WF~lvrjҖ Mk5ߊDQ]Yg2cOOAm=:'Zj;o{x{;@*MTgT}sM!lqv~҉kLj{򡻟whbkY/kvm6YvUˆ0PhE+MP0)T׿-vd<,o1[D>kj.(j9qJ2Dia׷SvHq ÙL$,_}8A$g7BZ dhA h}I3 52(J;YROASՒ@.$q#% xiN{xߐ8(NUWwWM3e WzyowXWâx댵YȵziV͘Oq"*]5̍;?t]MY R7nΖfLŧKt&Âmi& QA;?B5Z#M$ >FCS܁7w/}a@ i.3gH*"C:)p÷G"%,6,7ڦႂvZ7l׍5R0J30,b1_~sUcHڎK{ig9չ&j&T@y4ZN2rN=׋!#ӳvXZ4Yc1X0-AO="`1OH14涋`=#WK%`JmÑ)^uN2OؖvTe7. OԂGQBRjo&HV\_/H߽m۾hb)QM _6f ˜lCZHKmE Y;*z -T^?UGJM'}R5pKMP JO'{4,!O5J`ևqbiIَ`EߩwyyU3UUj"+Wbà7|=yZH{!׍Z?aS}e\]Y"]UdxZ -u)LI򌁱'Oj(v4+]]'k4k7@ NOjp@\v(B1{G#g}t_،:G$A wn v_|1+A$:xB{7 dcOdA+~*=̄mY i,P^Zi٦ /L3bW?Ṗ;4/νYY<32\:; uAV\̺_՞+b%2AMRw87 HC{ܞP2ad_'2QHJׁvg WCE}֬f1=U/;E$!Ȃaʷ-?mZ-y o߾0qOx8@7aiu_)|Am dkQuo~V(А|\er]E~wZ:,n}q"Um@ZpxAb Lmژs۵5~ɯv4Yق+=~u |՞{^1cչ~GR94 :[U҇gik{Z{~A{Zhey=NTMJLB1d''i 댠\RF Ř_x<^C@e3&޼Zӟ tkŵ`U}\4oխ/d26s#mѦ^v{8:Z3jOe"I߅W^kj[^X M$yTa,8;RJZ<|erW.E1ˬEQA%bej N۱; K+o:PtԥS Tk$>4fTZW{$y!E;p,zb?9OԢ[JZ/}-~di5S=CPErY{ܦ @ <AG{@s4↧owvRC QЦw10zfh%,HJkRq{7(zݢXsGUޫRآۛ?ϭ܄P hU1LD׶́Ifj;I{P?GCv~"FnB]f64K $RHF_Z3D@bcO}77??N U{t=U7gnkeKh,3If2D&,ADd;MVPI\ߏsg#?LFnniu6u~ua;Bfe8+S`Z||k{o_qxfMe5Cwof)A$(j}իe]sfx< Awɮl ;Ƀ!Wż>99~wn>\mᱍtהvGŞy,#e4Zq7M #*vJb=^r-o9?B,4>DI~Ma^@O Z>Kh=҈x ZkxGZ4 4K72f:o3c@eLV&I+W3̕p<9XhZ)S_}96Pxk\ΝmM&zo%u߮l ~%wwqe`J||&SN- >H YAΖI2d MiabRfdxZ,Yc OJL'OyF*T¼N~喫2_ou,Aa} @a筭_4sQ."zEM(xuOǷ]q8wMϯɝFW} 'HWх%Y419@sգf^ 'N kz6xDKwD[_IZ 6a=9t͜VvݹK ={:;:: 7M劧=wOmr|#K^z[ύJcۯF:z_iHbI*"݆z'XhXT-d*lihIyʿLIኸw}'?Wx#. s-w=C} *%gzcm+/ ;B.#މ*SSe/Rn~7m-m[X. ƽ &9(T4bBm3IHvpP}`Tĝ"}eztt᧡]4E*ZGCGBB> 3W~#̾s lw,ZO pi axa͵:ӧOxͅ#6ZxaHc`ƛy3 K [ծܻ3?Ri)$3:HdWC#o%PD9 /v2ѳ3!`XJ} ZݎxVZf̯oO^ | GyyS(r̚Cd!R9U⼶8݅4m/w&$>fPYQo^EXg@MqZbk|U'j4gl+/FGDbYV1YJʗ )ǯb@llf;CWK]G'?;igCCAb]gggWmЅڍ[-{"|u$ӗT3N\YHdoEςJ0-)ٛ@Idxs澝^TbzpgjV$ HBd;X nq&Q?cbݼ=>}JM.&zJ0?w K-\sN :í_Ƀh4,DH~E/me;)ʴ&HZe?e2 7pkkkor3:8,$btext.ΜÉ{1k';ȫ LiJS/_s^˧xZ~D/cj }׿}fg7gg8Mk:9;8{$k.Cz*4vk$(U[<9j}^ W\<3{&l$ $C]/{tB~Pf0tLBHzoa݇(I<S8uDnp->- #K#{<,iίgp—3gsG5m\xTn6@a$P' նtW;eR e2>啕aERdoF|._Ҋ,BXʔ;2d:}v69t{<-ގQz; լkܷ=V3{o=ܳ``ėN|g.@9f"Krɗ]ŞJo ,576bQ. /`G#5 u-ZSs^چ4 aob!lZBD%%yXb^(u{V?a{4v'6‰cjԍ/~`Է4>~BjqϽ0/z&<2ngwĉpI =I.FTft7>T CS$ObT_5NXI,'b ?Gf|Zc͓ GǏaoՉ=s'6@D4AZ_O\[ְ8o72{+ϬYnv/?sЗ 2 xqy"@k| D?AK# f^4!2cV wנERI.{ B;^W9xao}S/>v;XQF01L;^hCKc]khMe@>#. 0GwLn(~RL:-S@nE0d\ 䞩r܃92f=ܻI#*CM^j$T.U*r*֞·w3L.h!{w3ݷί+:VAy1w tށc< e-Hlj4$˩20 Y=񬖥FlNy L\_) WjVqO74NK *Ђy!)2MK}epώVvsT^Z >73N޺'tbCT(X 1pq |Om= /Vz ^Nʹڰe c"TB /Rpo&AR Dy^tQL6U^dtbӣ-;&$ԊZޝ ,'zii}ņmʯr"fKv.>6$$JscM9= 9i/<++Z4<$Z:qGL! [:oaIYsFAJ?<@ԃדnuJ>;Ҧ?c٘؆4af4N}TQoKt 7bAATCN9+Y[C˵gmz|tLaqޙ7hFwloQ >q+ M%,Dv,}m,<~%?n)rk0Wg3Gf.OE_z)M;d=Cݞi"<:ALGTi4UǬm~hcIu"E2;Ll*UY &k$C L2*vA_,,Ό-b k抜o.逅?Ui!@]?0͊dO Z Hm{+&2+#}c*wO&ΕH_ND7?C= q#^ U"t@5Q1ws Q.fUA5b< _@~R{Ɂkg[іܳȔޘ>Ax^*KT< klf)A zؘk8%B'ʋ-RVr7.5oO_{6p!{ʽ]KTkj-nM:?֩V(13=D¢0KVi?tY'\O% j\ɚCpFLKZ1` FSJ̞s66{pb?$gU=vSR|ۣBÈ[uo9yyQ$Lk !?Si6o`Z+K2^Vm#{W0>0L% o~2hMl.K!%@*u: (Qp<š]^x-:d,LVV1x1:4ۦ#|mMRЎr C\3m]U6w_zh|wsgf߻W iN3 :Tt[ $v;1N$I!4PR\^;Z X#Dm>Ҕl%# vA].W\zB x6t v-z*ugݞ?ofe Aj:BD菏=o739XVˠL0F;'OO{CnwK w dBϓyJ~"H]&`@` r`r||4ަ#xF)eHLP5q1'Ο 6ɽ{:<[9[y;ׅ\.=Ir2i Em-E-oÊo3߸h0hIW]CG_OG!Ԡ'TC$|K$%yS PX=D@*<(%Vsh `ܥ߿LgGϾ;Zu-z%@ X3M^Q^2ia4/1q^N0Gn A+3/r5w !RHD,֖y<}#hVxbY0 L8>A-` = hU{˥2} '8Jrg}^rV"k0\!'ʚs.( 4N @̊Gx1 ^NjE1R+xolHV'x!PO5?tb{DpE+ۡkrmE,: Db3)Igӑ3lcޙ( _p00PJ}RP /paf2ÁPt6CJΰdq\P/J(ۖ :bK+ځo-!+?²^٪cTѧh9@ N1)Ay2d'anG{] !hQXv$B]:Úe^[*c(lOQK#zi 狘D a;6HhZjZ7tW!'V?d}iVR^ghdd?Y# ):V9a+ibwE _%c}Moon@k-b)ՐQǘ`5VT|bcIozC:f-F="M\ɓ+2.ʐ;S@@` H]oږ:퓌#4C$ߐ_Yt|E5i.c-Ot Ak,Q|28FV,ay,\ԍuJ4[\ʝ6\s\Hd-> P!FK>=ֺ nWwH-'4wLk[ɍt4HN++^Yfsh;yG*Q;0bȏ]I(#{DQ0 =\VUH"j?g"'*qTuQHѭ ,߶iK[bށ1rK/ oHz[6§OdP+}+[r ;P3Y!XOb6XO "Tդ4q@\DV4[hϢ򆞻1%݀z( -/l8TvK΅6Wk o?zmmdvW.Cd]W60 @M8*WBd I]olm3رբ{A +MUihfXMpa=_>nWIbKQ]#K6ydntB_{;7ݪ?* X!~25Ub^a7'iӦ=B%1K40H)6O,ж!HLvc$1 D%-t,mbxlBnls6yݳh4 w5W*8tbqoq/CTj y %HP5C1S G1sWHQOQe*ާ 1W3ĭ:$m;K맪J^k[\Wx$\lO6BjXDgt K#Q Wg\a[>*F]wdԈhGiթg&`--LITC*h=&<\Wsawnz7t3K=xplwY|u?<9E=:}\V3py(FJ@d+\nIL1+j)_d\[LW0YuELyP&#\0`*#èݴ͉n?"%@**cJl`!=9ƚW i֮'CX [.n.4ΌpWv6lk9'z {s`.2,BH]1Ђ馱 `#]roSP=NYwV@9` .jXÚI><"m,eYZX h.`1Ӟ6|2fwod÷֞K |ٯ#\ep{gs}H`Gzp)?<'2,6IvF+V@8"f"fjDVlEڷH2oX'oi >Naq+]R)S0Aߊ{Ψ{.f1iF˦`vC4x׵~ o Tn7Z}͙H`x>P' [(\dbֈTw|4%;9/Ў =v^xf}aN&tSE^`Z)/fN2[tU_{# +4 g<hӍI)\w$Ո8EJ݋JfbȮxF嫗!;vz;G>nsve#]  *c(dg5֦D&H!L4Zڧj~ MkВOh:1C?Z]8{bH}2jGY:%gesX :U!5/dm=\gxD0.ފ_V).hP]erBSRF#3dw.=SK() 2%ż@گjow~< к1"r [x fnF6Bzv 6#@ g:\;?hVHtf^CP+xFyGQt1Ua2& 1US 64Wm_P&;*;\qIƁHv:fMt$;'XB!<S>g>U V L.[PUkb%] p's,:<5]֮T&z]&8E.[Z;.zdcIJRocΰjIc^XIO,b5/*٪b S\C,:RXA#ЮD"%䘮:'T݉8jU=SZR?I~"!H׵izW(f:1wq_/foq|:k Eb&K9#}UQPuL| /k1[)g H0 8^kH^d{e1kJ-R"ǁa:E Z H C9ݵ>3ЏBklNj̅mG"~at5͂R=oE XH?2L3 b:XBF._:^ggƣ;DHXJ*sԼuvgFA_1/[Ndd1-n,p.,@:D&fFnQj zk ٬ @+n=o9RY -V*alxA\$ m,0D01:a)DF? qBhB&:jˋ1cE,W=cA5ջH1i-uGuNLT4D}H-0E gva;Gq1}@4ݿFtp-etvs+Dc3JY7Y-}M 40DJtc1wR=젵 U晪դ,13GqX"8ܥfUXGZ1u:﯃m/#]p\o])׫I<k(Xe||d UC՛:8MӿeTՃxe$DBS֥$8b4ΐTNw829iEZ<]M2h S$dH,%{2b[μضԩ*h{ @ 7""NЇQp6M.v"!0HZ8"( EJ-cPW %,p ov,ñ:63h] +Ņ @g+r[RB@0 ?M3dscvsv3bu kcW()%vJ5}a4fkML(KQ-hgu[bo옫R]rRÝqכb :۝i"$r-zelH(4E"鹔+:<5YM @abςf%}$sƭeްHih[M-X>0h,N]oM]\rNgv@;ץT0Xi<'eF\&c$ L Dtޞ *\C !ɯb2~ Uܝ;e!i P"#a ցeSArȏq"mh餉\#ܾ< Z!EaOhGŌi1z犲-^Z^ۓ$քNX;0TfƊEqrRqY Ѡ=7\VTEEHPA;=T&uz 7p'Y Ȁ]I]OG؟&| 3BxXk0ƽ_rP%k8n]JC@R:$)(dxs ǐuer!l$- Ǣ,u;eVEٳk-Uy*`^&~@YY8 }p6@p >^A4bT\@5*"vb>P/8L 9muK^Thrcb]`sEQLa7_s0&=\W!^ѤcA!\IH$e7~+Uͬ諢 3z"(#cG.LX'qޑo}l,8kk>/V@YV  &4 י8u ?zEJ+W_y]Ѷ'}?f/کT }IcܖCm'7z-J Y8Ӂ=Tj+޶b3>fgr5wML-UuX\l ĩZM}K_F?1G0JKH'E$Q}#XWC9'?O6a jszh͠wEvUT^#;#Ou' cl8C^X1jVQOĭSlNbbdOm.]zbCnhuC=ed|glg>Z F2-d r0f2w MZmqZ7yc64rfw;lU=_Xo@Aҧj殧eij]?dF^.̎CNok@OX|%3qPI;Ѯ,Te8>͖m-R_d9iיAtucg$5#v/"EҖ Wj0 X]/_x/쉛q)eU4iTΪQث F-*HUpPcw4#&1b> YӖ^`8ˆa]ɐͷvP{+jLдbH{':3j *6ކY\ݳMܩw5맱,V CgFWlha>11/ 4d;ۏȝhUM#}XIڶB6zF/Gf+`}TגmhH5;v/CP8jgӯ)*Cggxdȭ;'bʆŴݟCuq.PLa T =u( ,~͖=m- M 2כ1>X&=4sVz]-i6ݮ'XAF +!+{rQEwj#߷.v03-Ac˧` ׼6V=N+Qm]:\5%l㲑 Ww-_'.'Az,=t%k }|d0SlJu/U y+V@x%(8/w dcL:z p 4 _@O% YF5--h@AolA7ס~;ppФ|JgahO r  `L3Kq\c}qAy>j$z.$‱2#wDx!zǩ2'Ҩl5XicE]]+ NoIE'].>>(ܾ^> _x*R,SGP RPM?(_ԫF]@#++kV̧mRЈQd%et0 2AT=4];<WϞ%VqӋYW8R+El%:MJ-P_t3c7RA+{ y%$`$S-ic)^ߠw{:|} ZR*I ;]{-vg{ã9#ԩ7^w OTp?ZZT}Gþ30u_!؛椦t]>S԰µD:ٔnTtZJ`Etd=amo=߼[d0ÀͧNWS#4j %H~feܺ(ZRiVtdD 7LV5=";煔HtjÃcGF4qt<4א\Q2೒ܧm6-m_L! tЯ!MɃ fИzvӧRix>?p!h֨ ډ{@XaA7մK}s-zj$^Ӳ>Χ: -mGj'zMF:AnD}7]l\x#haޤf _;C>?#ȧvM^tG^/ [Ψ.; } gGk+ eYTӒ/EyĦ)V(<9IQCut^EhzQRX6{jߎH7Z.&OGlհ)9Z>kv [ u@Cj=uv-W^\>I63--kkhk*y0,&hLYX_nޤo4W[2 jo2 Ր)SebQ*;9*/R8M8[y& Fdavr Hb~; @E~Ҙf8"Mgm|nY^X ~Zgf<Eh÷/Б1>Ӊ {u >={:(I .DÁH,T["6h^T(,NI߆;JpwAyۣ:Ҥ`0İ:ӽ놂X=@(EA%Z;i*N !l*2I zˬЙjxۗrl @p2Ƥ@óuO>dK(!f@Ej#mucK0-뾥x%D ;CI!  (1 $cԬC։D uomETSL|&XrJ1;Tj2[ۤUROđ`qW{zihz }P[n< +Iա?Zp">6lm$GX{MUDp _ G\G(`K5rUDv@;*C/aB)EiD 8W}QUrg%X=G/ /g&Ƃ7@?a񓬒*>0S-ƈ.]uP<:jr VYTWM%&$ާhQ̊zϞfEF7iJ鰄-sT:I\yp~3~o\7mdGh$@i~E/̰z+%U[TxхSW  iO^g$)" >$D\o{Rklk̥ށ7@!8h rd6dPDыɘ4jM*2-Coz 'QEz6!`8?,.`iwXVD+nˣoi(z ©;*#/+pVUx3ZEa*Qߛd!9}|-lCruXOg}v^=n|d=/??oR Uß^k8FeWRD|L"h,';.^PYW|p6 92%{#WVYT"Etk79@b*Qs/Eì*A!Dbb?4O?gQAiinj*[jV'*WzJC>'wȹep)7YQqkc<.'4؞]8I9IFc)cܞJY Hҁ:sr j;fg-< 1(wd[/hfk."|2h_|GB`j?ww05pqq#b_\NN\t48/]vx!mڍ̊xc4/XBVrbLR6X\e0 ˼mrHZᘳ1=O)^4=[7ZM4!junrGHXk[cs/@K#;ퟗ06Dž;줅.a'/w(XcDNFM9z$UIv?wHdꐬt՘;.p0e)zVQ4MG~Qwh`\6}䇍h.eO);Kd`@J0ga /r?D=Ms/s; K%3/P4'?;p廀QX Hɖ><<}e,idZl\E'S-ckܞ7ﷃǿ2[Вy.T* AT g"ih3娴kD~r)Kh'I]g筨xj[3p2F YR?!c~0*ѺXO; N2ucԑRcIk,aP_z^lt@g@qwFTp>mf6ϴ\fM|7/#Kz{[96I=k%JT[>\?7Yf!'C r_,wS|歼OEŇ;4譑b=#;t=A?q㽘v0.nNf7z@Τfk/z2;t=WOR'bM$6vNuf3 t,Na n"/|{yV0-h6`eSsV+V0;0ƭZQĒ-kUOi}\Aką^s" ~9fdj6ޭkfCw]Ɏ R |>8d)eq,k~JกTܾ N GcdMpל[;{ 𓼚 g1;͎NA>a[mPOcG/i==!U[O?K[=_ o3E.s س./2 P?bi]rܲ(u3j ,FPwg:3;$\P^z"T2^e\]%^Ax jChc 5zRN'Ln $b!yb<o[Q<:]AAAT)=!AQIsxzDqz#hN YդUL,(Zr,%*R&. 3B֖>$ҞoC^6C,㽠`/Z Wz~)'~iyCwKW B2=)hVśt>SC%W %F*=Oś7w7/ v"npvx&a宍tSᾊN#+xilH?}bS{Z cJvr:ӉǷ.n8B)iߋ=w՘Dh| s?{Iح/նYfRrVMM9g4tNړ9M r&d"W=2MRs}h :ϯrsHm}wB'd̉08/6M']d!Ȧ?B!0ޢwߞTls݇i^tPI |%ȂCbO} = *?Ž(8V3MuO%#uF >!7o\ 6%A1T;| RwC <`X&>xgQňǼZ<,S"\9_ŠcX=r"zOcU|r姱f',K`1 jpHA*BJJ42Tڪ|Bmьg(/ˤO2``֋92=/(or։yM̿-V(YBJ fyuS)dgb.oRLV)hC`N#BY/z19je12CHfPù 4Qݐc_sm2| G@w krO#jޞX˧4y{ӝS֋d߾Ƌ2C\ ᰞe|vǜ碌Ojyނid :ESze|h-l E\h(s XP%(eNtpYۄ#r\ |:=}G U/n՛S: :3.Nb%O ZۺW/2FgDgT<[,=j7^V5vz&J#|Py^dg>Cp;EY ΅Ucoo(k[йhEݳ`ڳ#+gA &oIς+*21 >d͟ZёwpvE;a?sG`'ߑ{ ;ZI^jne玧P(8 z޷ !Z:䨾>-ںQVw?B TPOg7f͵^qʯ|3O ϔ݂Z|H6WNѺw=%g\qB@HC&H JLs ̇Dy&y) #cbS]qS:?/mmk CIa$L,~gt]:IsΩ>bj$֊1;p*2{>OsAp.;(qҎqwEmɋUZEj,=0ttf{22ag$?<`$OJ]IblӻĢ̶pqpܦ1 Rۥ*wqiks8y)0ĄCx/t+>g'翷+TF'(91Ygdo<"{|sK\=Y 'R#Uh AbB^mϕg^xto`qb)PL|:eI|?] |R*hSas}ܯ ~l0n4iز`{0%Zw}i?̾Y~\UgoGIENDB`perfbook_html/img226.png0000644000175000017500000001261211672746137015317 0ustar paulmckpaulmckPNG  IHDRX- ZPLTE"" DDff"̙3''gggݦMMM'''D33hhU@@ fMM33wZZUUwwhNNtttZZZff@@@ss444tRNS@fIDATx] cV`tko+u7 $$r*BIp@>GX HQ'bb^'q^1 74.zb̨YJ,I,~-9X/ǞN/W!iX.IZ,ЩqE5Ûֱh,{+1b!&vDYEy%boBLmjWYEUSGgĥ5\X' :^zx8bex+ Pj^eDV7q(1wJ삽P]P(<}P]./SXw p,bñ. ø[Wcg~-BT8+*KZJs^QizMc'_jyF4Pfg-y++QsqQ GڑVM.ִ*ySI;t蟷T6àZf-@-ʽ]0;ҲvѸ&mmfZ&MTT-9?pIbt/~;y >뾖m5mSf. ׿BXN{eVm!Ũb0Z=_Yz3C=IҊg_EfK_H9Yv+v3g.nhah۲<;O^jbBM9%Rļi3P!67 M}n%yżnaMڿDE ( e&T {:EsN4O-~hK;1K'g?`Jk뒢=w{,? h`Ӻ_Xz+ޮ6_| P ;t.h wEMvOlhr6nr7rh%iY9.:l^0:@''6-W@+jS@{YA(kn*]"_j.tEKOeZσ_(M h2ʤ=y8ą>/qJsܮ"RZ~ϫ9*!i*5n!q qqP^l1㛰 ʗȦ~B,;6V/6킾ذj-',ȀK[9++Qlm5a%ZZ.  oMp,K?F*-n0mTDf[t9c5iu,6& e=в`D %\n9B_ȆvP@;{%̹->K;J(Jjq #\L~{KJͶ@O't+DhFU|Ap:/Rp $ ,!V^q@#dk[?byDB?{.VZRCs(ĺ q)i>faXA(Bi.'|+", #Ny֊^]~!Iѩ]pݳTuW^,{lQ-w] bذb֨\i; iWN>ĂZȕ+/*CZ.Klo .rb.Xẁ8i[s/=>R{sKB}1g=Ҷb>Ѕ;@xY]u$4 Fw _vCVl76l@![a'{_Wz7IRQ,Pt;ZB^i $yie `/(-̃s\!xb`Fb;dd܆ []h0eoI;JVmoD gۗa\6RߤB鉌IMBK&Jto/+֊Xiθg,Ȓb?g7Y9b'Нl\\bwd12C@b5;IWa:i2-igg9{E>}XMvT5Ҵo?gV2ZMls}TXHBZM"4X+ƋBZE,`ZE%UP*&uRR+X֔F: Vԅ ɄР% 4 Ҭ=E*IJ֍3ϊZr IԚUDab[GSES`\R頤;<UzG'82Q@#mRx0ֆ#k&v ??]Ŧ#? J'8<}{|8$2JH Z0x+އFZtV.kbK۱+&/HX,9b8Y/N]v\-6,`ZiAIbEF.W!d}[?? lݿX"3Sl x@{{u޻b`G3gpN,2 L +X+֊La c;b ~ww^f, e|9't73vUA,{.kZ,gV X^:MN,_OpNl]\۰&5ն8%G6IEb#"!b(iVR]ȉ!VJ,n+̭>0Kl2.ʜB*uk).P RIipAשĞThbrX2Nd|ZKLL>yP2 $0^x-Œ$1PKx-da7 5KsH:HKŶ}\h.]۳(y^E,*P ~*bk~X(b(ډ s}vQ HPX9Z(k|6bɪTk%1Yl㔳'{F b0bq5 \tK&Zf -XOuHNlYZ.P +82bL'CZƷ?XQhP hg-IJbxX)XVhĊ\LN,'Fz; R)XV++ m-m'^}:\2-M?dm4yTM/̒zV[[xgn"bQ4eۄi|lM[9*T%p :Ig^%LTQ]l4ŸkJb0 kZ (PCR7^J'_׊kZR[mUP!ެU%-P*ia$Q(YB,پVfFDIN}R(VW\{kʟõbҬ Q"6M[|>~'֞iE׉V[bIVFI5vH252Wr>hl9+kJ'֨Q3Y6@5'z (~=?LSrK[ ؓc64J~ı#W<^k8K֥IYLgoeXE}5B&Xc5 XMjUמ4aaՄz 䚮$+*^1x1s! NX }#3. iPC*'(|!JS}e0ʰj͆>2Fe,X5~zE p<:{l 5b֨j@y 9!H$bZc2GijlHN}2x7<\ UZ*9*^ЛȋQ[c+X<R:+1XQm¡rXC6 "墋C!士bEVsHelPByv!56645Tk>5$R}0kI`XHAM9`ێђ9XcM"s<ƚDx`5T|ݼ|^z#b4d ;O[Ť+8SI%Jm;'Uy>W~cl؉t##핞?C9fW˱3IcHN1)\';>|8"u7ت'u塋7ϯS{Mٙ*ml3 ]Ւ8ng]5V۰dHwn[9XcM"s<00Thc9R}0kI`XHAR}0-z Bx`5Tk>5$R}0ssbu[QYg3K{Rgʆ="kωi;7%+]Q$Hu4c ]WݜpVi=smohT][Dhʆz-E4ZG5P^~NY8TP3 jW֤ɱS9i+ϩTW`Nꖺ !s<ƚDx`5Ti~/$S_IENDB`perfbook_html/node193.html0000644000175000017500000002043711672746162015655 0ustar paulmckpaulmck 14.2.4 What Can You Trust?


14.2.4 What Can You Trust?

You most definitely cannot trust your intuition.

What can you trust?

It turns out that there are a few reasonably simple rules that allow you to make good use of memory barriers. This section derives those rules, for those who wish to get to the bottom of the memory-barrier story, at least from the viewpoint of portable code. If you just want to be told what the rules are rather than suffering through the actual derivation, please feel free to skip to Section [*].

The exact semantics of memory barriers vary wildly from one CPU to another, so portable code must rely only on the least-common-denominator semantics of memory barriers.

Fortunately, all CPUs impose the following rules:

  1. All accesses by a given CPU will appear to that CPU to have occurred in program order.
  2. All CPUs' accesses to a single variable will be consistent with some global ordering of stores to that variable.
  3. Memory barriers will operate in a pair-wise fashion.
  4. Operations will be provided from which exclusive locking primitives may be constructed.

Therefore, if you need to use memory barriers in portable code, you can rely on all of these properties.14.1Each of these properties is described in the following sections.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node164.html0000644000175000017500000001503711672746162015653 0ustar paulmckpaulmck 10.3.4.10 Summary of Toy RCU Implementations


10.3.4.10 Summary of Toy RCU Implementations

If you made it this far, congratulations! You should now have a much clearer understanding not only of RCU itself, but also of the requirements of enclosing software environments and applications. Those wishing an even deeper understanding are invited to read Appendix [*], which presents some RCU implementations that have seen extensive use in production.

The preceding sections listed some desirable properties of the various RCU primitives. The following list is provided for easy reference for those wishing to create a new RCU implementation.

  1. There must be read-side primitives (such as rcu_read_lock() and rcu_read_unlock()) and grace-period primitives (such as synchronize_rcu() and call_rcu()), such that any RCU read-side critical section in existence at the start of a grace period has completed by the end of the grace period.
  2. RCU read-side primitives should have minimal overhead. In particular, expensive operations such as cache misses, atomic instructions, memory barriers, and branches should be avoided.
  3. RCU read-side primitives should have $O\left(1\right)$ computational complexity to enable real-time use. (This implies that readers run concurrently with updaters.)
  4. RCU read-side primitives should be usable in all contexts (in the Linux kernel, they are permitted everywhere except in the idle loop). An important special case is that RCU read-side primitives be usable within an RCU read-side critical section, in other words, that it be possible to nest RCU read-side critical sections.
  5. RCU read-side primitives should be unconditional, with no failure returns. This property is extremely important, as failure checking increases complexity and complicates testing and validation.
  6. Any operation other than a quiescent state (and thus a grace period) should be permitted in an RCU read-side critical section. In particular, non-idempotent operations such as I/O should be permitted.
  7. It should be possible to update an RCU-protected data structure while executing within an RCU read-side critical section.
  8. Both RCU read-side and update-side primitives should be independent of memory allocator design and implementation, in other words, the same RCU implementation should be able to protect a given data structure regardless of how the data elements are allocated and freed.
  9. RCU grace periods should not be blocked by threads that halt outside of RCU read-side critical sections. (But note that most quiescent-state-based implementations violate this desideratum.)

Quick Quiz 10.60: Given that grace periods are prohibited within RCU read-side critical sections, how can an RCU data structure possibly be updated while in an RCU read-side critical section? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img271.png0000644000175000017500000003622011672746076015322 0ustar paulmckpaulmckPNG  IHDRa7iPLTE^\\\ZZURSQNOMJKrpq# b`ab``mkkcaaa__XUVNKL856iffKHHC@@wuv.*+[YZ|zzApߦtRNS@f IDATx} *}*[Y2pP09ǹ("<eigE )5+5AS=xRZٛV_tKkRi l@_=-Xo3xW(]{.}>p.ECXJaƝM ϳUYQÓ}|rhB58z'큱gn FFE5֧ZeWlh`79;7x>M%k-YOY+||! {Mtnvs>Qfٖvv{mo_3-Tl2Dd ~z+q|(j/XPGeJwF$v&-oG;`wh\+NJ1vF 8CK&ށ\QFGxooS-&-ky>bo2f S=}x"DLnO6FlKY9ޗ* ,r7ljukc. `I Ox(ҋg溝7urCll}SkڽD.\!L7BXOe1$/3c(ئ #)q8c`"uU:MZpT*[ݠ?:ԥtFgmL~n{WAZ;ż'xg1ѵ8Rgʜ<2:7c1 Drqzb!G UJ%S8rv8a^TTTz[fGz 0Wȸ fУ)A+rr`7 1u3~ظ|ϩ~En> j`j7X-E3+O { {vצwgXѱ?γFlO0#X\tvo`FumoV8Qŗ}Xt7? ,Z~9uF~ ؐ$|*3s4-eժRu*Ѥ)199Y]&wM ( n>Oνd6MfyUZ8piM(m?+2TcC}%$\H"l1+r@aJ =PuQp\fEl\acF0P1og*m 6tC jXj!43rBͥT=މ^</O`+t`ҏЫǭ\Z԰IFL8_kٻ̣W.+>D/{+5mFvm }ȸzn\2'eŌgd|NЫ2#f?M]):`: xfBK#5[O𼻺L nH"f'B{t$6vF6;zt6]>D*+@?jG/FzMSQu%l"o#z\|_qyFF<,C/.7 u8z|Os>?WH[eZ+I 79hll޻S!W=Tl?eu`wZW\gP[{l&-veEĥ*֙Hv* 6-t|[L3Ty#cS *s;M쓖 .t20Ccw[:Sz[ Y\˫"P0?lnص uK,lZ7AEwpjf!nFj\I 4pASIy[Z'7xD-={qHtC!¼."&m@ 1K2]X:x8uP8!@š7߹~諺_xA wQB=E&a&{ZbD:® DJ~.zkz|ΨK\A$M?7Zu=R1c|a6ׁ6 +b4< \j۶_x=Y={MjCMI.N(PC}zRP7N=f 03,bp)(lʂP+>E+F7>TG?#jg'ljWր }AYݥK+-jQ6bJi;~uqoE7xZJ4SE !f9~s*0FO3M@GS2J 6yuR].Nmc7\ks[m_i'od g J=!˄waTDѲO}+uuD 惁CӚ=j]X:х~Bz}{~\<_bL/%dbD45,Cm Q fHfrbE*1Ԩ:=W3NJ؇Ǘzb:WoT Sg,xV]a5TM]OSW0R'XUq5CYY8d:g,n8SH+_1MCH+⠏17v({pb$=c=dL@(vnLG#$/5@槁"ro׈:VMp̱w, R5Z=p"oa[m;z- 5ng(o@s>|~5fM?~x55%~Cu\R~w3c&AR= !+Y9oW JطBlew[LyU~(Dy,s`\tS*޿&X@m!5]|XKGk >hpy#c.I?Kw^JV0rTHu9^{@k 9MuvD4B@@.խ2mEO ]Bo椺ndzn%e?|,@)5#9(ő ;T/Fk`с|siВd& ~Q\8}(|hp?j3raX8z92YEA, +!kw1bdO?"5OT;p@n:_ 6#",pJ\ųDBZm),K E.Af4 F V oݱ`0 bI}iC NUz&% co+Gc9se8;g(揯2"xe Gb]ZB/Z|.V9X1ÝUr쉎T *ᡎ / +tjhu$9G3^һ[7|pla_esCŪpeû7:Fق@Q"X`:EuG;1s[Uu}74ƅ:wѵe' >7>=p0on!,]=r^U 5&^\c+P-Ѱo/K r)N)WCڸBF~/<':Hv=9H;|ChZMi,խタ Iw1#I=['ǍoaъԒ,5ac YsryT~꺙fT#?FRGL z3lKg׽Zh(e uWFZVc4qx!c'"́i}0k *0[u sP.(cUc-j!A˅X, ϐ㐮y$bƩm`ܹh#P. FSVt2(z +(BS5LJ Ax!Xqֆ$] `0_umJI$.Iuȗ˷ )^ 29ِvޠl<>m 1V_f)2DbI^._q TkC_}[o1?v}AS1?-䝾B4n/ 1Ӝ%(?"sVݳHF!WxI8̼JAQÀcE# D),䣌[l_u&CbFQWt8kj:Q{U Kh̡ϠYR G5Z|UpF*ֲ!ZR]cعԸ:]# rS4MaWxp@_L] k?O9[à&js)A[qw^Q#1sť!9 7!b_ԨE$^t/! -DA`Y D}O6=U%""G P .[M=!,?B:\GDɿn1铌h Q*T\ySHHQ8:]*ȠQ䀝`bPs/%T ŦCjVl(oD)LۓW9 XÈF eֺ/St2+ZGv4lZvgDѕ7uHTja9D/5/m1@!lP28kB`SG wӌ! {3t (6BQ=cLLeX /^rtr ͆nvr^A6T7,S-4K7#EdAt*VGŮ7a?3x+u>E*X~#a9 !˼ʸcRͤ+tD*XbTmaRzg` cö )jϢCp"jrhU ͵ S ȧ #,cE a+m ]}BEk eeƷkʒGB8 - ! Fyy'Y҅pHsIϣ H' EJ8Z+\臅ò=$edMuW"+BduGJ5Y")aD#;lG|S `YyNbV`5N?Aܛugכ.IU'퉆/;,~ou&3Q`+宮SqUv^NU-:ܣ3(<ʬDzP-y}W'Gj]ϑm+?1Rs5+Aa*2 *`mJEVΎ/S÷?['ծ9$Nf3_U;O3==eVܹ)w;ʎLۀ 1}|. [`.p>0rBQw;^}5F{ \JU{ENU80KIȕ< ֡ɈxPBC~` 'e5m+]INUQ'pK.'aWdL/M]^dBd"҃ˠL t*nl/ OKP=OHOT9]>':5if<߫(4~ԗ&FZv E\'%23jON2]"nWsS۪&hOS=}=H8ZwIDAT15(Ť+ǜ3{#R^*W3emr-#LdMT**+Ԯ*!Ch0;ӘWP1~AT}*% DNsӥԉJu~sr!G!3ObYmʉ |e^drRғuEVBg_.'Ka`QuN&G@H6>RO\ s.SIk B2r :K@{Q (Mg 3%r+2ᇤ\eT0@y|CB&7K&t\ MϥnjymBpN |&GPSW=.*h.vٚ:eX@$xau8q_о/RbGCAP8Dx];rO&To+\Sv^9J4W]KZvrS3uD֊Y] p9;SJ|_4wlY+1gCjg\4}4B;˂# #ѤBBD5cw2$SMEЬβ`4Ճ/%!_Fl(vBuO[M1ϧЄ]ؘ*8(o &0Ӊ?%n8U/kH.&S!-YzEyF/F)Edf ?$Էi?U썘Un@( 8 ]gî9S ya*Y=q\Xv+#a aHnrՌduwxo.݂ tѳDU78թ<}= XO0 Pyq7 ;L`Nαb7w#|ӊ]&% L 3@9*Ĩ΃-i1Fyxz!I\,f,cf܍~AN^h|u1.ѧ >+bxn /:uu[i cS1a<7^ܠ]L '鰷h;N^ǃbvM.*5u}Vc殌ʴ)PJdyy#_T C*LvۂrGy&"e.dS?Y{lc,~)TX4,Ry/q"XoQViO{|IglڈsZ+?*{0QqcڱtR4=bʐR>Pb@ 0UB.=;фEJZ{I5tc(O]ͲE\᱁Z@m*ah\-AtcRf-%tO%%:u~K9fVD6UʷVz}Wi2,nq&^q+*VflnVYow/>@7xiEd{lN+CKC|e2E/jU9~|yWIPA?,^kÍRU@婫:=r,?Υ//#ԴG,7I N68L=SQµApM7ta5)DuEPݴWB!)[pہnF'ȏcM*.*Fxp<Ұ("o3Ӻ:!\4Y{قex%T(Wun[RcTk~#Z{krblFΤ) .74&Q=dJ یФ%KEߴJv5):馿F;ֹG9o@O ycw.Y9GSYm 2IWoU ?XH(}7q9OiY'1t $$oj@"*5Vvӥ)#P&Ϛ&a?z4LX o鋓~c,{7 ;޺ȊI.IW7 ~x|^Ta .,#EoUig\xDFbwx9ܺd+R!_·KdWʨ8 =,F ^6L-)Q=!\7*4|oҟ R\w12R,+_0)O[g_j9?6Lˇܖ_CҺI ~Q"ROPwI$yE8(^):ea*@ QNfuQ|}ϗ` }R3R})?Ir6R}jdzCfN[sˤM1h2rCsTenhn)Nl/FdzJ9sv@BǦJntCty3w2HZ'IJD1 R6CIPf:ƛB/-(tU)xu{=94] ހj2my\ӻ R"J XCK} ^ ђvn rP0@~buc[xbW\G|uz/󤉉xf, 5,]NkUWj}gNЦ+b@v+&&aH`S&f0G@ga[>PO,<+Dé7iTd齴m m"$JoffspjYFNƥf4x"OABaARq#Snbd8Uu]@{iF'}( PJiƂassDlqnG4A԰.HI6L<KgCNb#xg4jTW,]&4"!/aJu r'TjxWӺiC]ԻLhY.KlQGK.⠊ݼ_8qby~έ_ic_ֳZQx\k"iMJD%x)u%7qy9 ?c5)a{,|F:2:aas4,G/r dL.Βsxfvu/ ?0nܔx'R>7QenTs6#G0}tM/x>b:!zRU`3\jNɓd=QӠ%&(ܛFs1ٌ~Dո2ć5ɪ]fn#I?/kUMv5#7l.G$FOZWp<!4n;S9,2AHV +ljۜn|enZ: HLu%% -ּ@~-PNk/yD9t!9?,)-D҃ Ҩ\ȹ~}cłQ$QoptI8&Kf'MeWX9$.tXRpId.ƥ4Em]NLa(䗜O#0N1jMĵNj`h'QltTVB^"k՞@ .vuM!N$8L eGtM7q,RB?AoSQ*C&h}΀k YuWn 5?EJ%!ZTbLv@kWIUY@L?bA[ZP`B #l}Տ:qMWyDjֆ 0 !I4^ûlOV*t> VSk}U!Ÿه?xF:)eC F)X-~0|0ʨ:,R:B b{#f=jC3)% >K#01DvE+=EuH%6Hq3?/3I% _00+# ٪$6#ڛF kA?NP8#_]b\9y#Cْ*ڶe`"ƅ) HNŻ[{wwa%FxNFC2Yq2ۇw )pwK0Eсv]P(V NN5'xw;:g?]}ZsL_96++_糲^*ḿ€:s 0jRk=IT8]R"-$ivjg+{d|`9]E084F0\58}R˖Pqۮ @% `"c7Xe7̶%\vC*{cROG[#a9 k- M)4%9, |SɌtDf\jhJʒF.؄4>$^iS ,;N+n"Ox:M.I d}g1DcHؘR&2+ERV 5V&4.A|ɅH(eR.\ʚYl'#4I3ʯu?)IRJ|>5?tae nl/˾&$9& HsAϑ81%-~D+;"1:QiiaI \"D]f}2%Ϡ:Et-_1Q,Swa>9+#\L]DDŽ?kaJZ3Ԙw4Jtsuo]#gno>G{F#."0_/ /.^;rkY[SSl"ছnY&n-IB)d!Y,]H7"MB 'broHӟ n'" (+M%q?o&{ӗ@`"6aRV]"ZBIhF ̊G,zoɁ!u;Ѷ&t;l?B:(4dӵЈT>e3FYoCGXYB8[6P'p9D;A.5a$ PDF0W3 Qh87_*e+3]f2e*v& MEb.xޥFTˎ&@a<K]g>isۉ(4}nhV T2 g!m\9ˆ؄(4'Çe! UAU:,(Nl^lSm]~oRgP I2Kާ4S|ς-&$%s\gёo ^x 8f Uv&(4STydAҨC %&*}$ڨ&?P<T #0i\`{UDAUTQEmaPLvS P;ԛ6=G !C@@q퍓: fV ii(X{4)jv$1L8Y!aq#@Zzjd<фB#&,2 fa60 ~LkNJ|堽3/C2zri;+x c1.DZ0Ȟd9,/q^&ܓFUy,D X U=J`Fd?#y# )vsx HzhOnMVG2#"πb5| <'ɀŒ;MК;Ow{!7&+}UB>Sir2}A$">͢ڤ-+ biaEܒZ$' f7D"^4%: .G\KZ- Hr[#%'A=KzvαqK۽/FA=D%^cK_$"a% Ra -,J@prCBH9eN0Y)wi <¯8U`n|l80ccTk1\q &bJYNE}Fy"^I%+xMS\ !`lc^\HqiI% MVlR7Wu=JV#%4?ML:` :>Hs\}(UثvIENDB`perfbook_html/img263.png0000644000175000017500000000655611672746043015326 0ustar paulmckpaulmckPNG  IHDR%_HPLTEb``^\\MJK# hffvstmkkcaaZWXXUV856KHHC@@wuv.*+mjk tRNS@f IDATx] *͂gYu?$⭵a>Bn*(Qʠi WamVVFjO~BP 4`\7t-"m+7p6ۿ *ԍ9|{_U˔nij1UbԜ=NFu[fb⏖;\d$qӵp;[bE_'X5 CI}ϴD Gpz$vtUP!m@UAJH:\q R#`r uE܎]M t=h_k@d9n:-Ҭ/[4 (1HчmhϱQ ]5s^G* 'J2zw.%I,Y%(%:Y#>{yݚv q)QTې?¨86}P$ cDa:MF({2]نªF H f)4OdUQ:*@D g`wMGo+CG,yP"2&:Nu0m](j%r,5Heo2M<0COTگD ! /h1;ϲ MlR'WGb/H7G(V|ג"R1C,6$85oKyPi@ =Scd] Գԉ$ba{i\$.CX  S\Y ~ϨnΎKâ6ɹ}D*k[S$Pԙ0랪P Bh-1qn'һ&H 8;2a;M$kY}O4{ht4LAMIWq녜Ω ]3nL~ J{EDUw>Ӣ GO,z |şpS,ɾTTCFw0T4tr. ۳@ K+QX^3sY΄OG@S /ggDo4cn^;lj' afm]gؘxEx-kSOlR,Y0Q -F$< H<#_y28{ќ_5x2؈qHBi(]F6G/;0VtZxӽ~qlk{N=8WG$OOawENBAƱC7A"\-'c1yz [%Vgq0dJ21_ XvlƮԳ6jaP&v&d;ݸ::Ua=[υIMx"KusUt# on49%MUI>Ero=ﺝSݱi):bgY?il<̻Fü扈!8Uf=\B@LF\yEl{-1B,w|"j6¼ž |";[xnʑf_*d8cKRD,)ʝɴŮ>S @NʿƏ\u<+g:|XbD_T=g69+Cjy+]pk qOE}J>0<߽p}ShI̤*O ׯ7:an{OB4LZOϴ^v;3\<()X<"r X7p<S)xk}өty$/kF 2JBA+v 6Xӵ>LZOZ/?ej%/k OíKMUeI&Fjadhmŝjա#ywy{KLڽ^Rq*H]cmt鏢P8y 42n+m'Z! qdH$sPj'a:+FfmAwf˩4xX[kBF{4Ⱦ#NT ,@,|i H *]˜PU3cZwiy?]']҅ g_6OLN464gL}^@8C 8ĒԴi[bh8?T䃂$V) aʍljIcwrc,5 6 w8Txn囦zydN`G3E4U1{،/uLyx5&߶O.(do XRngd,F03p?>DZBv&Y'C1]yk0X%a9LETm?qlR8].CF܅ LgJAwI({…  p_ʣ@൤ ޏ 1~MWI*ow`~ɮ [ڈ;IEnz?} JTr {Tt·WTq*a)ub`@x:}&vmзW0VuSx$;(jfJ?v3:<ZyW șf-brt5xI\9.|, BA6 ɼwy?kMJ)G7˜EP)_J潟\2< w͛y?zR-;Ovgyg>̫etx^wǰ]!2g+?r8fyd>̫e;=stc/ky݂c v_<5:.|}y(KH+e_xtp\Z٪~,IENDB`perfbook_html/node59.html0000644000175000017500000000742611672746161015600 0ustar paulmckpaulmck 6.3 Approximate Limit Counters


6.3 Approximate Limit Counters

Another special case of counting involves limit-checking. For example, as noted in the approximate structure-allocation limit problem in the Quick Quiz on page [*], suppose that you need to maintain a count of the number of structures allocated in order to fail any allocations once the number of structures in use exceeds a limit, in this case, 10,000. Suppose further that these structures are short-lived, and that this limit is rarely exceeded.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img270.png0000644000175000017500000001707311672745756015332 0ustar paulmckpaulmckPNG  IHDR6)Y.HPLTEb``MJK# hffmkkXUV856KHHC@@:67wuv.*+~~0XtRNS@fIDATx]*EtHt>&&'{걨!S K[#A16ʵ}0UG5R\%oB7B" ~\FX%$4!eEBsDO1E:x!W>r-%*J(=^Kx֮=}%V}T$Wv4Tǚ&[,H-Hjb3F_!C}auG=Z4<[y$w=GVmr6{=N*4AgC'bZkpdn ˅4~-A((#?˂A5tRD~ۂi`脎lT]Og)pӄ[lI Xe>+ ʝ´BBÅ[::~?PJur]"ؾu46r,^P#a;E4 nմ&hm%[q3b~cF#vC%x|A51: : Tߏmchl$w<dIZLhDu6N* ͎LrC~6"&əX۳N9s[(GWozj]TؙPWHˈKD8δບy7uARhXku}>5I?"Ī{xưB.%I>j?) Qꆤn|S3MY&VU/Cj8"l@ߧ.sN!DAn۴>^Mvō(YEA+ bhf)6}j/,rD2u,)# \!MI h4&h)͍'*U5##5gBHn9%ѻFvj q͂8~~۴_Qoa:~ApbsSRvcupG,o2P87z uNΒD AF( TTҎ<Dr]D6+k)l6oG ?T';n$Ie=zLFb| ~xс2g:u|gw ~Vhl*'4Ug' ;TҴ3kP |'@f-)^~+OO'U,!ɏdwe~vŨ,zx+ݠw 2FP ]̮ RzIG=WTrr'kgYZ-i\Mvf+Ϣd1h6Md%2!\v'ؕGql(32T-V@ĝvvlϺ\Z#4ͻai7߇73dD?'/=H~lpr~54h(h]F7J;L>$ƄS_7وw$͓vR%AH-Erk8jn=<~zeVhvOAmI&L[6yq#iz M=W$ʓXs$9W~F&z뵤?sϭۗ$`)"9d' `Ш@8E 84MvL%zoY0T:-xtRx;L ;P[ flj8|p vԭ?%=b:Zs ޘ(J ܣ]QL {ƞfh` E7@o9]{JsUb ǺMmHHJ-v e'{zGZe@ xc po=J<"ݒRδ2wK1xSd?ZX.᠓"#$,\d,#U~7#`YCN>T7/C'YCtwd#h!|'-0_5G%u10BW=ċ_p o/!'XK̖W`'wz>r6(8{f8=4T/^ 3Ɠ+b` ]" k7z]Xm}Wtn WXBZmGݏbXd=f`oEhY߄k o~Зp5l@uc)$Zkl"C[pgA$l77Hs m)<;wzSV"P֗KZ&xn811" mJC >۷[7K~|05E!@1Kj0w=WHmȋ{}Scg-T9nPq %[VR89R˫yYasb,+v#`n!8ys\&nשbAwjłU~uN*it w3ݙ!-Q؈YH-7 /6> Cz(+<\=@y-[Igד [x ]\U]k r h㬖3|BjkQk }ΚytpФ/>vVxs~ӏj0sQtn_̉'Z{9 (6\XD9:sB⏮^e&?,iNEk?rduQ7,&!,sTh–F1]WIoeJojRFмGس f+7&R . gZ ZY)0 $'e!gyD8Gl縱,NJMrƙ<5YmOB phA=do"N)th ćS4osYYH G/;h9d1s )姡zbռ=¼CLȹ<`sXڸ2^ȹzNSӤYZRȹvh ;6iU(p AOcW@N菍qAlD[9|mKŻ 7mB:ilV=:aD ׇ]+]ϑuN9:K7 3cf)eUlMj pS!2 >cakFק19UUi'قçO^=&`ߤNtx4ASֲHTXH,BlUJk7vt':y n {1@O~b6ָ ytA̘83J)ӣEJv1TpTHɗ˨_z[-)j^F;G-&F{/&¥rBׄj|f;J˽;H/aԐ)&nCίAlĵ+ɻVM(w=_}f0>&ɧ1hWgS;p̓6UI[a%.BS>%xƱLNT)~u 袐 j6̛ 7';,9Hefo}lG}[710GojH1ir 2g$ ~ 7:_|Zd&E*KK_63OM)PON5Xe4iDžҔǒ>P86DJkoU[k,|$?0rKo$\a! vboA76f3ǚ][\% v޹if㪕8<eagx l#m& NERV]LN{C_ 4~mEgH%K I -OB®4a0i5a-uqlQr&,(ːyOڔ}vK0{'iJI w9ɋy/nI&I \3 <ӱl,"I?xHY_yBj I(/}'P+]74+-p=&Wb=lsR!]A_Чdr 1I%1L)%ñwKQ˩m1QZѮ!]U}#`*m]nAc͖Rra=zaθDq Iey`Wׁ!"zp|ؔ?~ M?JΛ[r!~[iW1[r'rMe008anW&fe2(Kl &kPW!85ʆ*|xj}1+_ly"L-.V6M؀ Ѭ[w^R[Ii0AZ_žx =`wdcst': U~79IR`ofD{]`oL"lbcPo)%Y&ɹ9VeEZ*J1`s < o2<&җ)zOxwdظR*/]wWK-wIENDB`perfbook_html/img81.png0000644000175000017500000000053211672746102015224 0ustar paulmckpaulmckPNG  IHDR8g˲0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(c`@ BȰ `e(g80 ęTLP=v as3D21 `6-n2m -@eMˀY e@&K0q33@gXnl|bXtK@S|$[,Ƒ*@ dh2}g0dXxIk?`@I}WnI *gOIENDB`perfbook_html/node476.html0000644000175000017500000004622311672746164015664 0ustar paulmckpaulmck F.16 Chapter 

F.16 Chapter [*]

Quick Quiz [*].1: 
Why is there an unreached statement in locker? After all, isn't this a full state-space search?
 
Answer:
The locker process is an infinite loop, so control never reaches the end of this process. However, since there are no monotonically increasing variables, Promela is able to model this infinite loop with a small number of states.

Quick Quiz [*].2: 
What are some Promela code-style issues with this example?
 
Answer:
There are several:

  1. The declaration of sum should be moved to within the init block, since it is not used anywhere else.
  2. The assertion code should be moved outside of the initialization loop. The initialization loop can then be placed in an atomic block, greatly reducing the state space (by how much?).
  3. The atomic block covering the assertion code should be extended to include the initialization of sum and j, and also to cover the assertion. This also reduces the state space (again, by how much?).

Quick Quiz [*].3: 
Is there a more straightforward way to code the do-od statement?
 
Answer:
Yes. Replace it with if-fi and remove the two break statements.

Quick Quiz [*].4: 
Why are there atomic blocks at lines 12-21 and lines 44-56, when the operations within those atomic blocks have no atomic implementation on any current production microprocessor?
 
Answer:
Because those operations are for the benefit of the assertion only. They are not part of the algorithm itself. There is therefore no harm in marking them atomic, and so marking them greatly reduces the state space that must be searched by the Promela model.

Quick Quiz [*].5: 
Is the re-summing of the counters on lines 24-27 really necessary?
 
Answer:
Yes. To see this, delete these lines and run the model.

Alternatively, consider the following sequence of steps:

  1. One process is within its RCU read-side critical section, so that the value of ctr[0] is zero and the value of ctr[1] is two.
  2. An updater starts executing, and sees that the sum of the counters is two so that the fastpath cannot be executed. It therefore acquires the lock.
  3. A second updater starts executing, and fetches the value of ctr[0], which is zero.
  4. The first updater adds one to ctr[0], flips the index (which now becomes zero), then subtracts one from ctr[1] (which now becomes one).
  5. The second updater fetches the value of ctr[1], which is now one.
  6. The second updater now incorrectly concludes that it is safe to proceed on the fastpath, despite the fact that the original reader has not yet completed.

Quick Quiz [*].6: 
Yeah, that's just great! Now, just what am I supposed to do if I don't happen to have a machine with 40GB of main memory???
 
Answer:
Relax, there are a number of lawful answers to this question:

  1. Further optimize the model, reducing its memory consumption.
  2. Work out a pencil-and-paper proof, perhaps starting with the comments in the code in the Linux kernel.
  3. Devise careful torture tests, which, though they cannot prove the code correct, can find hidden bugs.
  4. There is some movement towards tools that do model checking on clusters of smaller machines. However, please note that we have not actually used such tools myself, courtesy of some large machines that Paul has occasional access to.

Quick Quiz [*].7: 
Why not simply increment rcu_update_flag, and then only increment dynticks_progress_counter if the old value of rcu_update_flag was zero???
 
Answer:
This fails in presence of NMIs. To see this, suppose an NMI was received just after rcu_irq_enter() incremented rcu_update_flag, but before it incremented dynticks_progress_counter. The instance of rcu_irq_enter() invoked by the NMI would see that the original value of rcu_update_flag was non-zero, and would therefore refrain from incrementing dynticks_progress_counter. This would leave the RCU grace-period machinery no clue that the NMI handler was executing on this CPU, so that any RCU read-side critical sections in the NMI handler would lose their RCU protection.

The possibility of NMI handlers, which, by definition cannot be masked, does complicate this code.

Quick Quiz [*].8: 
But if line 7 finds that we are the outermost interrupt, wouldn't we always need to increment dynticks_progress_counter?
 
Answer:
Not if we interrupted a running task! In that case, dynticks_progress_counter would have already been incremented by rcu_exit_nohz(), and there would be no need to increment it again.

Quick Quiz [*].9: 
Can you spot any bugs in any of the code in this section?
 
Answer:
Read the next section to see if you were correct.

Quick Quiz [*].10: 
Why isn't the memory barrier in rcu_exit_nohz() and rcu_enter_nohz() modeled in Promela?
 
Answer:
Promela assumes sequential consistency, so it is not necessary to model memory barriers. In fact, one must instead explicitly model lack of memory barriers, for example, as shown in Figure [*] on page [*].

Quick Quiz [*].11: 
Isn't it a bit strange to model rcu_exit_nohz() followed by rcu_enter_nohz()? Wouldn't it be more natural to instead model entry before exit?
 
Answer:
It probably would be more natural, but we will need this particular order for the liveness checks that we will add later.

Quick Quiz [*].12: 
Wait a minute! In the Linux kernel, both dynticks_progress_counter and rcu_dyntick_snapshot are per-CPU variables. So why are they instead being modeled as single global variables?
 
Answer:
Because the grace-period code processes each CPU's dynticks_progress_counter and rcu_dyntick_snapshot variables separately, we can collapse the state onto a single CPU. If the grace-period code were instead to do something special given specific values on specific CPUs, then we would indeed need to model multiple CPUs. But fortunately, we can safely confine ourselves to two CPUs, the one running the grace-period processing and the one entering and leaving dynticks-idle mode.

Quick Quiz [*].13: 
Given there are a pair of back-to-back changes to grace_period_state on lines 25 and 26, how can we be sure that line 25's changes won't be lost?
 
Answer:
Recall that Promela and spin trace out every possible sequence of state changes. Therefore, timing is irrelevant: Promela/spin will be quite happy to jam the entire rest of the model between those two statements unless some state variable specifically prohibits doing so.

Quick Quiz [*].14: 
But what would you do if you needed the statements in a single EXECUTE_MAINLINE() group to execute non-atomically?
 
Answer:
The easiest thing to do would be to put each such statement in its own EXECUTE_MAINLINE() statement.

Quick Quiz [*].15: 
But what if the dynticks_nohz() process had ``if'' or ``do'' statements with conditions, where the statement bodies of these constructs needed to execute non-atomically?
 
Answer:
One approach, as we will see in a later section, is to use explicit labels and ``goto'' statements. For example, the construct:



		if
		:: i == 0 -> a = -1;
		:: else -> a = -2;
		fi;


could be modeled as something like:



		EXECUTE_MAINLINE(stmt1,
				 if
				 :: i == 0 -> goto stmt1_then;
				 :: else -> goto stmt1_else;
				 fi)
		stmt1_then: skip;
		EXECUTE_MAINLINE(stmt1_then1, a = -1; goto stmt1_end)
		stmt1_else: skip;
		EXECUTE_MAINLINE(stmt1_then1, a = -2)
		stmt1_end: skip;


However, it is not clear that the macro is helping much in the case of the ``if'' statement, so these sorts of situations will be open-coded in the following sections.

Quick Quiz [*].16: 
Why are lines 45 and 46 (the in_dyntick_irq = 0; and the i++;) executed atomically?
 
Answer:
These lines of code pertain to controlling the model, not to the code being modeled, so there is no reason to model them non-atomically. The motivation for modeling them atomically is to reduce the size of the state space.

Quick Quiz [*].17: 
What property of interrupts is this dynticks_irq() process unable to model?
 
Answer:
One such property is nested interrupts, which are handled in the following section.

Quick Quiz [*].18: 
Does Paul always write his code in this painfully incremental manner?
 
Answer:
Not always, but more and more frequently. In this case, Paul started with the smallest slice of code that included an interrupt handler, because he was not sure how best to model interrupts in Promela. Once he got that working, he added other features. (But if he was doing it again, he would start with a ``toy'' handler. For example, he might have the handler increment a variable twice and have the mainline code verify that the value was always even.)

Why the incremental approach? Consider the following, attributed to Brian W. Kernighan:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

This means that any attempt to optimize the production of code should place at least 66% of its emphasis on optimizing the debugging process, even at the expense of increasing the time and effort spent coding. Incremental coding and testing is one way to optimize the debugging process, at the expense of some increase in coding effort. Paul uses this approach because he rarely has the luxury of devoting full days (let alone weeks) to coding and debugging.

Quick Quiz [*].19: 
But what happens if an NMI handler starts running before an irq handler completes, and if that NMI handler continues running until a second irq handler starts?
 
Answer:
This cannot happen within the confines of a single CPU. The first irq handler cannot complete until the NMI handler returns. Therefore, if each of the dynticks and dynticks_nmi variables have taken on an even value during a given time interval, the corresponding CPU really was in a quiescent state at some time during that interval.

Quick Quiz [*].20: 
This is still pretty complicated. Why not just have a cpumask_t that has a bit set for each CPU that is in dyntick-idle mode, clearing the bit when entering an irq or NMI handler, and setting it upon exit?
 
Answer:
Although this approach would be functionally correct, it would result in excessive irq entry/exit overhead on large machines. In contrast, the approach laid out in this section allows each CPU to touch only per-CPU data on irq and NMI entry/exit, resulting in much lower irq entry/exit overhead, especially on large machines.

Paul E. McKenney 2011-12-16
perfbook_html/img210.png0000644000175000017500000000046611672746062015311 0ustar paulmckpaulmckPNG  IHDR S1-PLTEMJK# b``mkkXUV856C@@wuvXtRNS@fIDATc`b`p`p``pb0pap/X 0_`````ɻ08p3@d3.`aEP#;Pĝgted*0,P".@fl. v^bM0d`U`` d00400ߊ,K_ԑhW`{Iʂy$/EIENDB`perfbook_html/img4.png0000644000175000017500000002556711672746027015164 0ustar paulmckpaulmckPNG  IHDRmr3PLTEMJKROO# b``mkkXUV856C@@wuv.*+1ortRNS@f IDATx]* /JEk/ OmmvNV"b x9T6FVQ 9Lb L?]م _ѯo%i($͝SllJc]>'`݉<)o$#ny_#*g_‰ ?Nrds|N+sᯑyNvHG' ~|p]aL[Qv/?bXj[ޥ$^׫#k[eFٿjgѯn˞f}u~W"?ѫSmZSbx$d!$ry(#a(1o-`Kџ-8 ;dj[Rjg`$m')EeSJ\;tD}Өx \!]Y] dǏ'dIv|E^͠..HdtAR6f^>z@3Q}HvhIuLvMgs=crBͽw)l+~uWP3<tEsKϻս><@l 4#[S]y9FMJN{}6oxnߌIPpAk1v hG (.) @Α, J{tN5 mGE0N"dn y16zۧvvBnZJA7;7o*^pf}7o8#nߌ@-}C8-;-}3R'p[wxnߌ;S.ؾ8m+{9Tu0>XNCEj+^k R>- d2ͽ߳#ç. yaR{3 7_ vܾwvܾ-گlo}6&ool[i @DT>~Gbca7_= )rҧ>M-xY{d R`0(k0k&Kqf<@;:}SHnߌ#8Ҿ7i:Ҿьalځj'>n߳}3 0wHc0!c4[[y#u{(yCS77{=Һ6k矉v[&![ 1Amj= q+ +FmilFxh?5ތMw#1&)ܶ>FfQO>~$BjoYMjRer4F aTD>PN̔!6H]:uxLjbe;t`xǼ!^tTiJev&h9w#o͜m)+Ck<%QA_'Yf*QSSx/99OO/'͚7uBRB|&NIT@Aji;taIІL\iaU x 5=Xpiw=(I`*S7L6ońjL?(#ChtmŬ 7S ]Fzڙ{W m.>n|ȃ4h]9go)ꅅ04v6BQa">8KK \d7KQL>S'4r/=@qƳ\I)҈R5:5.-S Ɵoٶ)Bץw˕7`P7u)Ne әRſ"K ە)Θ{LqqDU($lDkRymx53U5pFY-|pʔ|lͲ@ riHTXON=[;TI܎>Ƣ$*XoN XZnzCfP7v7IKЉ$B]j S1?ŷw~}-ZY3÷J^J%թ[//Wf0ދoC߽߫; $ '?Jv60kkHѥT.Ao|-E#`CfVࠉ,vThYa)BԪ})>6çF,wD Hy܇Q&t1I rJotqrZaYuf0PNjez(WKg08P7XY36xXCI❤ÔN(;)rܣ*9E*hDߥ2rsIGE{b̩:K# Ɵ=kЖ1 O20\6+D^ȲUvn }WC㤹axH'RaЫb:<nԂO̼Mp(*.iyYN٣ӜJ3AIkWU|u^#׀Xx>؆ 7C:7e֦7Sm;e(g|t[-FOT#W9[H wL'MV+wLA>Vv.+dn 鼱kMSKoʩWZV0I.$ o#wDxXMGĂzA߅ A"WbS;3VM}/f1J2vL:JIQYbZH]ݭrcڽToEzkG慻D}?_b1fu˫.0H=M_:rb̢Oܝ+.7b9)1:x$2U@VEv;acc$~Xw@M`q.cj j ni`P,.&5jlB=f|vc?A~KĦ> ぼHpׄ)Ժ4,|OVGS@ǰbǘ n9.K):'%v7N,+Ԋ+ty0 {+q)opMKf'h†來wͷ_H. Qkb:udYĎnh*{W&SFt lI7qMn0JJlG9I/MD:hTl0{9^FAYUU]#O3lF-wMyFX? /aPrl !f0 .\􄸒Uq*vWEudo `0S/GMv{/hoæp{ۛf#ۦm}>=`0SA5]}!{{%Ub_F 8%5JvcyWb_ކůۮܨ ds{`{`0o]-{){|Ii"vYRp=`0 j\X$5y˕3/XU`&ut-Mbs`m&X`0.~B.doPw,{[P'-6`0޾Bdo_qFo]qFwɅf0 Ǘ[1[Ͷ .ԘSqyF %*TmX26q.dooY_6m6 oXbR򫏁{B^:Q޲p W5`ovGOO9`l_\- 5bEd( <( V嘿(oI!Tzl؄z/(ƑAt Ŷ"bmPj4o1}~|іoOSqj~7yj6 ZXQަzoXvc.ioclj|AޱPm wBlo? q* ]/doľ"Vk/3`{`07,!nexoSgX_{j܈26)r% 1)38@;ZI2qZދ 7x;_Y6Pk#N^ c+x{- 5:|Ndx7HETЄV7Z/`0 F6seM[{l쭱D̡U%Ֆ/ `*~`7k8:Qn'%.{5 1*;,Mir:%Q-mdt-Лξjd`-0U,Oyof\q 8͎.ʼn=\r.,0iJj|%%Vk{Hse^,hcfhY]g[]5-vp6> 0I]|bB4 Nbk2ODi5 vZ1[Ml橶 UcC 6.&y3Ӏ'ꐜv6YaB+ܘV1@6iЕhc jjݵK}|p}NƷ`nӷ=|U/8>Fpr,րyGC:MP}IGU΋X E*/A}׬[+JfOsOh Z{[ִ"40mu g֥tެD Vb)CyzQH $vuzc +ӀO82kҎ! Óp3D~?1h)vD؁riѤ[v[kmHbOdHn>2o,'RKbk-"lbٙ!Gl7RC.2ޤA(tR/wEILSUg<,U~ȇ5vRg7Ai=y; u  `S7HN51-1gtŞr& M`0+ RKua$IʽAH;-4]w~{ imܠDR4ߎA$v܈b&cA5 r) N x 6<l6w1ނ@QqE(=xF;{ܖL$5~îDvQ.%V|aXU9 tqi2v(1lkw*cgmT:[]RCG iXۍ{,c^M>QӹlGbpR?Z n-'OWL]+d IZcm|UD="<ݻٺs_8Gވrmcܰ<ƄNaeY "6oZs3iS-ING)P8bç@G1FkkHr^Cn)VXjcluާ˛]!iZUm.j[cJZsߩSZAS>1tUYgWnHU(f$my gLrWг6ŮAAf5Ye˫sTf9B0oU|ET;@AC,DQA>+qͣW!Vfjw@c%`0 `0 *F~ۋGG MH@`ms" ͚nx D$õݴ!ֿߎ[КH`>& 5حm#rژI0LMӹ3ju|O`pJRjF%=N3 pT(6нڶT32 vIiʉֽjmǿiD&>Kt^6Em`!3J;ف} a~`0 `\߶ I>ѣ8`~ldbFmioT΍e~\$~;0 `0 wb|Ǡl`$q0ؐiVyBwaIK_.㪧%W`\\!bSuΝJe NZx{!EP۾yGYJ$9(g| h7+٧pyi O;JH\Ô( ږ8tp%h[bu;նMꔘAmYZՅ@Hct߆ ʉY~SZM%M)mW(=- H+/m;߽3`p(wnۣl/kWj[5v7Fr(pa_oB3ۤa tTp&,vm 6p=oȝj(*߆ h b"HyhotT\ҽ2t>SJu'ҋr#}R3rm(PYn1\o`0 `~mو1oYv7WF@0}&$5'Om`0 `~;g%Ko݈U׮+bp`o "8涶>MR&uz1I0`0 `0o$~;q/HG[o筶yHv]`~`~`0 `0Hv^SQ3]"dg#nSooo淟wOm`0 `~;ȼ6rsojfTOGᵁח|\]?B,f^_C%e~`0 `|5@R{ dlĸ$F̽ nl8r^΋rGQBӧ;Io =!/Jw>4HnPx& 5Xvk81`Tߙ(wm Jg\`=g\$^F+֌%bTw"j2f\Bn.W)T/u&>) ⥶8BXHNk$@z[!lmY-ф\5Xն)L&]ԶƔRQ6&}~:#iĽڶT8"Sm pp]ǿ>/}c%l:/Jߢڿ%^/1An<OQ_o"(Uȸ*{2Ac߃~mkwG `0 Bըج1}*2 fCI Fⷡv>qBg~d~[ng ۾"]0k`~`~`0 `|1rN1}*2m;7ׇ>n)f~tq]oog~Td~[淙`~`0 `|1"m1*$'oMIEO6G>Ye~d~{!eۧ'QAJTςm`0 Hf'coo e~\$~۶5ۧmo7 7'#' #e{(I4V9`~`~`0 NWKA/tE`2 ^'De)΋mhZ GUyعSUE)n'-<ɭV3?um?ytq8'u7W)!񉗄 jp6WQE 7ΎSNZ8@L(Huk@ticR$M4*|z}+y$:>s^i#X:⣤ܸ%uN*~&BRitZ5M%M)mW_At(j yY3sRJWt>7lc1<vDgB,4}iCsIߡO,R62 tj(Oj۾Tۨu>R9Q8\\?Uru$:y>hH@X161C{pӵN)ΐns;x|E5 *T?m; l~"`0 }0%4]_`~\`_v 0 GqM1}2MFm3}& Z KoHlk@1I0`0 `0o$~[ٽoo.Z Qo6۩oo3 `0 NqJ6~1%g.t6B|c}qo ǝEo %11CGJ8y,(6e^yl}](@J&˔9ؔ&rWT.12|7](iNm4S1Ėbc}Ny(%sm`0 o78CM߉[8mgyVk2`:"5x^̠̑8Z-e^:fJzMۡN1b-K[=Xm?Tۙg*:<8Qi'Ȓh6,_*(ej{IID nk;X_zĮk; 3ߵM,B%FCudW^{v<;lSA)ܶx}$IIe\|:].o$<7wC䤗sigȒ/iݢ(xsETx9EXӃٴŅmmg7DZkNzp.vKI6G7ۣYfOtr2`*R9'ų$hp^m3 7QAa 0:?O\ZB)ʒJHcRT+o9)[ȾA:4U&6w~ 4(U9rגa O2ETpmѤDY"pp—j./,o]D9\+ٔ6 /W5D8 K",uA Oy*Jy2R#\6R^Y GQδ\{Wk;z;0ֵʶg'nR ['˴SZX묎bS%9,/lG.Զn@.z9Fp"g((4[?0-/v1yo^ǫ~e)z+l۶y-6L%=Pyv#L;'to+Y6>M.\<3Gc:RP-#ond:^:۾Cye\G?Gqppؘ2Uzlؘ2 <6lxdž/Lc'3nTh&SAR|7KGM$DnIENDB`perfbook_html/img307.png0000644000175000017500000000665011672746133015320 0ustar paulmckpaulmckPNG  IHDR,=BcVE8hŒh*PELÏہ76"[g[ 298HSa10Q]~hi]lpگ` <d~9JiKwB95!:9 I-]6ѱZqXo~|Q~0!.I'Uwdm~qz EULfnb5*?m;'}5ɕ]: zagL( V_8uZmp cEMj?B*11qoHj5cbEC͒Fd:%s~+5q-ٶ &e5>Wbu]7it&x_4hKIGaY^ΛZe{)I|Xl.yI d4\ 4# h2@.XW%wq7 M%ę-A߁pDu.j\{%VpuUfnlRKLg9IlU*,BX[V}9g8XĂi2ag`G gz+ӑxPw+(C(CuƉ޴'U sE)+&XEe hvypAy}d;FN{`7=;y^Ϯy칠iZLɝ6"/t e>⒱N\SSVß.9yJxl]/E rr0VULQBZF Dpz Nh$>/0=wʠ_ځڅ:,pŵ57@CZԑDoEݺؾ։jYx@2'{/9lO{2%p+Ezl鱋sp=ۓPY4PfFK$}S8l6T>1`?USǫdY񂐵,>QɆ8|t-!e!ykEYα!\ UBj܅"AjK¸)-ZPϜBve Zi>>*6To}PR[e,uNȚM#笭pҶ5uc\SJU]dT17g`vUWQ(6zyS+cLZRIb ( 5S)F,@% RODpDe\G0?InƁ8OZFɎjf&N>𚒇InέX wzXLNIC?$'ǖ%)Ϳ2M@nqL eXpڐe * S $%\x 8έ^սtC0Ӏ8'DlG|&xݓ3]O*q?)J9fѿ ?A^3_*cC[\X?Ř<-֜n^PūIC Cpwj8D*kxV3|C=\F(6tߣ0/bEu4Em-Iq4Ngсt`N8c|笵lV+O{3J4_SvZcUG$xv 1 v{P5)]V( 朱42eGS*^0ߩX|#,)),2K+ӺZ5E>/tY1ݑ&OoNmnHCH?2. U"vkBͰ>[쯢E[j#-,1ٱQ:imۙ+_hFRٟ6_ ]p}ns7IveH JɃ:B/"uy ͵_F('zUGOB'3t曜Iʒ5U"1 r/t3T 6,տý8yV#eAYeځ|k|x\Pq( [%[b 9W >Oj[Pdu"~/ w1O%BFFf.1唅ր|#k-TҿUǙJW/)m`G[Erɪ':iI"l䥕y^pՌPD  JLp&Z3X+k_H?ܢaTY"^(HTKfvȓbu^'±x,\fwEwL~jΚf[$$k{ز!:?;7}wY&;P&GL nvo fwmbv(IENDB`perfbook_html/node390.html0000644000175000017500000001275211672746163015656 0ustar paulmckpaulmck D.3.7.1 Entering and Exiting Dyntick-Idle Mode


D.3.7.1 Entering and Exiting Dyntick-Idle Mode

Figure: Entering and Exiting Dyntick-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_enter_nohz(void)
2 {
...
...
23 local_irq_restore(flags);
24 smp_mb();
25 }\end{verbatim}
}\end{figure}

Figure [*] shows the rcu_enter_nohz() and rcu_exit_nohz() functions that allow the scheduler to transition to and from dynticks-idle mode. Therefore, after rcu_enter_nohz() has been call, RCU will ignore it, at least until the next rcu_exit_nohz(), the next interrupt, or the next NMI.

Line 6 of rcu_enter_nohz() executes a memory barrier to ensure that any preceding RCU read-side critical sections are seen to have occurred before the following code that tells RCU to ignore this CPU. Lines 7 and 11 disable and restore interrupts in order to avoid interference with the state change. Line 8 picks up a pointer to the running CPU's rcu_dynticks structure, line 9 increments the ->dynticks field (which now must be even to indicate that this CPU may be ignored), and finally line 10 decrements the ->dynticks_nesting field (which now must be zero to indicate that there is no reason to pay attention to this CPU).

Lines 19 and 23 of rcu_exit_nohz() disable and re-enable interrupts, again to avoid interference. Line 20 obtains a pointer to this CPU's rcu_dynticks structure, line 21 increments the ->dynticks field (which now must be odd in order to indicate that RCU must once again pay attention to this CPU), and line 22 increments the ->dynticks_nesting field (which now must have the value 1 to indicate that there is one reason to pay attention to this CPU).

Paul E. McKenney 2011-12-16
perfbook_html/node69.html0000644000175000017500000003157511672746162015604 0ustar paulmckpaulmck 6.4.4 Signal-Theft Limit Counter Implementation


6.4.4 Signal-Theft Limit Counter Implementation

Figure: Signal-Theft Limit Counter Data
\begin{figure}{ \scriptsize
\begin{verbatim}1  ...

Figure [*] (count_lim_sig.c) shows the data structures used by the signal-theft based counter implementation. Lines 1-7 define the states and values for the per-thread theft state machine described in the preceding section. Lines 8-17 are similar to earlier implementations, with the addition of lines 14 and 15 to allow remote access to a thread's countermax and theft variables, respectively.

Figure: Signal-Theft Limit Counter Value-Migration Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...r = globalcount;
62 globalcount -= counter;
63 }\end{verbatim}
}\end{figure}

Figure [*] shows the functions responsible for migrating counts between per-thread variables and the global variables. Lines 1-7 shows global_count(), which is identical to earlier implementations. Lines 9-19 shows flush_local_count_sig(), which is the signal handler used in the theft process. Lines 11 and 12 check to see if the theft state is REQ, and, if not returns without change. Line 13 executes a memory barrier to ensure that the sampling of the theft variable happens before any change to that variable. Line 14 sets the theft state to ACK, and, if line 15 sees that this thread's fastpaths are not running, line 16 sets the theft state to READY.

Quick Quiz 6.40: In Figure [*] function flush_local_count_sig(), why are there ACCESS_ONCE() wrappers around the uses of the theft per-thread variable? End Quick Quiz

Lines 21-49 shows flush_local_count(), which is called from the slowpath to flush all threads' local counts. The loop spanning lines 26-34 advances the theft state for each thread that has local count, and also sends that thread a signal. Line 27 skips any non-existent threads. Otherwise, line 28 checks to see if the current thread holds any local count, and, if not, line 29 sets the thread's theft state to READY and line 28 skips to the next thread. Otherwise, line 32 sets the thread's theft state to REQ and line 29 sends the thread a signal.

Quick Quiz 6.41: In Figure [*], why is it safe for line 28 to directly access the other thread's countermax variable? End Quick Quiz

Quick Quiz 6.42: In Figure [*], why doesn't line 33 check for the current thread sending itself a signal? End Quick Quiz

Quick Quiz 6.43: The code in Figure [*], works with gcc and POSIX. What would be required to make it also conform to the ISO C standard? End Quick Quiz

The loop spanning lines 35-48 waits until each thread reaches READY state, then steals that thread's count. Lines 36-37 skip any non-existent threads, and the loop spanning lines 38-42 wait until the current thread's theft state becomes READY. Line 39 blocks for a millisecond to avoid priority-inversion problems, and if line 40 determines that the thread's signal has not yet arrived, line 41 resends the signal. Execution reaches line 43 when the thread's theft state becomes READY, so lines 43-46 do the thieving. Line 47 then sets the thread's theft state back to IDLE.

Quick Quiz 6.44: In Figure [*], why does line 41 resend the signal? End Quick Quiz

Lines 51-63 show balance_count(), which is similar to that of earlier examples.

Figure: Signal-Theft Limit Counter Add and Subtract Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
...69 spin_unlock(&gblcnt_mutex);
70 return 1;
71 }\end{verbatim}
}\end{figure}

Lines 1-36 of Figure [*] shows the add_count() function. The fastpath spans lines 5-20, and the slowpath lines 21-35. Line 5 sets the per-thread counting variable to 1 so that any subsequent signal handlers interrupting this thread will set the theft state to ACK rather than READY, allowing this fastpath to complete properly. Line 6 prevents the compiler from reordering any of the fastpath body to precede the setting of counting. Lines 7 and 8 check to see if the per-thread data can accommodate the add_count() and if there is no ongoing theft in progress, and if so line 9 does the fastpath addition and line 10 notes that the fastpath was taken.

In either case, line 12 prevents the compiler from reordering the fastpath body to follow line 13, which permits any subsequent signal handlers to undertake theft. Line 14 again disables compiler reordering, and then line 15 checks to see if the signal handler deferred the theft state-change to READY, and, if so, line 16 executes a memory barrier to ensure that any CPU that sees line 17 setting state to READY also sees the effects of line 9. If the fastpath addition at line 9 was executed, then line 20 returns success.

Figure: Signal-Theft Limit Counter Read Function
\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long read_count(void)
...
... spin_unlock(&gblcnt_mutex);
12 return sum;
13 }\end{verbatim}
}\end{figure}

Otherwise, we fall through to the slowpath starting at line 21. The structure of the slowpath is similar to those of earlier examples, so its analysis is left as an exercise to the reader. Similarly, the structure of sub_count() on lines 38-71 is the same as that of add_count(), so the analysis of sub_count() is also left as an exercise for the reader, as is the analysis of read_count() in Figure [*].

Figure: Signal-Theft Limit Counter Initialization Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 void count_init(void)
2 {
3 s...
...idx] = NULL;
34 spin_unlock(&gblcnt_mutex);
35 }\end{verbatim}
}\end{figure}

Lines 1-12 of Figure [*] show count_init(), which set up flush_local_count_sig() as the signal handler for SIGUSR1, enabling the pthread_kill() calls in flush_local_count() to invoke flush_local_count_sig(). The code for thread registry and unregistry is similar to that of earlier examples, so its analysis is left as an exercise for the reader.

Paul E. McKenney 2011-12-16
perfbook_html/node221.html0000644000175000017500000000527211672746162015645 0ustar paulmckpaulmck 14.2.10.2.1 LOCK Operations

14.2.10.2.1 LOCK Operations

A lock operation acts as a one-way permeable barrier. It guarantees that all memory operations after the LOCK operation will appear to happen after the LOCK operation with respect to the other components of the system.

Memory operations that occur before a LOCK operation may appear to happen after it completes.

A LOCK operation should almost always be paired with an UNLOCK operation.



Paul E. McKenney 2011-12-16
perfbook_html/node294.html0000644000175000017500000002350611672746163015660 0ustar paulmckpaulmck C.1 Cache Structure


C.1 Cache Structure

Modern CPUs are much faster than are modern memory systems. A 2006 CPU might be capable of executing ten instructions per nanosecond, but will require many tens of nanoseconds to fetch a data item from main memory. This disparity in speed -- more than two orders of magnitude -- has resulted in the multi-megabyte caches found on modern CPUs. These caches are associated with the CPUs as shown in Figure [*], and can typically be accessed in a few cycles.C.1

Figure: Modern Computer System Cache Structure
\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSC}}

Data flows among the CPUs' caches and memory in fixed-length blocks called ``cache lines'', which are normally a power of two in size, ranging from 16 to 256 bytes. When a given data item is first accessed by a given CPU, it will be absent from that CPU's cache, meaning that a ``cache miss'' (or, more specifically, a ``startup'' or ``warmup'' cache miss) has occurred. The cache miss means that the CPU will have to wait (or be ``stalled'') for hundreds of cycles while the item is fetched from memory. However, the item will be loaded into that CPU's cache, so that subsequent accesses will find it in the cache and therefore run at full speed.

After some time, the CPU's cache will fill, and subsequent misses will likely need to eject an item from the cache in order to make room for the newly fetched item. Such a cache miss is termed a ``capacity miss'', because it is caused by the cache's limited capacity. However, most caches can be forced to eject an old item to make room for a new item even when they are not yet full. This is due to the fact that large caches are implemented as hardware hash tables with fixed-size hash buckets (or ``sets'', as CPU designers call them) and no chaining, as shown in Figure [*].

This cache has sixteen ``sets'' and two ``ways'' for a total of 32 ``lines'', each entry containing a single 256-byte ``cache line'', which is a 256-byte-aligned block of memory. This cache line size is a little on the large size, but makes the hexadecimal arithmetic much simpler. In hardware parlance, this is a two-way set-associative cache, and is analogous to a software hash table with sixteen buckets, where each bucket's hash chain is limited to at most two elements. The size (32 cache lines in this case) and the associativity (two in this case) are collectively called the cache's ``geometry''. Since this cache is implemented in hardware, the hash function is extremely simple: extract four bits from the memory address.

Figure: CPU Cache Structure
\begin{figure}\begin{center}
\small
\begin{picture}(170,170)(0,0)
\par
% Address...
...
\put(100,150){\framebox{(}80,10){\tt }}
\end{picture}\end{center}
\end{figure}

In Figure [*], each box corresponds to a cache entry, which can contain a 256-byte cache line. However, a cache entry can be empty, as indicated by the empty boxes in the figure. The rest of the boxes are flagged with the memory address of the cache line that they contain. Since the cache lines must be 256-byte aligned, the low eight bits of each address are zero, and the choice of hardware hash function means that the next-higher four bits match the hash line number.

The situation depicted in the figure might arise if the program's code were located at address 0x43210E00 through 0x43210EFF, and this program accessed data sequentially from 0x12345000 through 0x12345EFF. Suppose that the program were now to access location 0x12345F00. This location hashes to line 0xF, and both ways of this line are empty, so the corresponding 256-byte line can be accommodated. If the program were to access location 0x1233000, which hashes to line 0x0, the corresponding 256-byte cache line can be accommodated in way 1. However, if the program were to access location 0x1233E00, which hashes to line 0xE, one of the existing lines must be ejected from the cache to make room for the new cache line. If this ejected line were accessed later, a cache miss would result. Such a cache miss is termed an ``associativity miss''.

Thus far, we have been considering only cases where a CPU reads a data item. What happens when it does a write? Because it is important that all CPUs agree on the value of a given data item, before a given CPU writes to that data item, it must first cause it to be removed, or ``invalidated'', from other CPUs' caches. Once this invalidation has completed, the CPU may safely modify the data item. If the data item was present in this CPU's cache, but was read-only, this process is termed a ``write miss''. Once a given CPU has completed invalidating a given data item from other CPUs' caches, that CPU may repeatedly write (and read) that data item.

Later, if one of the other CPUs attempts to access the data item, it will incur a cache miss, this time because the first CPU invalidated the item in order to write to it. This type of cache miss is termed a ``communication miss'', since it is usually due to several CPUs using the data items to communicate (for example, a lock is a data item that is used to communicate among CPUs using a mutual-exclusion algorithm).

Clearly, much care must be taken to ensure that all CPUs maintain a coherent view of the data. With all this fetching, invalidating, and writing, it is easy to imagine data being lost or (perhaps worse) different CPUs having conflicting values for the same data item in their respective caches. These problems are prevented by ``cache-coherency protocols'', described in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/img179.png0000644000175000017500000001530511672746011015317 0ustar paulmckpaulmckPNG  IHDR-9[/PLTEӧ{{{gggSSSQQQMMMAAA111'''!!! z|ztttrrrbbbZZZ@@@444 %,qtRNS@fIDATx]b<lfچe$N 4=y;|@|o#lYȲ,-H ̺T$@'2c 4?#ƘG7i߇ AbNaԖYZ*,rbӧ^fWCqI@cH[>[߻_) wA5x$é;4 mmgZfLgJ塦4o4Nw]"Hf4r %,Dg$*KVb#? 9s*S72vEzawJJn:yI @=kg`c(b8@KQVx[r MV^2+ϜS'[Ȩ[FgTmpNK& %&˜99S+MhT)୔;yAQyTO; 0XCrx_;Yv6w8:WaU|)ٟ3  @ .@,b0(l9DljHcXUUzjEy:9.7ّX3Tfy곧)A~?+$i)Si?8gcRhQ2!oUŒ(- tؽJJU,e0fQ0(~R7 6{VK%`{_a]$5-PxF_VФ [Vx0GIBF6.3C96$C!\U4-㬢hަD$ʾV1SWZQ5oSaV]reƘey:1ca̸|\deqa*Z/-PNP:@Ypme?qߠ(lĿxyPnlIJhC Ӳ}rl3l˚Cr_T5*P(/Z*+ In\y? ]֧OXe3zU.U-l}J#k*Z._fhOPm%d|Jgbֻ[m#ۈxBO^OކhaB,fSExͥRby"_.U[mJLV;'Gw ]Ʃ4ʢwb$gw/I'55(K!lNR|!|`8YYV<_gO[\|OW3_jֆ9] δolfL_"A]Xe!ES~GHT}<'QAᄬHZp).%9XHҕҲ I̲T/sBdભ=:I`Y_KU,8rCR䃧tֲ`2TR.M"}bp(K$I$-#kL:ږt\" -qڈ7 !eь#X 6w-mN8X2;QOC%3l"+>>h)/UuѶT~/,ww;>!|_?:_ؾ_*u r|R8?TWg-`3΁< /ͲuwL84o/J`xC6 ALP-QVTi"_bn旺kom U^x T-Kb xi`U\YQMf e?&K>{xaW`uKI^4nd npY*-+B$aKRw*Lu궜ށQ~SJb^ ey4_`Ձva4J= sd[;{];D0mFWV-|?CK6#zxvƤ^h(R6Xv/ک`6d`P"U{cmnr{5ԉN_`( :Gİ >j2:Mnw{ux J}ٜø fYm'qu刈fYyW= NRWJE`H؀ Q%-7ńRJ#O^ +;:7ɗ&YBXQuan\Zʗ&YqlXg_r\#ڝLjs[e q'd2[%9?_4Ypeu]ˋv^Y=h@ejn["NOLD}+,IJQׄwS+ڱNrY8ͱ~\#?B}S/NJjUG1S:rJ!Ԇϔ41?Ƕi @GI|ޕB(+(/3u 9)sCse=w6 "w惂|i —P XЂI0U`csUpeLi(]a(r*;#K݆vFGׁkݐ=T@]I*Or,R"-JagC^.l]?"HYk[[<[Q[-زAؒnھ];_n-qAoEv"ǖ BdbĖp"W˖UA]v!rlav[v_号:ԅ 74ub֟P7 vÂ~Ϧ g .-Ch'RBB%@Gލޅl68a=e #BEoؘ&+c˺}g:]c6][ޓ;1/ؓCԄvli~A?B'7щtlYןPcf1&kc̪[_rw!ONٹZ8@p.bbm[dK㸂ɘO?Lzl 1pD kID^0r)$pSȖVH;dda2x1mq{1ŋ-^h5$u"Ȗt'kq'Iܛ!<7e-!%]Q\i}g:yG[F`9Dt;QI&4I;Cr'ܻ}x-K\ +|cZǖlN-N8Nz05=5axRG9-TGLUURUo@!Sx'-HOyo6Aa'6b|Z18h44^Pۆ\n` _8վM"BwROX/le`;0%'.N#` CM6]NAJ2Ic6L2&&iIZ&Fb|rW7}ۅ2I F)z87[|pnLr tPf|҂w4a߄̞ˌF=%mj6ygx/Y28}LP,!$ѷ!7@ܺ% R "3Q[4+|~.HFKeE+N@"&<Gb6Wo!N(u'i䡤OqUBly%ĠϨ, )n+|ZgY|6<#ZZ26pVixtOZX3jL8\G( $@ZBy_3%VU ’wXRo )6m= y{QICdi#K[ZDx3;Y6γ:֓Ϩg׹Թ-oytl#|Rsl9 ⪚J!jUuLU>׺E΀ўp,y?|9MGo9N$ g|2͕ UHEU0$QKi@:KCYa B5qZMf%@*RIBVRRԤ"FxGZ1Hep떼[B~Qp;DK%GiR x"]Ut<\礳G}ԚÈ"ҠEJV!@R'rz8ͥ%faDuwv춴G&"*۲lWElj销Ь4# 7DH[RH3S@X7ѿ)v1ȱ;!2!Ȅp Nɓ@DGmL^wZ Mksm"qee0AmSr=a,֗]1^i!mIZLZN^ɽW#$-C_O1t;IKгb L&MZǺJ3H/@Ғc-r8>ʅ 7Q&ҽDz}&c Y7?D9,d|URcy𽫼\7DzK w1\ clw7Md(DC4xRS4ABuzHuOKHoiQ'ec _Bz7 t7l7QTm?MZ.V}U܇g>'./JZ|[XNv?j6z 'H$|aW 3w>7_6{7 m1*Mq\T#S>kqzښU!rQDEif[`zt8tC\{ 3r땈j*y5%y. * CiIީ=ړW$M߄;$bdpFd^:jT.l"7+`&UY 8)WE)(oz[1y(ܴHys߫DiZUyhV R7$7!kށؐEׄL,}Ghggg CHt?6|V([M*B&''"QcT--.@Zn  .io 8&%OIJliwM28:yͧ9 YSj#H]E^H$+dE5OIuUcDtۗ2$ ȧf2 nIENDB`perfbook_html/node203.html0000644000175000017500000001176611672746162015652 0ustar paulmckpaulmck 14.2.4.5.2 Stores ``Pass in the Night''.

14.2.4.5.2 Stores ``Pass in the Night''.

In the following example, after both CPUs have finished executing their code sequences, it is quite tempting to conclude that the result {A==1,B==2} cannot happen.

CPU 1 CPU 2
A=1; B=2;
smp_mb(); smp_mb();
B=1; A=2;


Unfortunately, such a conclusion does not necessarily hold on all 20th-century systems. Suppose that the cache line containing A is initially owned by CPU 2, and that containing B is initially owned by CPU 1. Then, in systems that have invalidation queues and store buffers, it is possible for the first assignments to ``pass in the night'', so that the second assignments actually happen first. This strange (but quite common) effect is explained in Appendix [*].

This same effect can happen in any memory-barrier pairing where each CPU's memory barrier is preceded by a store, including the ``ears to mouths'' pairing.

However, 21st-century hardware does accommodate ordering intuitions, and do permit this combination to be used safely.

Paul E. McKenney 2011-12-16
perfbook_html/node90.html0000644000175000017500000001776711672746162015605 0ustar paulmckpaulmck 7.4 Parallel Fastpath


7.4 Parallel Fastpath

Fine-grained (and therefore usually higher-performance) designs are typically more complex than are coarser-grained designs. In many cases, most of the overhead is incurred by a small fraction of the code [Knu73]. So why not focus effort on that small fraction?

This is the idea behind the parallel-fastpath design pattern, to aggressively parallelize the common-case code path without incurring the complexity that would be required to aggressively parallelize the entire algorithm. You must understand not only the specific algorithm you wish to parallelize, but also the workload that the algorithm will be subjected to. Great creativity and design effort is often required to construct a parallel fastpath.

Parallel fastpath combines different patterns (one for the fastpath, one elsewhere) and is therefore a template pattern. The following instances of parallel fastpath occur often enough to warrant their own patterns, as depicted in Figure [*]:

Figure: Parallel-Fastpath Design Patterns
\includegraphics{SMPdesign/ParallelFastpath}

  1. Reader/Writer Locking (described below in Section [*]).
  2. Read-copy update (RCU), which may be used as a high-performance replacement for reader/writer locking, is introduced in Section [*], and will not be discussed further in this chapter.
  3. Hierarchical Locking ([McK96]), which is touched upon in Section [*].
  4. Resource Allocator Caches ([McK96,MS93]). See Section [*] for more detail.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node436.html0000644000175000017500000000637011672746163015656 0ustar paulmckpaulmck E.6.4 Alternative Approach: More Capable Tools


E.6.4 Alternative Approach: More Capable Tools

Although Promela and Spin are quite useful, much more capable tools are available, particularly for verifying hardware. This means that if it is possible to translate your algorithm to the hardware-design VHDL language, as it often will be for low-level parallel algorithms, then it is possible to apply these tools to your code (for example, this was done for the first realtime RCU algorithm). However, such tools can be quite expensive.

Although the advent of commodity multiprocessing might eventually result in powerful free-software model-checkers featuring fancy state-space-reduction capabilities, this does not help much in the here and now.

As an aside, there are Spin features that support approximate searches that require fixed amounts of memory, however, I have never been able to bring myself to trust approximations when verifying parallel algorithms.

Another approach might be to divide and conquer.



Paul E. McKenney 2011-12-16
perfbook_html/node214.html0000644000175000017500000001434111672746162015644 0ustar paulmckpaulmck 14.2.10 What Are Memory Barriers?


14.2.10 What Are Memory Barriers?

As can be seen above, independent memory operations are effectively performed in random order, but this can be a problem for CPU-CPU interaction and for I/O. What is required is some way of intervening to instruct the compiler and the CPU to restrict the order.

Memory barriers are such interventions. They impose a perceived partial ordering over the memory operations on either side of the barrier.

Such enforcement is important because the CPUs and other devices in a system can use a variety of tricks to improve performance - including reordering, deferral and combination of memory operations; speculative loads; speculative branch prediction and various types of caching. Memory barriers are used to override or suppress these tricks, allowing the code to sanely control the interaction of multiple CPUs and/or devices.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img231.png0000644000175000017500000002372511672746117015320 0ustar paulmckpaulmckPNG  IHDRVFPLTEݱ""$8D 6SfDDff"l̈www̙3''ݦUUU*3-EUQ}333wcD33U3U@@fMM"33wZZHoUUZww~fff ffDDD?awssfu"""D"%>tRNS@f IDATx C۸rS:qeCa 6a(I(%Y%)Zr?yFeYVNNN@2VP,ތѝTn+$WB %M%sq´<\t:EKrUtusIn F ;6*-e);Ԯ07]$Y3N9m]=W`cbJ뾺! 匂a0 |(Գq+\IݒƏ\T/̝+fs3gKds9mj:Z9#F&Or/gst:/ѝuEC\Nx#\ȾRK(ع :fAW"=Kz2'eŏLkfŹ ɢ{@%drɢI(D-AAG_.C9]/N1%Qo* }X@!woc*=!InAn+?[74W +(';\B+mHr^5+Ue4:Jra$;08וaHTtr3Q%D+2S\QEvQ6w'8XlM0\ X C=\KWtsY>qs*r_҆q&7HXGt3r7(;ԥMpQ!grE}Ԫۆt.j!(2ɢ\;gxVM5阹$kQ;,Vgds&wuyerq>b4s\F0rJWl ƹ/Jrq;[4haJw !yA_W!qK^AY4~iX6 ݩܘ, Ұ/ bd?}X| q=DȚ YYΑaU``dsaDx &uЁ7J;`HWX)q֖ʊ5y)%4(#)+WDY"`1D_N~=PC9ؐM W ddnp7JU;9Z]|>ϸ*f(]6ΉniVX'˒p{?I=MdkT7S$ }vYÇdsܳ%EaC2JeYe(+6!<רkf- QTRrNfW*N_;T|5Z㪖U|'O쀠;U|%PM=6=Zp@Y_fo|IqXww+++!qYiyzz:.j-+#,]\ϚFue}|$$ƊYYXUpHYF ؎Rhtb ӿ |Oxk WE%)h'r ( 7:}MNXa+Zҋщ^G#igƷӿ,e*-Wuuˬy6V2 pfW!C86Q^f0٠כ vz>؄F2Vr=ݠ2 |u<'nh{X:V+IQ.aUIdU|ueXc.ѭT *niUTi@C &Heu"Ӫj4Tf5OZ*˪֡'Ւf5*d}ǧ;(e3N+9걎#Tr4M.Ϻ#6+:#}(e39+=h,#~ߓk nkjxPC ]=7Hf+Ym'd!9[bfDl-20eDZϠ~uXBPum5C*n])NJײ\u]s]aXs+[[jXAnS>T5݋XߞF'z <֜ZSRBYV-Җz6p/UrX HJww_gi͘kO5*Ѻz|@F0u[ugKco#Sp!_ߝ ;)njUhgQ>|XD\|]u:dz` aUvc̠҅cm\2s\tm)#+&I ܪ__Z}E[}˰VQɜ[*b9-5ND.z HF2`"+էJ[}QK H -5VꃘqOi–'mBKM$n.\V2־`wgI֟cVfj3`?gVEw'1{%XqO`ةqn{dX˴uXUXv.kKYVe]Z (Uf/ò.S(1M)VnxQ֘V^xײhqiIV7XUDjemc~VK4YO*'V]hiIZ2zX5[6[k35|1KNO-ւyY󢭱!S×6-[4zy[,j SqhֶxJ'ܨ)I"jUcS>flmiAM*_Tu<%Qӯ֥(Ihj뒙Cجm= ];i[9dNl& nQm=#|G~LIV4`++ª:JB̢Ŋ:nG~ߴ\%uN=/Zk+MT|K˵`-vxYo?{[o8WH`'S<%U4uiԤ֑՛~#$- E$lS[i~]kB ~\|}+x/Ҫ5dr5ek\ڭ7 Yn+%B)gJXC&Wץ.S'ŢC8HSG_.*b \lJء׳AiazqajMK_UjwZwZwZ&ZJ֌Up+ =[Q nYфGjT֪UXSIZn6j%ik_B[u%i_VK*ҲZ^ Aʶ6 X.݂jt[gmmnWXʶeճU.] lkQZk[gmVeW ֊qX5*|Z,ښk,{檗|mS|걵Vi[K8o+a=V1,ڶ(l"l"l"l"^[h,VM΍r`9[`5o+w%{r`5g ^|~IDAT*.]|>|O ؚǚ\*XڇGZgp?7mk+Z[϶w ]Q%q"V̥.K1jun[g,^޿'My'чmUq_ђ}=|EJѾ3.C۶b\M sA@2C붪a`=WeX̀\cKXa<հaJ"gMܟ(+zhVe X2F̨hX3XŒ^GW,5^Z̍cmk+8]Kggq[K5ekX[ u:ƨ?K X`kzx]nX<.Qgvaq mMxDcԟ5[ۄY\fk8.7.^cikk8wYhx]<8.%Xj-lTZhRvZ jX'pVrZg[%i\T?aqh[Xfm4ʞc9[7Ȩ^7`[7m74ϖM`loT֢<[9ye*DKPA.TJۚ2cڶ5mVE{6bm Ijtvu[UqZkI#MYXXm^=dkXl=ir)OQQ궞/P 4[χ#ay==j%laл臏 An{KkXmm BExs״ۆ; ކ߶ljG֨$mUVOy[ƪjImVOֽńbыMe[ձ\ZXm=)_ |</ ^&x{~\d+s`5jĭn=-zrroGv2ۡg]LU[Ub.9"Y[=D?'›A'a*z_@#zgV>V%U-/ SZ{xa3I;PGU[= W2jǴ5-BO㖿LkԭX1V˰Ӳ]VFY8D|`{'e{c/WvXnl!fGKpߖkxjYH:3٭cHժ {mo;g V}w̏{Qߛ}> A{='A wR}ҷwK}RjK_JhۀCkl|㿿;>$o%ӵliMQHnuc>~72s{;asdN~<>r]W }BpԂKhg޻e5 C\#쀖 1CFoc0zhc)$QX~i5/fi,IɐG%s f!C+8'J>A ! x+ XYSZ!{O&aD' 9KUb$e/7*{5t>w2 @F  P)[Eo z_>}~n 2$\i5.w/qCO0N+q̯q W#_BJX ]QkEY ^C342Фۣmh@CH6f:x"Z=kVUtT?ջxíĨL˸q1/(i" S߀rRD`j&GMp?kZYA2hx/ዡlZm|~F%Stϵo<^y=r EU:t'T8HXjk3 Hgx,bjD9xtjO9 w "l{M?@[I|&:مR]]#dl"·3Fr_Py6.]PzL!I~q_ħ/ܞ\UH *߿ Bw([-5+n JُEaC7Ӷ& pj#ip!L%M;teR8$ǛbÛ/qƷBs<|ǩ"Y"y;d/ӂY0{D}..`Zýv[̓)$k{iß~ Z;>z g ς 3S/@'e_&Gߕs)!0~;78uɚ1Xkn΀34 , ZFIɚOq nr`K)d-WJUjaT(0-WgKkepv|T BDjFǝ=-$}H +lj^ wʞ[ɟ{tWVh}VbEPky\Eiz-%Vw VT> ja\ԴiH5; 5 ) AI$Ӿ!݀3rpkPT'Tk\X) RЪSbTOi_p&6訸%ն"O27>"tUJ 'd4RNUĿ $[} N'Is' tbLoOdo8Y2փNqwg싰c &I"y%B+,p xȇR>//jn/z8 V/3One4xJ%Q{g8?z?=8cBhLyQ!x?_oLs6Q:-91c8xuf2TiR, x1E 1@S0Jx3Y'KΠ&{'O3.VguTj_k+A=y=-ΟF5m Z+jɱCl4۩BbؘE|z篆[29sW0@yn׳*''5>KdV-cJ.OL8` 656xmGH:b'mnK1*YJw\o6\H|kW0>oM-k (U4PVY"@aCWMLS wt!g8k㳙~CTAm5(~"9&)snE»x}/s9 ~Vk(NT/k\ Ɍћ%H@5aa[)^s< U+츂[L IpZ }φcI@>r.eK7b`MA&S Mҭ)<8++3DݩX} F%7X1NBcpla$ h':3 CCY' Tۭ\`k!0Nk{r 9I4Mj SÛYt|8vai%f%m)Px1䘆h88#ӣVyT_6R%$JK;PLjwyj2]_R痼qEaT{Y|?lWGig j3=O::C3q0ńf@j%LX,^0+جK:s`BMs+42rw)M>0h2%_ ~`2rw~78etP9>@I >/)72A 3?՞lCBJa:'С|/VhW}1_!º1^IVBiO\OČ9jpجCw@@ۙNQУM)` 0~@eC{gidog80@i@&FBC [Hw>;dGK {^;^1Zk'wk~Ov;:;<#3VO&FȊoOZZklN;ybi3jb~]nn/ɎMx1q܄:\yG|(7ʙlhtcad+GIAd \&ߌeԙF x1-'STh!_Ɣ2h*"S$*:p;L1)/L),ǐ+2=Ȕn#S`azBlR,3)P)vəpE<% N/N opi{d2^3+Z{,d[u>O ϳ%=Ͷ&Iȶ Mn̔ d=e&!EM>#D+ج>0NYp;sEl,oaޖE&or+!x]Eu!a)_ p3=_sTW-[=0 {@\L+@ BʭŽ%m0 f* 2^W,+@ ӳ'Ƴ Dift WNPؿ .a{*E2lrQL30f3/)<΁ϊզrp"*^pP z錥xQR"};i_ʔTVK3:H'Y3Ý rK EHUW!Q=T\n7? 9_韜$d^9'| PQo/\:,El B!f??I8ـM)JQ)a|qub]P{`,871D tu.ld1ta_.Np~\&]Juc|>{ӎ!`;\ϛ(dLH>t!3X++3f~Wc9d}p~GW›P~Ωa躧ܾ6XKo~_J󹤿w?ۦI9d>CM NI{Ltއ_P`#Lrn&\LRfL 6^þܙ/8=;d#9 W6  0?_0?-p&/\pp83q*3ptU޹;"lv7;4[!e4i_aֶ-9A OF -UW F. d3種6ufAKU-Bܷ海8ƒE'M߮XzSAp.a)x>lx0>@s Z{mvj0^eǶѻ f@ 2 Q;na&0?Cλ*'伻07b\yGagD-ؿ>܂"`7㇒ZF>FYIENDB`perfbook_html/node319.html0000644000175000017500000000501511672746163015651 0ustar paulmckpaulmck C.7.5 PA-RISC

C.7.5 PA-RISC

Although the PA-RISC architecture permits full reordering of loads and stores, actual CPUs run fully ordered [Kan96]. This means that the Linux kernel's memory-ordering primitives generate no code, however, they do use the gcc memory attribute to disable compiler optimizations that would reorder code across the memory barrier.



Paul E. McKenney 2011-12-16
perfbook_html/img121.png0000644000175000017500000000111111672746147015302 0ustar paulmckpaulmckPNG  IHDR"3PLTE$8D6Sfl*3-EUQ}c"HoZ~ ?awu݇xotRNS@fIDATXV Ti%|A1똙vjf# CŖ{qM$.p^֭ۚ`$R1 `9GlYkW[F0:1~,בXxC F|vcg#uwMu i~wFY&db|cp+p09w\Fs`8Л@Owl j-9TxLFM 4 6fVs@ȼ*brHJ2FJ (Bڞ,rǨrġ)eh̜U"Q+\p_ <zCCyH6 TG288i~ l=G,܏Uve!sqIskA%`uzM2{yf?ߜi?Wg\-e2wo6q IENDB`perfbook_html/node166.html0000644000175000017500000000652011672746162015652 0ustar paulmckpaulmck 11. Applying RCU


11. Applying RCU

This chapter shows how to apply RCU to some examples discussed earlier in this book. In some cases, RCU provides simpler code, in other cases better performance and scalability, and in still other cases, both.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node380.html0000644000175000017500000001444711672746163015660 0ustar paulmckpaulmck D.3.4.1 rcu_init_percpu_data()


D.3.4.1 rcu_init_percpu_data()

Figure: rcu_init_percpu_data() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_init_percpu_...
...dp, lastcomp);
42 local_irq_restore(flags);
43 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_init_percpu_data(), which initializes the specified CPU's rcu_data structure in response to booting up or to that CPU coming online. It also sets up the rcu_node hierarchy so that this CPU will participate in future grace periods.

Line 8 gets a pointer to this CPU's rcu_data structure, based on the specified rcu_state structure, and places this pointer into the local variable rdp. Line 9 gets a pointer to the root rcu_node structure for the specified rcu_state structure, placing it in local variable rnp.

Lines 11-29 initialize the fields of the rcu_data structure under the protection of the root rcu_node structure's lock in order to ensure consistent values. Line 17 is important for tracing, due to the fact that many Linux distributions set NR_CPUS to a very large number, which could result in excessive output when tracing rcu_data structures. The ->beenonline field is used to solve this problem, as it will be set to the value one on any rcu_data structure corresponding to a CPU that has ever been online, and set to zero for all other rcu_data structures. This allows the tracing code to easily ignore irrelevant CPUs.

Lines 30-40 propagate the onlining CPU's bit up the rcu_node hierarchy, proceeding until either the root rcu_node is reached or until the corresponding bit is already set, whichever comes first. This bit-setting is done under the protection of ->onofflock in order to exclude initialization of a new grace period, and, in addition, each rcu_node structure is initialized under the protection of its lock. Line 41 then invokes cpu_quiet() to signal RCU that this CPU has been in an extended quiescent state, and finally, line 42 re-enables irqs.

Quick Quiz D.36: Why call cpu_quiet() on line 41 of Figure [*], given that we are excluding grace periods with various locks, and given that any earlier grace periods would not have been waiting on this previously-offlined CPU? End Quick Quiz

It is important to note that rcu_init_percpu_data() is invoked not only at boot time, but also every time that a given CPU is brought online.

Paul E. McKenney 2011-12-16
perfbook_html/img259.png0000644000175000017500000001101711672746125015320 0ustar paulmckpaulmckPNG  IHDR-Q6PLTEMJKZWW# b``ommmkkXUV856C@@wuv.*+ؐ]tRNS@fIDATx]( dEj[g(@HB!'Z)_נ (e5 ȕjRRy@i LA^)3Qɪ 5.-VR^T_ס2Qoo|5iVӈ#\}&LKO/>b v}纇,7˙Z_˷[P 0j4T<[ԗ 嵻|:5Dm-;GpqVU<ˏsOI ZUjPES[O18דu>5>vUS6ʛ6{sZD|EL]{$?REkZ@C;WkT^¦dͥ{;'0#~L'.x_]d@+9BڌAΤ0yk={@p8.N>m>-WEo(} )rA.q(m.+ c?yP2Y̕b8*>uO\*Nj9 'e>G*Y!)KJCk]LK&٪ XRﭔ=' c}Bg+J|S0Q֗㮅7>yxF&5eOY`UY knvm?e]MQp.>eB<slL581QU)4odQJIʭ5LױH?*.XkZ)#ZWq76}8 3~xpΜ!/YòpҾA;`4MLTbVP>UMı $Z5r By;=/Me 켢̹-v!^YC; 09Ji" %%tlHSQ֒ >cIbr]-L)ϕ.T]mkmsj%}wXǬg%JjPL1.-渵m;0uBTzֹ(?'>.{|Y G^TRu+6\:5EzaGƒ{߷ طf4:З{95Q[>>Bv~ y|ịml|pyRk7"K$慥n!M Pսق R2*lLK:Ԏ{vVtVQWd_iVZl?2ςeڊ y"cdٺTUӮ)9\g@O >R"΍F9bWGͅa ڟ?3)ctsk+ ͋l^5 ء9Kcd}Ϟ`{#})[ ?9qgE JBFèo):>N(fPn +dC ň\=pI.D,4@Y2YAۛ_:Cu0ٻ0 ;Ͱ?pGFLVyrEV 2*WSc/<+ơz('pAxLtњq# wfc 8_U%>s>L,m%>G,N#= pC*#[NxJ5W=*Qj^"AD+gAġ*}2lPQC4 ~#*4k/ 0k?3>cf8[ MS*BM"V/JI&r~*b抜$B=euUDCdzb}peqZ {ҰZE C_BqVzYE |SĻq.|;`x~Hb@gDsYE|h0X.ZEp>*b"Nfؙ1a:*ӊ/S^lE Q fx$¹8B;,-PUWLq n{!l$k]49=fU6=1~UDFfdy6uA4GHN yIҫ2#G~-[IVʦ=6*h0{L!u 'p^`,IqGO'[Q'9HH6 Q ׽k&BDl9~rOU{ nYAk)ZNrݢҍu海@K;Ӆ!C/C)T 3oM|yɽ.1…rogČ9c~!`&4@/j 2%c}UUeri ( >`UTBUf!u g)߲Pd(Dpi7Pp1%yNl?t*,}HV]TH[r: BkXd(@2Έt} fwx헽l6w]X,űcligЖA;/\6|ɝkSg<< P<>"ʝ2ԘQtYn^r yC6UG*d}5q6T,  =%"J"L(\Z';'f_ "=2G6DP9Z1 1^,ʤ"f!.҃|R-5_+f(r ˛`_Qx , <`6 6QEEl 摐Lp-1rP)^uPx"O&&$ct A!챾'}OBpF y7άw>>gLxWŸbEl+Vī0Z"Iޯ*;C$ >}bE$1qX?>eXWbElmbE0pO㌱"9_3Ɗ^xsŊPW+l}V?+ YUl/+x%Vx 81 bˀp;ytC U"ZWN^Y/\~{ X #p~3OGwNX&U^$d:Y@$* Ňإ \D#C-"=-(\5$oт %D,2N"{ D4CӾ5e_ll,ʁ'&Wn PDLlI|#FXѥ)@Q|ؿnE{ 6.1 Why Isn't Concurrent Counting Trivial?


6.1 Why Isn't Concurrent Counting Trivial?

Figure: Just Count!
\begin{figure}{ \scriptsize
\begin{verbatim}1 long counter = 0;
2
3 void i...
...ng read_count(void)
9 {
10 return counter;
11 }\end{verbatim}
}\end{figure}

Let's start with something simple, for example, the straightforward use of arithmetic shown in Figure [*] (count_nonatomic.c). Here, we have a counter on line 1, we increment it on line 5, and we read out its value on line 10. What could be simpler?

This approach has the additional advantage of being blazingly fast if you are doing lots of reading and almost no incrementing, and on small systems, the performance is excellent.

There is just one large fly in the ointment: this approach can lose counts. On my dual-core laptop, a short run invoked inc_count() 100,014,000 times, but the final value of the counter was only 52,909,118. Although it is true that approximate values have their place in computing, it is almost always necessary to do better than this.

Quick Quiz 6.6: But doesn't the ++ operator produce an x86 add-to-memory instruction? And won't the CPU cache cause this to be atomic? End Quick Quiz

Quick Quiz 6.7: The 8-figure accuracy on the number of failures indicates that you really did test this. Why would it be necessary to test such a trivial program, especially when the bug is easily seen by inspection? End Quick Quiz

Figure: Just Count Atomically!
\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t counter = ATOMIC_INIT(...
...void)
9 {
10 return atomic_read(&counter);
11 }\end{verbatim}
}\end{figure}

Figure: Atomic Increment Scalability on Nehalem
\resizebox{3in}{!}{\includegraphics{CodeSamples/count/atomic}}

The straightforward way to count accurately is to use atomic operations, as shown in Figure [*] (count_atomic.c). Line 1 defines an atomic variable, line 5 atomically increments it, and line 10 reads it out. Because this is atomic, it keeps perfect count. However, it is slower: on a Intel Core Duo laptop, it is about six times slower than non-atomic increment when a single thread is incrementing, and more than ten times slower if two threads are incrementing.

This poor performance should not be a surprise, given the discussion in Chapter [*], nor should it be a surprise that the performance of atomic increment gets slower as the number of CPUs and threads increase, as shown in Figure [*]. In this figure, the horizontal dashed line resting on the x axis is the ideal performance that would be achieved by a perfectly scalable algorithm: with such an algorithm, a given increment would incur the same overhead that it would in a single-threaded program. Atomic increment of a single global variable is clearly decidedly non-ideal, and gets worse as you add CPUs.

Quick Quiz 6.8: Why doesn't the dashed line on the x axis meet the diagonal line at $y=1$? End Quick Quiz

Quick Quiz 6.9: But atomic increment is still pretty fast. And incrementing a single variable in a tight loop sounds pretty unrealistic to me, after all, most of the program's execution should be devoted to actually doing work, not accounting for the work it has done! Why should I care about making this go faster? End Quick Quiz

Figure: Data Flow For Global Atomic Increment
\resizebox{3in}{!}{\includegraphics{count/GlobalInc}}

For another perspective on global atomic increment, consider Figure [*]. In order for each CPU to get a chance to increment a given global variable, the cache line containing that variable must circulate among all the CPUs, as shown by the red arrows. Such circulation will take significant time, resulting in the poor performance seen in Figure [*].

The following sections discuss high-performance counting, which avoids the delays inherent in such circulation.

Quick Quiz 6.10: But why can't CPU designers simply ship the operation to the data, avoiding the need to circulate the cache line containing the global variable being incremented? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img250.png0000644000175000017500000001141611672746036015313 0ustar paulmckpaulmckPNG  IHDRW4؈HWPLTE$8D6SflgggMMM*3-EUQ}c'''"HoZ~tttZZZ@@@?aw444u݇2,tRNS@feIDATx] *tN6%g5.#CQD1uleYAl@{#XeQXr”sSBfX9[Ҧ-XQKJ^4e7Bb?ۙD.O & L.0P96dHnj3$IY_mgiJz^o^O?]wj;YMO,k31w8)ˈ|Jz_#2@ xk391-kũc2<,̬QOy{0Y2>agGcdOO㱏n:{t*ެ9LOZal:__XwMo#yK~rՔbs:׌Ԙ>8)hnq槵OvW0D%{89rZ֖'Զ]%,Hn •zia&DNA)y}'oV nV>" 6}LѦ"k]T]PYM(ӼIhjWu"=FȇX9\7&L*x58䥯b .^ݴ&5qw6m'щ&(QhKH5#ͦP?g*RF/X0yf. E;RCB*._ l͟R+*`ivw'W} :˥[jN]rSv/` w=-tNjm|}K6vM^ w},{ BɿV6vΥ2ZuQU +||V}_p-"-ƤfwGV{vZXS=#7+|Wjp?*>!-Kׯ3烞\9xr k_tqXqCZ6hUOJ)L;f)b 􃞝nKGs+V6En2'PY՟0T5"%D-3|FkabIeR4 '>ZhKqci;a\~lVo=uV[ek#Js~^ hՊZmtb_b쫤wU ZËWyKp 3+vbuv L hLY澺v5GWMi]|)Q^*K6?)vb+J_?ngpU5z?>nӋ5v{hX(,/;BBBBƯ̊x;( >`;s+p:sqw~@|T Lōo׋-ۼhƳLuދ]@wFzȻ Cpz9m hXzJz^1M0qH[>z'Mߧ7P'^(Ck-¤%KkZRэ]TmlU(ջ,m^mC.i=VZ[e*i!z`Nڡb0V6EK԰xh/uDq,WMfPB@ɖ([2b*,ْnG}5JgEC'%mMW*0F}xPV*R~$_kyۊcGǑY<uAX쫯Κ>@VxJ4bl 1 !X*KS:JrӪ+=n5]IW)?ItL+?*S\6Ug(PU#6KՃ~MڮM Xgy=5~\?H2Tln[ŤQ_WY2Jnwy<8*Vi2k-ڡ^F/D~(MT YY:g9Vt%DkYo]g?U.j `YmnB V#DΊgk[gʳܾƫbYZcYIlg @0@0@08z0I,jjgq{aJZaZap~VJ˴Gq$3e֥89LZ=SҍЭrF@gώ)ĝfFp=Bh*J1o߭GqyjM@:xT+fogk=‡\7:D+P uV/ЫU)]o Oa|%.;~i}p]^Kk]%WSwyxU剿o]=Fh=ugVVVIk   Z?  uoSF GZaQ+ 1jG2"P+ P+ ~VTw~A $Og+Ik ? 27_I.|Ku޶;6Z?~^ψڑ9oO;Cp;yK͎3mB/~V[jV<>q}5㭶)c/h]Vh9omeƿoV{JxR~ԚLfgv]Mi/}OlQZZ? CJQ;a{֦?vqW";e7/eZ2* |UC0ڡov̚zus tA\i nhLU? 1QASٿ(R9Rp"lZ^W6%1υ<,u,JOjo-&/ 2 1؁GʹNo:?2Ez4BƏ*<'Z "Nbͧmѣ4pv18?/sRy/SBn(S߶a=!W0@_a}BD+ W0@_a8d+  C0d+  A&;8xZ}u>`cB̆t+=N5M086_'mkp~C磱|E៹(|U]KM^ulȹ/pQ|k hRgbv57EWsQ0\ݗu5 R[悁?aj 5`8 14.2.12.1 Locking Examples

14.2.12.1 Locking Examples



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node62.html0000644000175000017500000000602511672746161015564 0ustar paulmckpaulmck 6.3.3 Simple Limit Counter Discussion

6.3.3 Simple Limit Counter Discussion

This type of counter is quite fast when aggregate values are near zero, with some overhead due to the comparison and branch in both add_count()'s and sub_count()'s fastpaths. However, the use of a per-thread countermax reserve means that add_count() can fail even when the aggregate value of the counter is nowhere near globalcountmax. Similarly, sub_count() can fail even when the aggregate value of the counter is nowhere near zero.

In many cases, this is unacceptable. Even if the globalcountmax is intended to be an approximate limit, there is usually a limit to exactly how much approximation can be tolerated. One way to limit the degree of approximation is to impose an upper limit on the value of the per-thread countermax instances. This task is undertaken in the next section.



Paul E. McKenney 2011-12-16
perfbook_html/img13.png0000644000175000017500000013433111672746140015226 0ustar paulmckpaulmckPNG  IHDRZ1}KPLTEgVN 2% вʴή(ѷʼͰ৆{𴔋ο¹չs`XPC<ȩԶ:/)ʹд׾۶óﭐG91ʫؿֻ˼ʦҸ Լ\MDӾпqgŵyoѿu~i^X>tRNS@f IDATxsy( jJNgECaEL0FMڄ\ɴ55%nD>qqyOf˔a.:g^.L<JE#73t4Ysѹ X̹{riPtN. Vpif*%tɰB:#bBGݬR|ic`Ba ]5Ga&0e)uQ!g i2Up<z~;",1U%yK(kN{="4:S]x1 L3$`$q4Om y -%0{Ce %0» 23bg T`оEm3*&lNO > a-B rUԙd?gy=#TG.?PTA lw-cq_^,[h; Fʤsޣ_X%4뢄k;}p٩zhyFü̫nDj>^|rYBxe$%􊈃hE3c_1g6L8c`D`fӏςkoϔי56k%H9 Owjvf VsC[\Cz#=}i*5Yl f$ĎL[32R\׸G|Qږ>XSB.` ]N7A"F<ߔ&cD> 2o S?Ezc5֥i! td 󃩶.mZmɘghߞj5'nEၖ:Vv=91]vlxi< nBP[5p/ !"0A%s%sCmRqPwfsH[87-0&%SP9P"`< ?&"6 >G6_R~Z j5R&t0[l9|6yTB+fn_'JmӺG]@?Y}:z =4=<:<ǥm؉ 32O}-ŜPj5Vcm@D*JEKr5lCDD3JzA6%\ȉCjtO$DJeji C & C[2LD~ճok4B|Fqu[ `ū,e@r`]!*3m%i-HXe%LsI&ǫ ͙P)`556o1_- IZ&VXW[Dvrbb52~ ?IO b!9R,i𚴏,a%OÕmMJ } !PYZR4ʩ3^2#614NYص|jW5;}Eqr0Ʋ!yN? zu5*(CO ))}{x9]~  X{=T95*!03Z۴@jabWCdj+]uN$VGU ms(l|t2R$ӼIoqZ\fU${#V{.`4NDc?a-0Xs@fGI9n(&kdki4/(w::,mhi9"1b7^,;:E!\Y"Y¾:#Rr{֣DZ4 )O<&pDa/GUd`aP3HnA>n=Xž\dUՉf8G-:Wm0qv;:4DDomz:9aȂ ͠] Eq}Kmh̳)q]K|RV\xr TSq'.(k4y]ښ2]\CaU.rՐ''{ܹ ZIk`p-UEݡs*EK| 5uE4؛lP1Afq^/j*U)XL[\md)f(ɊvYzH7E܋C3e1kT_4:YnHEtsQtE8ZϪzM_qٔ;SYt F`G_cHk <z$& U}*u5&㛲v_zިo Q^,fZ-/v{{ި_2]ٱ%̆h\s3ZU?_˰Q6Ȝ5/_Al@:O7: )mZjek5-9Iunzm!Fyx͆39gpʖ0В~I~D 049  "nj7b̭n9x}pP0]ncMh%+7.iO*uȂyh. R27lB!@6> qM, a+Sás% ku)e0u^e `> ~*s'؜>#y {Яo4CrNp7Fш~;Q(1?\>TKF-n6JEҁ5xi(Y ?Zdx}xnc*VmsEm}!}]9%Myb,A6& 0t<8 QDS~:5e87rJSi5ԙC5,[~P*@n5;/zl#kĜ&=QEQL<{,D& l^;&QuaۘW.7ۋYWGlf-͑ҏU5v4l-lK7KOl'dsI]|P4O~ve5ok.wq-9V>3}蟄`\{@c϶š'SݪySnc=EBlU! G%%jCʴnӍ"u> LM%wת:gA*C`ožy)V%IJ//0Y%PS~0L䋽cd1~V?Gp,R0 rѐ~"=lkebQ6.2$%QD.nbM!T^~cBw?tTeSF8&/" ,榾%.܂8t7gwO?d%fH9i#-FÄU®DU'K@ 75kK=%IC.A( L>pg*`_٦o$l; 3/; TZI( dz`$ w6.21m[.&ʜheHsK54D*RkU)zz%M)pHj "t ,Jt &v+}$֋D_ #3c7ݤ=j^Q`H풒֭tģdbf LNt kO'nKƶ ﴤV JpP%YZN|[Uu}@!s2.Y SD.,|bK2=`U%<=^GD\Uj۝‚{Oe;'DNpw|y0!Uu, +4ÂFF9 /WCXn4驪.z-=7vZ;XM1KSۜLJ6aF@D.gM!k 4Ytj͙4%TQ;mJa7yc]q\tæD涒akT2yAciY6!ןn@UDDu4\RVҩ3qzzy}Kr◀5ȅvXB0#*Z"iL]rD)ƓOCu t_hE6]`)xw,ݫ_4.;2mEE4\%׆~}nlzn/tɑܽaU8H':ofcٚ#u#͈'*S"먃}3wܺ'r#r&E$^ H)hz>{&8gcڥZ*1PWk06SoҨ̺jE_M!WF 4m 4܃p'%/ xV pt {&lV#6c'}X!ٲ_ԴwAg8k@ fE7f7g:$6@y ķ:#% !䲾Y<'dvPP?@m`C)iNhelBn Ղ!AnW460  [jjò Ϧ>)TʷS)kzBe) k! 4όDrHѴ֍?=q8XV(CVaBN$IˣTKႦ&&R`Jq |Afs֔| &U_T 62&M۲`o[T ^t~2]Ux^In ʶl*8T{l<.IRŶ% W%xvAғd(|~x+Zi9nQ;+h\ %$L1Ē@ ëI#T K˹`_ .{$9 P֮ʼnV˪~\l}prtxA&_3ݼd% eX)J8CK) J2kC;p\ar Yy 򾋡z8@lMΜ͝|+YZC3s'i!:0k]ojV?!v%*,d xy7yOZωgļ(J<њ34 YGUku9g[5 00{Y-NrA(>OY0+W $jmjHbX?&BͶ1!lgtg77ˌĥj(1tپo4~ _k|% Y.mq;VKK#7ė,sG܃чЖvE(*# t k!YeZ }S-eWoKI*;F743,(%Aضe>ǜȯɪ!WzArآ~tԝcKK3A9zkqtI~PcK^l A~d8|xעݐc,gdE!+޲-o#޻dp'~}/M"ƒ9I>b23`R.v$l?( {e4iټqP Țf @>P.aQ)5?p-6A7e'ω}_rM[]b%MOGvY sx/ɛ~^Z#h~ )%)2 (SrX ՒS@)Vל8 ]f/ %gѾ Y4t.Oѯ Y³ziӖh}(AaKLw)egߘba:f vAܼLLR`љũjN"qGZ3x F/@|U9Vk59 K78db",Pݮ@v' #-,@>"S紤}uްD̓_T,X9G|eo%aGڼ0@uM0fU%Rkx SiC#QOqFY=@#VtMUI"a ,El5B`I3 guYt< pʪ0tG9\4-{^".\IcrG$o0`w7&kJ 2X9ve:d@p¯HѨzD%Fv];I@gFD3j4/P4pBx_G tRN[KsD(Nw1 w&zT D"q=T  34Y'#HV$Ob$GeHhp@TUlL Ǻ^q<}-"m08S 3)t]D55+;%TYD e6L >tEx4 n=liD=s4v[V0ō;Q0O5,Kl|t/ގV_z 1(SU q|ʼn67{wYӕuD="ELFJZ{KSŃق;N/։q~e^O$Eg2F?'t+jm?K+6.FeC@n,ң*z aw$GԚM!?kaL>icN|%olwi;7K``KY%O._o]Ct R2o< Oݘ_%-qKSKﴶ9w-qa[y$:c\ 0@OрxkTc"tぐ"ݥ g^%m *b{S넰["-Zv?͡Ac@Y_ jTe5'BY8vXf'!X͌nChV5 q90p)m6[Y'ڒv1k&_(LZ-{{q1ƱI&Ta:m= g\o[ϭZ >| GmźsJjې}XM]'¯x畐]dAyiR LJOBy\H#.B4U#Bdu-{k3 sZqx<[-w;el O oEQ *5z!(3!89b/8\2"«ftqp /h3<(2YTJbj3:㧱uAdxԈ'n|A"v*:. [}mde+t=hEn@ e1{H~lL՜VnL]4.'_uS9fpNM# O`UջzJ/3 ͋BYV"WNyp}Ƴf/{Wwl#=^7ov <7ݣ8kk裷6J3/!-ĢY]j FMK=w!gAs׏QQ5|L0C\4V{SrĘ>)G|uZ ێ Jmi&ʵ}OM›YCI̲',VEq,>Tb@|33#x{:Kak{?<%Hۿ0I6fef #Bl¹3::o)jڗ斿's<9#:,*>*YVfYHh0DbcV4?gWYiWw_orB~pW[a+X`j4"χ6=c95%r;^g?ZX_|ĦXEh[\:Km^nlg-souK|I!16!IxI!/cy5 d7!NV.?™_IJZgfBT?voC)~{rEuHLk)tyyJ?<ӫw1iʭu?Nz4w%1ILOI!Lt=Fg:5+8YuC="cDP^/iVw\鉕`<7z>x@I;ޚ}\=\"ܞ9߅-!ZGK͖Z_0An;`-Hk𹃠D|W+7n|IV5JVa*=vJ lΚ9("%0KtnK 9An {~iIx*;]"F6 Nm8. FHx)phEGΦ4mBIiPf$w]Fns4jss~ϙq]'4ߛ=MHJ5n o!T Ų{ IuſL4EEHQ&4z$RۑDqԨ݂[j@2 n1h 䍷-z *P5kHv񐵄Q]s e-2iƥeWZ6fpP(nӅPQ >koYk[GSK=ȎD!s&lPj (?FFosbN5[݄B2"#A<" cPiXC YRnI苌hBe={%9:Ԯҥ±a-0|e x̅|܀|V Bxm쟵 6GtHDҷdcC"1x8_VRy\|EE\=NbCW8ɔUAӶp+&sZS>3ŝUr 璣|‘ʏu(X)QXALxI:Qf3<@84.jxK|>~v}o&ywcxLCaQ+E񐚯tOv~FSMy*ݲӦ3*[:}F,%~`ltqՁ 8kJWF2q=pC $Wy+D#_HUi5@b6l^.ZP8Tu>mf_m4kduIEm4mؐ[c~ߖe˄w%jڍwԬ55e|q.߫R;̥GVW碁FKX7+5&ҪibZ|5z:*kJ4χX&Tъ,ˉ魴q 2ZbԟہgaF\` Ԣ TagX%ZصTm=ru519Qᶶǥw#[-!c<".Xx &pB* )[2su(TJd[׬Iz sN5/ĥMR;g H$pu[Wk"+v4W)fTl=:ݺ6A@=k߁aQo|PZݶoLNm^Y7c qGR'Q N BӬRņE-qð@<c(|8k5uyQU>U`v m[@ zi 5[*iOcif4 @νYD|>o=vwƮL28SwPXRWtکEcL/Gյ 0CIu衸;!?x{iE^r|b o՗Dpcːя͇wãÑip9 0A-DL8m#RqFQ#5$㴰}؟TokK亹~dZXRYz4t~]dz:kȚ<`)hW&q$r}lش)sX!'Tii#7KmZ;ȥ~c0-.\jseT8ddѤsmE'$ƹ!Hj`N5 q$řNSp*ˌMj4gO$07Q 3=&Ĭ&:¸sk;!=aq\` k8H "ZVlj( segC.HCX es;W\0Yj w@*"/Aa 0:ޜ/Y&,9m{ίH(0SXZݡϰo }ށt5.>ĭ1N(Wn]P,iaFϩnl$΄J]ОLh؞%v;7مrpD=w@>,S=FXжrNZQ>|a9RR- $纷;I++*{0ȉS6ћGtl!`s %*D|Oa;м z E֭*҇p/{M,gN#o+TH%^q*C⩳)|wѵǐdߪ7ĥ=L z0WEF)jwS?ͻk.[ؚ (V[cZeOh\E?Yœ9glLmb2K;i ᄫU: VkoɴD;292 !5HPպ1}!;~B0$p܏`Ua kۜA+ㄌǿFy^uUu!6P6];q0/.MTs}sr{"2Ư k*Rp.)ݳ1S7n<n""?,^WrfJ-K7b!H p)Cd Ϯ2e}k 2qke"F[ݕ ƕ+oh p Le_ʑwDmHԮe[k6hmwz3=%U 8`fR,gK+QHժUZdNR{ ]FkY(;0ph IDAT)Hd#HsuDZHo/,FV~xtrtCuީt;d%w]~:g=magF/ȏ~i)9Cs7ICq7`PXZ).{apҖ  ʝ%Ƣپ \7G-ubaP-2"/v+prOҏs 00#]7eFPʎKkb-aY#ȺoE9hپ$%6^ZT ij͟>"GUkDŚ=d"\5bC˸~JD/}{\af8<8..G$Rq0V&"lU=CC)U/z%վ~WbW-1i,׭:7e%#(kEan 9 OUk,;w8BoAvem.%6CEʴ 3p:[r rZE?d0LH5S,[?/{W'zk6ZҼUeD߼0=mky.V4dj 3b2B쳞'oh*苚hg<U[62Q]i-4.^]t ͒EQ+b1nѓ؛KĶ GF+҈HjxIg6e-cCO^’ݗvޝ.@}hX{q0` ǥEG6gNbz_,d=@tuՕ\+T¶j3߀cFwA[P,xe'rO5g3vgwOρp 6g- ;ѣ̌;EfzXkvֶЀi9}⨇s%~(`ӣ`_^h&Q~Ħ)iQ9=0l%¶GM(=]Lw8Pc}E~;4bَB7㞲[L#\yif4t&3KC,˖dݲ_<5[5YD'@@D=H''n5DO*H$?(t~PJޥ'n=إئ%x1&L9ĹJXcX{bKb}X?z<<:acֲS;5b呧y좧Z deJYфPdwNhgpk ;߮ Ҳ(Wv t]fbb7XT(SRpWFl` ~eHfwF%WiMəW>t]nG26ZlEHQl3,'&L؊[,ۣÇkIML a_inlYX+=&h$8g(i#S`T8,T#h_%kHZը:=ށU^3}%-EFXb=Qz7; ro%5Hn XgAX)%LYBRz'OK\\'Cj&,D-3˲IV$) (쭷K-b }3NMat3ҖyRT=ƪAP5UdW~]1ڣ[d\Q@6HL𞪊b8؂CA["&A_va8A{ųco (seL(QaÄ&m [ܮ9 sҿ79G;)VW:%oXD|ˮ0Dch*SpdrIR d 2sWe-;Nwiw8DJiS]]0pm;}<ڜщ;85a{,C(lMrfⲌx4ZfkkW:{~ec5_R<34&xw`AMpk%1}ݯ$n}\# [_BS8\- :4fhE<[=+f[ZϢJ8b)O⋗*]3CbYӨR =DLf{>X~95'zfr;ZT<e1t%G< }y{sK;!_{\odi [ymAnt{&@oT5(@[e7y'jL`)fFAm ,C1jjI Tj{9]t$,X6p4h//x\d~(ZndD-?RJ=<שwVWɳr|<>ݛ^ ig9?-:c՞W7OV5:i6$*f}Mmt`.BEJG/ ]]=s0[(BޡšV}b'Zl_1p?tjNidaϠ<\R#5e~Y8ڍB_`єb-ۤד1~]T?Z:-)Y.o^VTks|V%f:%DFS,^Umg) >?..yw"ټ(A~&j "eac.7V~bva{Ig[TC|`.]ۣF.R"ͻXW("\W:a՜"B[Z`cg,o6+Z#gt8iw]:ޣUCG\'iɥwX޼JcK!S77@(;Jxl' ]z"ijqWԄ>: HF `zш8'iιTks/ ij(*Y+Z1>jrkB v屡,XZyF˂0$]4|ڋ~= -VL^|֍R5Gh35&rf>V^H)I^B|UgŻRĬ+͂ze("8hs#\*8Vv}vXyZo`[<͞Q7媉/Q,2zح<$B\l1>A%r5u'#jX@71bwQk(k6qDk Zt|,1Z%kk([S+fls3m)j{Ưa1AA߾; X5Efi޳!e0>,T@Zܰ0[맞{TȦӢ.HˆpHXs VKq0]n/PTnӞT;7Ғ>{o}F #$xŰ1ɌL遀(M6mLە֢lUi4"4Ιdix}?cE{(59񆁻^u[2v>7̵^q#ZcS3Z[oz3 / 0#rH\ɇtdRt]Kz~osdG xͤ+'r&2e>Q{J w5!PSut11~?R(aG΂)CO:Q+ԑ.td~# , Pܫ`ZeFfe؉W](΁zC3W>Vn2Q{Ig{5ǧ"Ӑnߠ_exΰ N8d-Ⱥ#-OOezο'xbQ'#Ô<]:%餉a N1*?rL R#`2Fj0fyo_Y'>,tAE!>5>Lr(D`󑬌E`Χ-M3S]Sv toh2݇ݡ7)41000!gںV>XqGשɃ'?`/YT))`o,/W"ȫz;5 :ϛoe4w6E\~hRnȆa99rY#EҦ^J$cEj [cCyCK"멟VT❒(lcvÁ^ |4ZoUtzoݸ`*J>:ԓm>R#?\$Mxm*]` 9趣C;yv55Ȍf!Eee gɁz4yVohmojFW ;r%?agTS )`[p0Ƥyz~kNxlԷ[lsĂSu7-~!&E.MqmWN} t~|LU);5^?#̗;s-i/( T,oi9s?S7ۘq4!Cbwo\ym3;'siSLu+bZvKXb܏_ dO/s I9?^۩x%9%ߞ"2bџXqUIyNjf[Y-pNStC<]]+8]2֔VMtbF jɶ1RVONVPe3Vǟޜ: -Pꓫ=:@`Ky=o]C9e2"b#j|\ڗLD/[iK7L;;&睲ں-ē9i:9A5+ky!)аhԒf5j7tE6f쀐->~07'FhsW+Om=7t/\sӨs) IDATeDYU蜖˃Ѻ6X,ONn}mRtB￐L%XlHM;jn`py*v$U }9/-!?pa*9ۤQs\4ܭa OT]4*BaJV=˟__ vwc%R l oz\bm\O'7uqD yy3]+tqR ͅy|u`E%=X r]a?3T;6Qo>g: -X ֳqھ=9#Zww2GvTjW_6XNgYtRa?RXKƽ kp'/svmZMM F~%5,/NZTTAN,3#d'e99wk_ lPhGd" gN՜PSb`Hf~\t+lkp Yw)5A:…`o/z{uT*_.LG!ZТ˲,u("''TRȶ 0MUkɍڼӣ=)"ӵbiSZ)MGjym!@};P) 4.joKYjS,IC7AfR;#z3Хwg?΂$-9B G=!Z^³_7 D`/QAйzyu0 4N/&sѨPJvm-M[u!/m,=[?uGcjn^m )p98>âͩ2mˤBXc}̑::t8c9Q^nTt<\-=ï^ep 'P={q^jT߈~XyKk2JZY:~9H3m6Ԝokw#5(<9@e;ݴ9IG'Mk9Sw&T r1=#XKO{i`tS+f<qcV4+^ ѵ|8iL Zn|hF<krC@˛W%}[$.MRfH6?H7.%ZkVB6uFۏNeȧz'/ԗ/{ZjfhWtq(~}(N\e9&8YK/g/]ͯ?U,5 גhG~4/h ` &۷WbY?jv Zkճ7Anāp 5ZevgئA5' ڷNVfǖG~)S w!eSN5+oˑHؕyߧb!,(:OLe-׏s$f_īb|ka I;iWk$o[rl>#EA8X@ 4zj_2k lxT1}nbeϸgy<˻x>_ҍ7u0U~$JGKGW`i/ܻ(#,x19Y>LGfV~AQ&xV|-2Q/`9Uqok+s*0jn1nH%R7P(ѬcD<_Kamxrstf6tF8ͿiH8c赜ujpPKd~Mzmȋ|z)r\G-ߛwu~_7y]ޱ B6 y]3l-kv5=6Z76խMhk#`Ӎh<Tԋ;zRDŰ_;߆//_x#35v}1&2~JHk]*8z&-lrYl0K_V 2^-/H`(ܳ듮ɨ(L Z cڸ<&h*91FoZ[D 5`*}%k;nnOCp0'NdׇL:7gy Btcxjξ) >w&٫jC;5șkwKMڠ- s"nz+q{!99Iҧ~) !䫾Zo;biB\]>:R81?(ЩW.jˇl|vg 3?]1~Ջč $l/|ڼIe4J ݅L }90Ḋwrtp6_ۘy$^eo)a2Pa5 W~yN GTgCSP%]kPJ oa#;+{_f *o '`Rz$"rT5̩I wµ~[,vo m`Vy#$-:"`͉80oQZ?:ÒL ϭv};Qs-mduvBh%&e#g8OOH$LٿoհD"ivn^v* wVw 9 : [-0na?.q5q[?s` OM⼋^ePH_w?@8ƺ j!l#ǼPfԶ橓XovӖ\ird4^}_+hQ&ploR;)&kB;MhZ.Xm%7),X^RKQڊБe_N3ZA*,{3T]:ϛg& ]Yi{u|z֩"6>8u'[eϹo<jF9Kr2ܴ>Df#pm(p4²yw>kl\APn#<L~at'>uMer?6q SSt0;[TLэ/~糿&ױ$C $7 !%=1Xah(Wv%l=5l:k95g a2'j5KQji;T=}GDhA_Tأ&zw'0ƐSmvkk!@X%H?TװHйMlcm@˭Xt0Mmߥ{ؤ` kL: doߠOF4 PiCjlLNw w$&F&[9bUŢ$O"fmuJ57q$E@!,,ҏ@kaaemr?0?!o7UQKEH( U4 TcvODԚ܈A7<еxJEϬ&(,j@ӭٓPl<77(vO8>v|0 Dwے\+bg`, ĭfvflZZvd͹0q ԅϙgd㡆udpGq$Z$Zp4Yػ>Gi90F4 6ÝMnE%* AڢHyP| mq>&njְ‘'<4}>w(+KH$8F/)" axVv mk=!IR7vU!D˛.eLP A 8@<;'}3#6 ̭%I˺CE-H@[0&z*KĨt S;w`x +}=؎Lktv 7Gua! b-$vcCvDc@%-<1X 00 b|"Q}@?s½%ZP W.OPT慭~N`滉`]Z3/NF0X&N&8&*V/J eQLM{]W"O{ ;ڴM]xDC'|—)>S< 2$[/Gỷ.]qIMDy _R^"+wDEk]jMYM=icߏA.Hұ Km@Jh@|\tnݴ>߲}bs,(^(V0.t=̄'.MP`сKw7.g{SAР$$:͙diFO}iLtӹd.Z>i zl?Aݕvo#Q|o ##hã]91O"WA!i'Pon ~s~ (_$*:5gy]6QLݻa۝ 1o7krY@c,O`:`l*˳OnmMŰY M-ۄM/`̺z6O VNT3.0+LŭŨ;޻vS7eKxJ^C7yn74qm'%xlh1q^uMiOz,|@5kL*(s6am[!^DL_w߿᝭V a-@2dc:hVo߼nJ}\2VFR Y~kōɋbm&0Eз8qy\F3oܝh<;g$lտŷZ6 s`i=C{ [ClAeNxBtq+ mA*w2$ml6w'f~c Z+ߌ:D#B{٠+Ѕqܯd,s/=K(}[=G +=ؿ;z߶n2ܿ?ܿ{M5X5+:oy0Zrֻs(J͉_#Pcg.dvp& k%-`܊%sK AM̊ v9vQYCmpa3W)&Y}xL2a 7s>!ߞuTXWzlyyy@$0\'tPU7ўZNN]ؖ|ҳV`;~SX9MGF;J\S&Gy/ , (== ;\ŋ2f0&Mg'Ebe)]E> aUCi#i/H19~)M X;A E$#0, Av׌Lƥl*SEeJa滨PYR;;J,zsIe֭^T smpib#4\Kc 5]bzV!"taL;䍏#éxD& Ж% B 6JTK-=߿FU@55AbO4WѮˣ~x ZG«=Ke!O40/61R-2,~N<,} \`󠇛H\e0L0R 7_SǾ$]@d*< ջ@e}^`KӝMNqeNMWriNTUsaSV0֞HX˓#e Lxӵ 5lp6eunz4^|pkw/[ nKuxLnφ#O6<隆c:`An S͓M< ވ*L?+{AHǿ[I{" &/ +]6o$W> H2W`a1AףG@iŝ-] ϬYMV5f믱Rz?{BF UO5 *N.3J&ad'D5M1~pA-j&l 917Z:(+ j?Wnk~Eٝb{^UIČ1OT?4Ϳ?Nno2\<9JQ*PTdX0wm^ X%)([5Aí zLbgP,V s%D_Ĥc2J& ocuU]Ӣt.Lwy0g _\/bnc&+XlM`" [Lɪab^]|RY k9*1Ƚ\}~p76ʚ:N pd}LT]eEl/-EҪMZ#rɛOT_RX {cXצ=[VKL=׍<2BTgLk֣o] %Q\/nEG)@lT'.@a*6 s}'eȳ ֋Ńރ`OPHf(/TtQuVFAzo/$dXƎ7qH-"Lz' E%"l+͞drOOa,H=`Fz &=W*'1_F?RvLR&-q2nۀ@¿@ .q2<既FKP:UJp~.F / /{|tk) ]&AFT < 9V׹Luu7 d] IDAT6ԕo0럈k g`Uy2w25{x A=$ ̃ :V=T;xN2o՞`_Vj8; <#<[w,}[<_b}xxy4S͠/SYdzLxЍ|Й#:079lMZ}Oyp,5HE, S5Rm Q#K4D{(| ί+n]ZY[Yw^RJ]Z"0b>X7*5/|m¦@m=eooO`MC.6JC}|u} l ƞXxbR22}*(\;`̖x'RsHCV}# FZ(OPB>15eaٔ( ȥ̕GW6O+RV> |1`|03!bC;Lo/kZu&pCcщ}&)ƏgztMB AҐnKB;&}U&^FO?B@JQrEPI|[@I~1l*~}vl{{_=c1`Q~~[yM92آ>S5~8vfӺܿEj?P]"f=ĕp4R;~@&W?azA<\apV AXiה7cxH10񼒹0,oR]=EIH"8@0#t,"U)@Y|"P}k 9}]<\AXq"rtኦ _ }Kr<ggw_>vOqjiUԩ*`E=ӄ?U[> ]Y+{b a+A1y =LiFcŢS: "$0~|(jB}0٭a'm 9e7[S/;ۏu+â,PdWɷ 7AJ^/dYǗgt=.=K/HD7.*qyĴDqI3b:fy(Jd_#" YW-|tBfA\$.Y?eǸPD 7kIa5i'i&V,@ ՀB0j8lbLϓ ֎9O{J^n:c@>eөnMv<Ѩ6Aw.̕>"we_9q( Hoirv.mL7x|Ov\3'Ld'G6J&@5M[`$~PS "/j" QD\W,_4H&;%{kP| ` t|`"e ZҒ,]{{Gʃݹ+15E"'+ #l[B[CWK(qḛB_ٯSoa "Ʋ,[!8k7֢iNc| XdV'3!d$+g %ѓp{hj*ht't<$$#oaR%&|9H9;|!Evo)S֯~ 1 (0?<&ӤnuktH0qJҨBmt˸gWG~|tTwz!/g(5K,<-L@4 'B=, bm !R@P tk7,p Sr(:58 L4(sVd1M>}[ &M.l0٬ PN>ma:ЀTŊlI1D:p܁@Wqxn7XE|wֻ_I0s$:m1Fe\(]Ā{d+׌.`f)ppSd`M dH'( 4$)1t[cKFK]7]D'جܟ{p6Sa~e\j[S}(4]Y0dWVGˏ_>}%.ς>AXÏG$ ޻o{1Q:s)M\NJ)WggD= ɾAnjW$lN'l9nH#X-XԠ"_HL |&ޠk <#zfܺnLM Xr6pLsc`]Eh`3mq5_s;Wގh.J;W>Y~&ۿg· ݱlO2zhsh z3ĦT:9y<]9d1Iz\js%tKb/vZtc L ;5u+߬GCӓWRm d1nw]զn9rv[9?le"%4k@m_M5p+>w-1?,ȭb/p"r5 hd1]"!oM\@r!MOp6sf5A܇3HZJ\w@`^I~lW˒ljtQ#~iҙXAZu@6eP8$LӲn6'VP`:5egzZT B#1?L{Mu2Una럍PIY,>v"/c~$NIOh]9ҀȆDEj)tkz)4߭iE=\BˠrGٽ>< 8 !h|e2xVF}~ڝhZՌ8L<\sn閖rD<L%% #xJ:nn&Ae|S>$I~| ^"izO< QY%^7A Z, e @-M]KF&1Vj:7n4x@ (n5Z03"׻U-kUAVXA mP`re~ZBxLMOD;Ib&yw@F{XvG5+4Y;n [\Ͻ_WkBTx!VJHlStiх{4YFIP,ÒJU{t-gPkvUkNT^2`QFUWzwz3E Z%[ 2lF4TD@_`?,| ͠kӿ8YgF/isZ>m V'6rZʴk׍74x[DH+a <ԁk۞,$/@Yar<+vTuS[6Wyli#[9O1=h-͹) ;[/_~f?~ ts d"gR?Xb] ?¦H,E1Md0#Pzi6~w,% -F⥷υCprt$sY 3-%K 7~|x~b#cD": o H8t!Z5uaB2Bkvxݲҹ""gYMq0c4ĿxS4I2Eܜ_)&HE( WΝYP+Z*:*^[n>࿴ k狈PĄ?N^OWhXaLxx-EO Tf7Oi59q.^$ožyUz.✵OPKgHn;eS0"/XlJـlNSݰn6V6"K~}ld]g`"cR'1Q53 +106OU/k˕I جD},ƃ.1R<']l/QЂ ..Y+?R { a?+=H.Ih:DOa2h,ᛜUJHWU;t$։_Ts뻎{dik~Nl&*^٢xi11Y8eN% f0a9/3 r3QT͊g<'3|4 zW:mzT̋[VsV8pkvG@8<$<6ב@lUYz&ź@7|Ԫ-L7 )O-lm%>Hi%х6B\\—I s"QT+U>ƑDZ;{*20$Do.`"Nb-ŖQ0H^Dyێó4_l.C霟H:̭Vc_JYfwSoȴxBngVIsbQ Ԏ*~1۩P\:#X{U/oA≤ 6àbpu/ttjϬ :0+hqMA*}Hxi ^?kiFCFSzQ;, H+03xhZh) bpyT5ryj8ة~VaQiT4zs}}Žk+S Rb,}6qYŀx)^7L63 8T/4N ,L&a4K 1(|穱7 pImFcq$f6]Yh&Fj%) PLxןDXSk g\;!;5d/"0bƧtN%'D60o=`<q wD2O\|j gȵpˋ.A %=sۦ99c9{Ky}ZoKqykn>*-MI!*l44S;7Y`nOa-x>zl %.7'6sD/-ϞԼZɡk瞨3kjhF "$+Gʇ:Yc% 2 ~; FN I'!Xemfs`"&8(Zs?ꠤ[4mʬ+_|G;~::3q*{Tº\oc|*--7maoInKO1Γ0t_] ߂ t1yO)1js4S̤vkqLOnX{_/GFJ:^ :6j 7aX PmmOR8s3V5BXw(K4MFTeל,c?#f~fXީELV`% ӑk̂0P[MLMLm&̷'SWn? [0ժKnMR͋gN7OkUuº3 Wd\Z ݪp@ $UtBժ5aד+"ҘSA'F(doYa|f^ wcZ{7cQvʵO[tjT갓2hc}}J ~niR)_IED+"OIL#\@+9*Q.5~\uX01) 苲.5ʘYU^-΁)BeL{*`66F-&*A^GNĊCr:ZOȧʃE[,T]S8sF$˶x+! E )H/-1mQa!NףL52SFCD"ؤR8se2\7@%-x͙{NÙ`󿬐rm٪Ɍ<,U5!־ Պn3,ˣeC+ ;ڠ$PuMh.)S1yN_|km) @RڹqJJ`bTR٭ˁD-aY[TВw&_ևSqVMXLleH<{Up8nh ILGŁ3+BN:`]b%$ZpLW@9 MAeD6qE%P ^1z3߈]g?7j'J[RX>1\FU7""Ϛ(EϦnatqAYD(ȋhTzb"([[rqI>FNc%.G hQ Yl>˚ٶklhGg v{'l ,oIMHbo$R $l)G_Dq/cA/bCɛJB4vIL[PR>$B2^(J2(EEcMlG+!<VΎl>ggK3 ̲$3iy5A^k7G2@B'ۏ^ѣ~|1$rQ4lzΩ9U 6ְ,;'mEg.h>)ࢸNFлǯB"#~WICJU=$4äiI&e=E9ً,eqDuh΀"SNGNU6៾%>#nhScb2d ?L,*ϗ3CV+cS@<cVġcX_q D/ȡ BAfzSQuh!I !EqXhjU#Xѷ?OOkt/ 5Tile3{jmTHaD8m"M(Yi8tk#cIZY=޹ki|}P&s4pBxC`5scЁk9UExpS ǯ~ȟX27-1ZW-xƛV9|ݑu+ނ@۰8X>X `qbz9әp)5=;5mg!Y!A?TFel-iyD2@KYXXf$D ,3[Z!] SNE!lrG 򶋡zP(о.Ƥٝr NQS!DV<(yXfs1IZsSs;l0 W/+XYaa*.cbU,\p`Wĥk!*@k[Dci1xm=ƋGGb)8{L EX\c=BhJhݑ&b$t{FLd QrA3ӈXn}Аx_XTrW` µLgHXz{w0sȻ#{# )hSOk@XP`}+̦Inx"Mָ:uMfᑏ)@bVl.ȸ#L5mC!@лVc K[wݠ4H7nDҖgwvu؟{%<_P̵>3)*V]}:|-ZH@\_ (`x@v \¯=rL`!#]rk6{ekd Ǥ00-`7sl* JDN!AJΤ}vjm@ceʶWtQpH:2zS:QNdH(-KL˩=h|J*NouV'*qFZ0&'/6ږh\ыlE@)Fz+8(4@^s 6EVkFqhEzou8]\[=Kk[$v''biheJ|BW^$vjca`5xt[`kgg ݹˉNTiK/K;IE"Z ^]j{N כr S+BeTr:-X[h,+R?d[ !٧x;I bt /;{a@ebF 1kmLWs9&eWzv4g|\I cs\|̅E谁xLzS1{L)jRţu<v976}9[m6~[Zw/.8u }> ޾kvAypOB+LK^D$m~<hpQm89:mJ'o3 cbקKVjVLѲ/nYRgyK=;|$(iR5) 1y29h'^UXCLA*^Rн )),0a֏v-f9ڂ-qnXӨL0tA!x;Zd}k~}zi].fQ{K}kk>Yo]k HxV۪Ԟ5ml~Qü 1.$yl rHvۗ@5X: pݻ@&y#*_i'<0* }zC$^v/{cL#n@h'Y>661e7!Y5s"c :T+vYk`=WoJ#KK˒d[ IQD m2)MhzCb\l`@;=NL;5׿Ν T٣팞H=(} ͒DGc,཭gY7}HخFbyݖcRCcPF%.ZuKZrs1Y;ss3 GUm[٬g2bQZ*I\.Hkv˳(a4Gf ְ\tvT3̷Rl j3Eqmuh`ue oC նK]59i)/R-[BYBri֗ TtuPցUuTJafO uG$RX R飭Mȷw~\i]`q=XQPX 6~f $dHZ"U`=ɇZ0ZZQsT1DTMUɈX&,?&_r*2HSL<١[v:ճ7=U;r0yPI: EC |ӵcnGӒTGWϤDX2j69!, Aa- bޙ6=ce# IY˂_m^-M[9&w*J8 12. Validation: Debugging and Analysis


12. Validation: Debugging and Analysis



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node205.html0000644000175000017500000000470711672746162015651 0ustar paulmckpaulmck 14.2.4.6.1 Ears to Ears.

14.2.4.6.1 Ears to Ears.

Since loads do not change the state of memory (ignoring MMIO registers for the moment), it is not possible for one of the loads to see the results of the other load.



Paul E. McKenney 2011-12-16
perfbook_html/node112.html0000644000175000017500000001551411672746162015644 0ustar paulmckpaulmck 8.3 Lock-Based Existence Guarantees


8.3 Lock-Based Existence Guarantees

Figure: Per-Element Locking Without Existence Guarantees
\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 int...
...nlock(&p->lock);
13 kfree(p);
14 return 1;
15 }\end{verbatim}
}\end{figure}

A key challenge in parallel programming is to provide existence guarantees [GKAS99], so that attempts to delete an object that others are concurrently attempting to access are correctly resolved. Existence guarantees are extremely helpful in cases where a data element is to be protected by a lock or reference count that is located within the data element in question. Code failing to provide such guarantees is subject to subtle races, as shown in Figure [*].

Quick Quiz 8.5: What if the element we need to delete is not the first element of the list on line 8 of Figure [*]? End Quick Quiz

Quick Quiz 8.6: What race condition can occur in Figure [*]? End Quick Quiz

Figure: Per-Element Locking With Lock-Based Existence Guarantees
\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 int...
...spin_unlock(sp);
17 kfree(p);
18 return 1;
19 }\end{verbatim}
}\end{figure}

One way to fix this example is to use a hashed set of global locks, so that each hash bucket has its own lock, as shown in Figure [*]. This approach allows acquiring the proper lock (on line 9) before gaining a pointer to the data element (on line 10). Although this approach works quite well for elements contained in a single partitionable data structure such as the hash table shown in the figure, it can be problematic if a given data element can be a member of multiple hash tables or given more-complex data structures such as trees or graphs. These problems can be solved, in fact, such solutions form the basis of lock-based software transactional memory implementations [ST95,DSS06]. However, Chapter [*] describes simpler ways of providing existence guarantees.

Paul E. McKenney 2011-12-16
perfbook_html/node336.html0000644000175000017500000000626211672746163015655 0ustar paulmckpaulmck D.1.3 Implementation


D.1.3 Implementation

This section describes SRCU's data structures, initialization and cleanup primitives, read-side primitives, and update-side primitives.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node441.html0000644000175000017500000001604011672746163015645 0ustar paulmckpaulmck E.7.1.2 Interrupt Interface


E.7.1.2 Interrupt Interface

The rcu_irq_enter() and rcu_irq_exit() functions handle interrupt/NMI entry and exit, respectively. Of course, nested interrupts must also be properly accounted for. The possibility of nested interrupts is handled by a second per-CPU variable, rcu_update_flag, which is incremented upon entry to an interrupt or NMI handler (in rcu_irq_enter()) and is decremented upon exit (in rcu_irq_exit()). In addition, the pre-existing in_interrupt() primitive is used to distinguish between an outermost or a nested interrupt/NMI.

Interrupt entry is handled by the rcu_irq_enter shown below:

  1 void rcu_irq_enter(void)
  2 {
  3   int cpu = smp_processor_id();
  4
  5   if (per_cpu(rcu_update_flag, cpu))
  6     per_cpu(rcu_update_flag, cpu)++;
  7   if (!in_interrupt() &&
  8       (per_cpu(dynticks_progress_counter,
  9                cpu) & 0x1) == 0) {
 10     per_cpu(dynticks_progress_counter, cpu)++;
 11     smp_mb();
 12     per_cpu(rcu_update_flag, cpu)++;
 13   }
 14 }

Line 3 fetches the current CPU's number, while lines 5 and 6 increment the rcu_update_flag nesting counter if it is already non-zero. Lines 7-9 check to see whether we are the outermost level of interrupt, and, if so, whether dynticks_progress_counter needs to be incremented. If so, line 10 increments dynticks_progress_counter, line 11 executes a memory barrier, and line 12 increments rcu_update_flag. As with rcu_exit_nohz(), the memory barrier ensures that any other CPU that sees the effects of an RCU read-side critical section in the interrupt handler (following the rcu_irq_enter() invocation) will also see the increment of dynticks_progress_counter.

Quick Quiz E.7: Why not simply increment rcu_update_flag, and then only increment dynticks_progress_counter if the old value of rcu_update_flag was zero??? End Quick Quiz

Quick Quiz E.8: But if line 7 finds that we are the outermost interrupt, wouldn't we always need to increment dynticks_progress_counter? End Quick Quiz

Interrupt exit is handled similarly by rcu_irq_exit():

  1 void rcu_irq_exit(void)
  2 {
  3   int cpu = smp_processor_id();
  4
  5   if (per_cpu(rcu_update_flag, cpu)) {
  6     if (--per_cpu(rcu_update_flag, cpu))
  7       return;
  8     WARN_ON(in_interrupt());
  9     smp_mb();
 10     per_cpu(dynticks_progress_counter, cpu)++;
 11     WARN_ON(per_cpu(dynticks_progress_counter,
 12                     cpu) & 0x1);
 13   }
 14 }

Line 3 fetches the current CPU's number, as before. Line 5 checks to see if the rcu_update_flag is non-zero, returning immediately (via falling off the end of the function) if not. Otherwise, lines 6 through 12 come into play. Line 6 decrements rcu_update_flag, returning if the result is not zero. Line 8 verifies that we are indeed leaving the outermost level of nested interrupts, line 9 executes a memory barrier, line 10 increments dynticks_progress_counter, and lines 11 and 12 verify that this variable is now even. As with rcu_enter_nohz(), the memory barrier ensures that any other CPU that sees the increment of dynticks_progress_counter will also see the effects of an RCU read-side critical section in the interrupt handler (preceding the rcu_irq_exit() invocation).

These two sections have described how the dynticks_progress_counter variable is maintained during entry to and exit from dynticks-idle mode, both by tasks and by interrupts and NMIs. The following section describes how this variable is used by preemptible RCU's grace-period machinery.

Paul E. McKenney 2011-12-16
perfbook_html/img309.png0000644000175000017500000000423311672746052015315 0ustar paulmckpaulmckPNG  IHDRAȧ0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAThYMG~3SӞKE(F!d!. rD.eo\8^[> eK8X!+8X7B9Hc&H鮞+nuuիW?WkRyZj: 7k,K @'de h;i [zSÁyB =~/Dp^i,CVL%;ڿ6Rp8u+0"ށn^w[z5o$:`7iFք P|%PV$iB\YlDYKm*qZ<O<F\>yz* ??jZp#D[5Oj^< fnfOL:mk+ϔHʛOPѢ*+Ӓl5XK6gBa8L=bHHz_"eJ&C NA]Y =kej`=r>3 IG  <l6K8R%BQ#d ?ܛlIPޏ x9oVlٸBޯ'nP,VxŠ1 @0Ô(I β[2#V`fȬEv+퍾=~䃄Әs6]珬?'ws \V³v~fEzY/v+c†BQwQBS`M7X~n|,DQ{;9hh&@F8P" 1?UrcsS\xbHN&GF))ѕ,s(׮7jsbz拫e|5h3yZ zξ;'H3 *A?]HN_qswlJr)TMUiQxgU$ |W+rNtPr/ۗ9p\M 87kWqH=^TU?VX? 7di9wEmD$@.\4#|i1*)>||=`?\qOW #W3 F{ =kαT<cY~"~L?sN^p?" dxX~퐆1pEJRtœ}\b58_# ?n_/-j7ܮ0Mdkonrmd9dUDzM83 gx͗F0ϸ_?ʵPߢY}۬-Xclk Xֶ3XZ^ZcX-7ZڭE,62{[g8OGt"i*>Y:Bq {}co[U_ 4.1.6 I/O Operations


4.1.6 I/O Operations

Figure: CPU Waits for I/O Completion
\resizebox{3in}{!}{\includegraphics{cartoons/PhoneBooth}}

A cache miss can be thought of as a CPU-to-CPU I/O operation, and as such is one of the cheapest I/O operations available. I/O operations involving networking, mass storage, or (worse yet) human beings pose much greater obstacles than the internal obstacles called out in the prior sections, as illustrated by Figure [*].

This is one of the differences between shared-memory and distributed-system parallelism: shared-memory parallel programs must normally deal with no obstacle worse than a cache miss, while a distributed parallel program will typically incur the larger network communication latencies. In both cases, the relevant latencies can be thought of as a cost of communication--a cost that would be absent in a sequential program. Therefore, the ratio between the overhead of the communication to that of the actual work being performed is a key design parameter. A major goal of parallel design is to reduce this ratio as needed to achieve the relevant performance and scalability goals.

Of course, it is one thing to say that a given operation is an obstacle, and quite another to show that the operation is a significant obstacle. This distinction is discussed in the following sections.

Paul E. McKenney 2011-12-16
perfbook_html/img80.png0000644000175000017500000000034211672746127015231 0ustar paulmckpaulmckPNG  IHDR r0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@f`IDATc` 0tq@rpY$H,c 0r%0-P``ša-]D3؀( 4Aӄ*S"=v`Dn4IENDB`perfbook_html/img165.png0000644000175000017500000001433111672745751015322 0ustar paulmckpaulmckPNG  IHDRZj6PLTEMJK# b``mkkiggXUV856C@@wuv.*+|zzFTFtRNS@fQIDATx]bA@3LigTDj_2U_'`১)?MFuՇ`hBUovC.? ZΆn}$E\gVGG2nTc`$Lf ޚpOלt+c<|Xum=5 ftң ; CTǗm 7矣2gXTF 5.W]Fz}lk|hpAAϵ;t:,'}l=jL=7:j=W.o)k^ͳwѶJߣl)7jiPh|ju{a$q;C6tg<S0Xfsx3$z&fuOí- GCxSΟls}m<yJ 1jcp/ +bb.Љq'a{ D>&\#eWVītM4*jﴴϥ!n=Q ܢKkexf>j Q-F₃]nD2YS4;`pJ犼Ol{̖7 q5WX@`iw۲ KY,*OT Mt[gr`wg\}IekHLJ9S]e/ tտG Enno#˂ ^6*w}A0^ @>>ɴС-3j~5{܄NCZGt> =@ 7qnT-'jd9Msg L `L`6Deo"JsAGh^$z: 3.6)h~uQ( >D7LPѱ  AgqbcJri3#rvxtl<%fт ; f9 qu(lnqdpμws\@&pEOf-tBJ1g?QG4cH+Xb"y+%ݣ7]A2S"X Js>n(G6( \/b> ƚ_%*" @ROx|,At6>$^EM8f!C.pdܗ26wVu 1hjRAj%u]=:`@-mKװfA&ዩڎR,ļ5}׿ $'ͮeFRɨ2bJ]M:i麜r(nQΉRxl1!X&EX=duUjS^A]]yCc>_ m탐w (f]1sn1rv\--6yp]-CW 5㻆[!p5A-Ő Fʈ.hUUSN& s1$YOS4eN(Q6HN'W{d14" 0 :g%/-Bu7sV_&&umdGl{c2ǚc@ !Ą4fs`#]YyXW%8S!`_ MZfK9jҕԊ%cb/II夤U PFnt{Eu, }٘1RWlGm 7)ɱX{L⼆0p ,R^SdH}_2˖`&z& m]/ %7CA<ꕣ([;mu9'4:Zopl}"Դ0tl&RTI&ZOn׆ XI3 WPGd9RF߃;or 3Z z%3 0<>IQ_)I/7Y(.ȩ2rEZG0Ϳ[QnUmL+ݭ^-ـc_T  A^PdtyRbk% ˾7O4^ʩ;il;J$-Sw&7$P\*W ͣ e _ɷYΥQ{|N#hL1ߠ1&]|m)HVl#V7dz8 C> \] |cI"h]^Zp`dy)B'Ա?T xs dӤ`v+5Ɖˏ5.5۹IۄeG-A3h] J*mr{>Plo _0WM͘SZin rԌ A^V<3ȱL$IU ?T+zB! q$vCjmLC<w?[C(]&]YPު^Q4u;v`b (0dډ.awe z/+RL8G ШHL聪tQ|0ٛ *7rWt2iRKA-.mkrK붖t#j"ۉktR ʩz -pS,Y#;p*J|B6&]2N2Ԝ@؉M07p4aŶL~.hd[vFRjZ8hEm-u=)"uؙttpYxU|6<5{ĬRV Po[,^ӐmL7Z-QTHv-9Ȟo毚!:C|׮2U̾n(aO; =ڲp]( g5QPu,'iN8:."X&'`B |g>gO8WGvG0D'|O}8NH 8 t;!oW n )ڛK.lR0R7^=Ks?>uWsGʄ ?#'2Ц^VJrO{ ߛ^A2*wo O(Ωr{@Ⓜ>1;e^5񥫜.9r'}T=I%v^H]tɡ˼Yw2JAQ'I W9ߛt#?#R/ꚷ̹?BjP8#$$3AÏ$T@jDX1Lq%7_W/*XhQkMpg}ݢy2.PK!K}oKzQ_AHjatI,dfI"z :Un8|iS' U")7B"+"N|_pzĆ|o2O G &hAYkzRl%+W9Z̫'CiZAKMK] k>l:="UdWP3;GŒ2 NXʇ+^=z߆wOcc?~H}]̚Vp9p yIaG(ͥ8iԧ?0[lB@mn,IJqs/Kq(ű>:!bg!(;@[IP{-lV~?>qٔ\/=BRe%)¦aOтݜb@M)f0}9E8InJqSěRx9oĜe%|~*bX Y,;Kx;d*/eٝ$;xTXw\:Ivd[)߈/(!NZ:B'}]-urU#.Yv' Iv:nV|x;:!iyu!s^ޣ_<M ǷHط*HH[b/ƾ"n56[[cߦ෩\DAvIENDB`perfbook_html/node83.html0000644000175000017500000002476011672746162015576 0ustar paulmckpaulmck 7.2 Design Criteria


7.2 Design Criteria

Section [*] called out the three parallel-programming goals of performance, productivity, and generality. However, more detailed design criteria are required to actually produce a real-world design, a task taken up in this section. This being the real world, these criteria often conflict to a greater or lesser degree, requiring that the designer carefully balance the resulting tradeoffs.

As such, these criteria may be thought of as the ``forces'' acting on the design, with particularly good tradeoffs between these forces being called ``design patterns'' [Ale79,GHJV95].

The design criteria for attaining the three parallel-programming goals are speedup, contention, overhead, read-to-write ratio, and complexity:

Speedup:
As noted in Section [*], increased performance is the major reason to go to all of the time and trouble required to parallelize it. Speedup is defined to be the ratio of the time required to run a sequential version of the program to the time required to run a parallel version.
Contention:
If more CPUs are applied to a parallel program than can be kept busy by that program, the excess CPUs are prevented from doing useful work by contention. This may be lock contention, memory contention, or a host of other performance killers.
Work-to-Synchronization Ratio:
A uniprocessor, single-threaded, non-preemptible, and non-interruptible7.2 version of a given parallel program would not need any synchronization primitives. Therefore, any time consumed by these primitives (including communication cache misses as well as message latency, locking primitives, atomic instructions, and memory barriers) is overhead that does not contribute directly to the useful work that the program is intended to accomplish. Note that the important measure is the relationship between the synchronization overhead and the overhead of the code in the critical section, with larger critical sections able to tolerate greater synchronization overhead. The work-to-synchronization ratio is related to the notion of synchronization efficiency.
Read-to-Write Ratio:
A data structure that is rarely updated may often be replicated rather than partitioned, and furthermore may be protected with asymmetric synchronization primitives that reduce readers' synchronization overhead at the expense of that of writers, thereby reducing overall synchronization overhead. Corresponding optimizations are possible for frequently updated data structures, as discussed in Chapter [*].
Complexity:
A parallel program is more complex than an equivalent sequential program because the parallel program has a much larger state space than does the sequential program, although these larger state spaces can in some cases be easily understood given sufficient regularity and structure. A parallel programmer must consider synchronization primitives, messaging, locking design, critical-section identification, and deadlock in the context of this larger state space.

This greater complexity often translates to higher development and maintenance costs. Therefore, budgetary constraints can limit the number and types of modifications made to an existing program, since a given degree of speedup is worth only so much time and trouble. Furthermore, there may be potential sequential optimizations that are cheaper and more effective than parallelization. As noted in Section [*], parallelization is but one performance optimization of many, and is furthermore an optimization that applies most readily to CPU-based bottlenecks.

These criteria will act together to enforce a maximum speedup. The first three criteria are deeply interrelated, so the remainder of this section analyzes these interrelationships.7.3

Note that these criteria may also appear as part of the requirements specification. For example, speedup may act as a desideratum (``the faster, the better'') or as an absolute requirement of the workload, or ``context'' (``the system must support at least 1,000,000 web hits per second'').

An understanding of the relationships between these design criteria can be very helpful when identifying appropriate design tradeoffs for a parallel program.

  1. The less time a program spends in critical sections, the greater the potential speedup. This is a consequence of Amdahl's Law [Amd67] and of the fact that only one CPU may execute within a given critical section at a given time.
  2. The fraction of time that the program spends in a given exclusive critical section must be much less than the reciprocal of the number of CPUs for the actual speedup to approach the number of CPUs. For example, a program running on 10 CPUs must spend much less than one tenth of its time in the most-restrictive critical section if it is to scale at all well.
  3. Contention effects will consume the excess CPU and/or wallclock time should the actual speedup be less than the number of available CPUs. The larger the gap between the number of CPUs and the actual speedup, the less efficiently the CPUs will be used. Similarly, the greater the desired efficiency, the smaller the achievable speedup.
  4. If the available synchronization primitives have high overhead compared to the critical sections that they guard, the best way to improve speedup is to reduce the number of times that the primitives are invoked (perhaps by batching critical sections, using data ownership, using RCU, or by moving toward a more coarse-grained design such as code locking).
  5. If the critical sections have high overhead compared to the primitives guarding them, the best way to improve speedup is to increase parallelism by moving to reader/writer locking, data locking, RCU, or data ownership.
  6. If the critical sections have high overhead compared to the primitives guarding them and the data structure being guarded is read much more often than modified, the best way to increase parallelism is to move to reader/writer locking or RCU.
  7. Many changes that improve SMP performance, for example, reducing lock contention, also improve response times.

Paul E. McKenney 2011-12-16
perfbook_html/img254.png0000644000175000017500000002306711672745777015337 0ustar paulmckpaulmckPNG  IHDR-F HPLTEb``MJK# hffommmkkcaaZWXXUV856C@@wuv.*+b>tRNS@f IDATx]*FdidžfUΗ傈l(eUN@**W(V>!,3bm8zew,ypm^)ՄI\_j{Y'ݠֺk{L7u=R-VH [Eu3/GzvSjaNjlƀv*(Xjz՛5:p)ij+k d;:NԞһ =\J9-ԱV5tvo'xUU(9v er-2)ξRͫ-Q 2;v#z٤ v&Q C-sGEynœħ]EdoӺYꓠk"!7?ۦj M8& 2x6Yxo` ʘڸx[#ӳm\-%oVU<{3a*ůu Q[h++NML+]P㭣]>|UK<2fXJ;l.i-T[I/ӣmum (r*7ŁO:],7|9O{H(C+ۊot=`Ι0#AY˷?lR"y E c@^mO@x<6AH"j H6hb$k|J{A\-a{'?C8ۿonm2GUCR-?OWKL@(kA#UdMJVxM`n qk^X\@7p.C9~NJFK%j@Ϣ}zJfv*bpp^yjvi~@6@|s*\8b7!C=?0[A꒛߲h;*V%c[ه}_ffjvoBF#ޓ+gܻZ~%1JRs4pMGDOX7̳f͹gz#.Fɫjj[T㰀10mI}TդqĻ݃>㸜I@3u%ỳ M}-7IeՂ2מbg/àx7&2rxnu,JYXUZg kѳ`K{i;ձ R?JB< 9Ӿ=׉0C CjR5{|{ԥ+E4$J C ֠WVv.V (m[[%6;F[ H^`Ne:Vy bG \v7$k`œgTތ s{ʀ۠z4:7c7Jzy}#v'l*yWCt۟ rI!z$O5-ǾMsoh@gA^jM10s ܾ0G9prҊ69yZ\".}_SWD_v%($5p/%oPЅvd*5%sF7+k p2;UXAq/cC`f~VO6S&s5;-hjI\*(d zj\I1=S[^W3Bg7۲ӹ GHg 9͞/ :Z"_Yy|Hl.1ckM?q mRVZ1ErUZ&yyT^c{?Iox Sy̓oKy4=(+DKt]AxUoc;*td* k1=͕Pedau_{z\@*ȋ"hh9J[[*ABAU^q4ߠ%ǕslWܰjƗ=89 82pPۿq!f/r,K%˟rE~Ǵ+*k; r D='*g` -VI.@%GT~d`;$Ș. mafZZ}-Ԛнrb+"<)a~&фR6-(*WmX3tr/,w /#΃ЈЂeŕvbY;Rn%!=ELJbV ."+u:4f8;͸)҄K^V /LV%~FlI\"|#aȔO$Ս\$y\! UL?,t?'Md :"4 \a˙<.CJ5DC[6JQDjU; 0`;tVR4}.|%ZPk}՘fȥ$ߑlʐ+A(?,ټuvCQ<8h-Ҋe64͗Lޤ08z]oʁ5CqgqJRk:-"n5k0 ,E{`yKZjF%>$ lmZkfG#ۘ$OK15-Q{T8Sriy-UBU+2Bqs+i[РRzY\G%JU.,cb|ňt֑{ jU NCC:M*]WC?PߊF]*0+Ay%ckry*8Κʊ^dϊ|/g0L|!3DY l<+ϚhaMu2*4\8|Z01pzAlEPүe;i2RKA"-aMgb!mea}Ě<aS펏8 ɩ-(бfOxH9s c:6jcmbEN|--*-Qy除+Duʼ;sHcx#1͙ޑL.ڭΑIF_C݊%QtJ \-k.LNd3mK+ Ɇ=?8fJUrb,뾷Q3([..sC*s\Z2b%rZ7(er.`ȳ)<ljf~݂E!f*W5 @maS/;_ˀTWssQ`h,Psd8qCaܴT4;O Yp<4b cv_,IbNib"e1FaOG~y0zi@ YNZq#bI̗X'Am6,I7c3Nu9 ݸU@Sre9'-9gy97rZ8/CG.ߣq80JJ\m!q+)܋{~HU 1xb)¿!΅ q].o5h2l'1\l5 q%a P-y? 5rV%X 71E&`÷pQe| WqF3j^_\KCFxXӼ%p`qBr]BcM3icZ⚶Vd%x1_)5)bE5EX#Zb*.E0 <+̛^Dq&&-+"~ܪy7t;'՗o- .ߪoVoa=BcOBO;مDkw{@r Xg<8JcO+r rKk};)kH'gb}QXQo[|6/ˆBtQmAօ940:nq+YukU?"qe6ofo E㨐1=nŏh-7Y>\XXzL4p]WDXY~FQO7 D;OѲy CPlH~Йxfy.jBKk>H-p8l1k2=P 15rf9^VD7GxEp,XƔ[Xspڗ#SP֊ڋ0ު%XGB< [ NAڈـCT!y`(>;Ȋ<έ `sh {f`Ch1~,dTXh6XvRP) m( 8hŦk@l 8R[8Ԕ(5$!THX[AS0{V^gaL9` !ws#;Ni LK?zp W^A 7Y5܏vD}:Ej&|/ji:pw;kבR#H8*(e>;pf,ȉ1s?BF Y@u FxX 4~x8W5-פ ?>H~^ûUUM憸|'OH_Q.k[mOv&s1ތPe)58%4Y_LF:=/h,< ژq!8Y]8x*GŚb-&P U!gKOKΎ.FtggT~I*Qo@꥾]M`m*jRqVᴬ4]W)S4bπig]}3+VLxa A߹"=ӴS/9_Z+QmQ0hCf&5'&-R[#uuqv}0+gsl#3SDh5q],nW8-@ dz*f )qWd$DH~gӈ0Wyt=3e9ZxsruFͧ) - SjC2cBzƺ[L8_d\mHq3 >xk;F ruz@`7'xP < R 8J,E`ݳ.' d'cɌ]y9Dȕ.CVC &'~UY[^ Y~+ub"'gm˄mq2ĕw 46ηf3]_2E X>DV#gd}rJ ;lHX3Կ/8u6.gx+;_.;D])2k5Ԃv5[*.Bkd4@mT5l)4%p)SY^ Y_3d~r;pR 2-aiznAo1ļI@\w:t*2e Ϥ!ObSٷF5r-)7Vhբrۖ,5u]oR[*N(7p9Mey'񙈺!Zbdf{\n۴yF0T=0Kn KpUC 4;,^hgR^bedžh#{ {x| P~R<4>O% ($!L< $r,,C\ %22f*i)vF9HtXaXPkaXMB^NBUI/sxg-LR="n|Y54CDgDLAהOUGtқ*A/W'ZgQw(ºBx2rHIJzN:%XIKg[OLs z(RRq*g:*uO_>I'}VI_<Ցz^ud8 FG'Ņ[bm^7?WM(R|!:sUGk~}(uqtiQM{8c&MUoG{޺qkI;o= _!QH^, bE/dL$\pF2n5v+aaB%Fn?4 K[_XPq-µ}T-& f\m߰%f$Hm.$MIPQ6͓-1똗2&5IDATp{˔!h\̔8ǝVEsf쓛}ǫazB εLLcz<hOՖhhŦ9%:nv^aM`RnoC4rl[ԕZ߸ko5mVM2X~Zߺ \XSr`Y> #ˎ|Ec")u#[⎌oER:Ynx-WH'F7.>sBKƮJ)"PEorcK /@>+lz !:%q7rqmRRDV 2n".3ʱKԽCU؏ߜ %n[6a9ٌ~k‹"45-@q3糠NVӋCpvq{V jv.úVՋu4wp*AZ[-WH-4KO Fp:lpD/ Ola DTz iz!oap V x)Մi-)*X 8\kCq;t3!7HV}qނbpa qz=üt$46χPk!^bj>ÎƠv HA29!h?\Qq4]sYڶ;98U3M;kf׼k_6JbMz *ICsC0.x07>|xAwW㩵$a ZeU7 WL?w]# ci-rMlМ70 &tzJTB᪇jLն/+ؿፏ[ٰQ*S[} ߡѭQ b(J.][R$bqX|U v{ٙwUXGG9X@/¶//Zꦷ :miJ u0@dh9ou4?6^l)!7oZ[_0 nqlF8_/!T[lÀzgz 4U}8TMhcˆW P anְ|Gֱeގ*!cھ܌-]h*TbSUn{_>I^[1^ntR7ICόE0{3t0 ܒ8AIJ‘cYu2uW,$/Duq ]V c$ЧF2. Gx2DQS)ݸzӸjŠsHCJBE"S=L  ̇AWz?(ɑtO35>rTSgM+jc%SD'̻/8ɫjٜdP7c'Lq㼷\^\Zj-pr!5 k4V[0;vXn/VLn]-(-6ܝwZtׇ `_0ziΨi02N X*m}Q' V}`<:o(#O%1Pffs ̐گn0D,< &K;10]Kn&]{s2~88d8ܘ݌ܪU7d1qG1++-PKqQ@ ?"bL*ܰ|>,̈́0 Y.h侍2:<uxpa~,:aZOTII䣶\ \j/B @q 6F"bL0, ~TjsbbuZ \+¸07u{mxl8F'z9'5t1ZK:>.Dx-UX/Ct"Ah/큝S Fs[1pۘQhz0^)xցFW GJ3KE7V &!0._lN~thI7T#zbHyvI }HG1Ƅjc/ypM"kBrd|Ї(ׄ*ZƍX6ps35_RK緵D\Z"w®n.4)Ye?̼ܸDLn؆p~vʒ=ܣ mث^nX w7Н^7z,i= |J,EqSZf:'h6tÛG2LU hhquB-W ?niu3T t4!&|}XZ^^D1o.Qypycgg!qtpjEBS 6' Û6Sհ@R:ېB!ށ+.}_~n$-(&:oW4C94sqS%|=+ZTuʱ#Kv!ܮz9u)g~TÉCiwq >@!ҳ<^F?dD_7PֆÛ"?ٍT#e]<5Z4w/7/-ُQan/@Nck ?T۱A~ezy<- Ϥ=R57:B{FezD"eǦ()]S M玣Kn8*j .b`x<9J-j2q$R}gEgmq)lkK\; @7f};Qm㚭sãFͣAs([FAB/M 5<]KBH@8S>W񻩈\?$?a7(<~2Z' NeV1FrΓyCy'8/bɼCTPq[!Y~g+9k\HGDa[l"/TQخSdXJ@Ae : .C"6K^1JЎk d QmAې^gI1(rglyIA@܅iH֠#ֵ%Y$SoO/2苟ΰbY~¯D<,/x@hckCz][ʘBlE52>8kT z`F><6#ur̵)"[XO XD K) `1H奈 Ц{39c GA'x ?Hn$9~U{Lpry':=4F"xr`ٳg՞./@/?Hn4=8tv雓{y8FĊOaEb 3.7O[BFm,6$"` =e~ +x.*Jx2%;H "[@[BlyIMqT;$T@Pڮ`?gWe %\ {<)< OL?Q]4b?;K#s5#]V$m<͙J E~DуčSMvi.'pfLGwU5Yc܊ 97$xcbPAF6=D^s^1a|E'6lxf vMi %3EĔ9̯S^^d#e .`UPpJHd._?]%~)vuB1첒]8~3c2~gu>rXO KCWIFE l,;IYl>䏿ZQ7OM7mL7ϯ@ISwgW ^e*6o?M|o @. ~%GreHhۀTHW6TJ.X5?#p\U~ $ێ<փ[lV><-9(cN~DVO(6܉Dž ,\ޅJoy_ߖgPo܋-]7djv!S$-V{g֓swڋ/Mq3Њ 7jJ}ƛ\Mo qȇ:h;fw77u<"B\CqohOGx|ܷ"\wBUS7u\K[}[B 7'S~_Ld[6,&L?B' tZpo [ qdIENDB`perfbook_html/node361.html0000644000175000017500000001476011672746163015655 0ustar paulmckpaulmck D.2.9 Conclusion


D.2.9 Conclusion

This hierarchical implementation of RCU reduces lock contention, avoids unnecessarily awakening dyntick-idle sleeping CPUs, while helping to debug Linux's hotplug-CPU code paths. This implementation is designed to handle single systems with thousands of CPUs, and on 64-bit systems has an architectural limitation of a quarter million CPUs, a limit I expect to be sufficient for at least the next few years.

This RCU implementation of course has some limitations:

  1. The force_quiescent_state() can scan the full set of CPUs with irqs disabled. This would be fatal in a real-time implementation of RCU, so if hierarchy ever needs to be introduced to preemptible RCU, some other approach will be required. It is possible that it will be problematic on 4,096-CPU systems, but actual testing on such systems is required to prove this one way or the other.

    On busy systems, the force_quiescent_state() scan would not be expected to happen, as CPUs should pass through quiescent states within three jiffies of the start of a quiescent state. On semi-busy systems, only the CPUs in dynticks-idle mode throughout would need to be scanned. In some cases, for example when a dynticks-idle CPU is handling an interrupt during a scan, subsequent scans are required. However, each such scan is performed separately, so scheduling latency is degraded by the overhead of only one such scan.

    If this scan proves problematic, one straightforward solution would be to do the scan incrementally. This would increase code complexity slightly and would also increase the time required to end a grace period, but would nonetheless be a likely solution.

  2. The rcu_node hierarchy is created at compile time, and is therefore sized for the worst-case NR_CPUS number of CPUs. However, even for 4,096 CPUs, the rcu_node hierarchy consumes only 65 cache lines on a 64-bit machine (and just you try accommodating 4,096 CPUs on a 32-bit machine!). Of course, a kernel built with NR_CPUS=4096 running on a 16-CPU machine would use a two-level tree when a single-node tree would work just fine. Although this configuration would incur added locking overhead, this does not affect hot-path read-side code, so should not be a problem in practice.

  3. This patch does increase kernel text and data somewhat: the old Classic RCU implementation consumes 1,757 bytes of kernel text and 456 bytes of kernel data for a total of 2,213 bytes, while the new hierarchical RCU implementation consumes 4,006 bytes of kernel text and 624 bytes of kernel data for a total of 4,630 bytes on a NR_CPUS=4 system. This is a non-problem even for most embedded systems, which often come with hundreds of megabytes of main memory. However, if this is a problem for tiny embedded systems, it may be necessary to provide both ``scale up'' and ``scale down'' implementations of RCU.

This hierarchical RCU implementation should nevertheless be a vast improvement over Classic RCU for machines with hundreds of CPUs. After all, Classic RCU was designed for systems with only 16-32 CPUs.

At some point, it may be necessary to also apply hierarchy to the preemptible RCU implementation. This will be challenging due to the modular arithmetic used on the per-CPU counter pairs, but should be doable.

Paul E. McKenney 2011-12-16
perfbook_html/img267.png0000644000175000017500000005417411672745760015336 0ustar paulmckpaulmckPNG  IHDRa>rPLTE\ZZMJKZWWPMMFCCrpq# b`ab``ywwvstommmkkcaaZWXXUV856iffKHHC@@wuv.*+|zzvtt}tRNS@f IDATx}³vZk8{v:!Ο(" -G&rl}g4I{{ml[4Y!B$KF0BT_{mAY3c d/2U!E+Hj;](QΝ@Ƨ20OR˕|Ld6OZdv14lY}֨n@?l4ſWiBf45sڔvf'^Qw%,k7{{W]LKғDZm}v`]_=vQ.}/]L9웺_;#{j4<6&#K;EcE瑹W|#S+rƎ} x~?#S&`Yv\~ $`xٟAX󻭛 v^ۡ@y:%7=n鮧v\*&A"[I/}+0*vy*)mD/J FHz2Vx[ga{[_Yy$a{864맄Шd:tK_=Œ_Kdec%iP@m^*=]deR/x} X}seetG!Fms|S OG)xAvMQ |=pt< ]<ζj>e]fn_~noQ fpowAbqAh\Zc!`@,NNlKS'h`A )Aײ?fLηZcSC}mA䇬Z}Z`r~F#k0jn̓-݀g-X !=jO#Z 4Y=L|(eU<5_Ndݣ$~׃vLL=L?EL}0qxa޼/%ӣKzi&`4NoM1W鎶윝 #M set '}AáPTNl(pBEve@+|J323lRg#Mo'k'm,k4a讠A%cdd#? beؽhvX8 ;-*B'RWi|Q-C9- vaC]_N?CDQA˼.zίu㌾`_9b ZVJ]ml=3yieŦ%;;;U%}.a܀L Oٳ(pkYڊi MYcD[OLGf+lY*d[I4ڕ9HhX+?.7_.@i-{U>-z+Wv6d|G 8=˜6'p>>Ľ= " ;{Og:]s!q9 C:ôĦ촖rh |Vv;ZޭyPH.7C\iO dexU9CI^Ouo;%bh|Tdqò:PHIUѕv~4y/qՒ̖~8{]hmmF!H)F}|e}nνHr~Ί[ h(v #S(N`J-Ҳ{J5Dtv6NRj&/ `~EihF}V`gPU+PCҾ)*;Tޑ{M^5җ}pVC 5,T0r1CP W$Sc0qM#/:p$6+\hHʁ\"A !n\F3"ZDX9s]9=fqhGBkjs}Rpq`!n,i-].#!0\q!pؓLCA~j;e=IKFX9GF@/V(%rފ%TtmH3VGѾ~m$}i bf--/#)TK U=bXiGd:bPF:YSţ5W%a&o6 /Ĺn\&X!NRm`폑6cyE୻Bk4cΒc&[ 0hڧ[z%#+PJ׵X:ٓ!*P% ;̤Qg=Byy]Kpxl,ڠ)6\9E6V}Lݏx~#ש̯ˌmDY=ysad#J+箠pA`@w2ӓC580i`HcjJZk 幫,rѪgB+g)q,{7Q/L>AAҿ/(հhCtVi#6i=M6 *_ĐJRah)$K0J SbpUs# r9KbY]fx(5lMH,xL7Y(ە p^hxׄ9]+rhJJvj繡b9> Kvx8+u-TG>\oO.~(]V0/ 4xv^kh 9~[ JPaʾGe@vaՀsCdqdL Ց%]/:1c|Ywi_ .w9qrh([t󥭉穅OvπUCNerp ,c̋YKDsM]cJgلT.GMEr@%,~X 7fxjYbzY=>v]e&[֛MWMo wcpM&Pf#ӑT, 7/9thd-,[KkmBJLyWvHk_Ir>Pgm5|fgzVV!SgZ<=?/ \xiG"E>F1 s{Y#ٸ+>fz4:uit٩1љlsqL7~t2:uf: DL@/f]7?ƬW6pwk+r37 nY }B%KGDMj܍eЃZIG3ȍ+Y^x#2 1Z#HDXBaZi;^64Z[:"rW+WC@;]RhXc𯆚_ڕ &V3:&/SkǪQp&upZAV5Vnd3{]RBAy9'5{ N=juU} )N_hu/" I"?G]^P|C~JS/rE^ .Q.2t"?>Q fs]VgnZîLnH2((̃JX2{'6T ѐV^6P#jr\ه0+r`K,BIRSVpiqqpHf2m3 ZY̻s s! $ I- $\{.=Y$n'f揱d\?kD[C?Cy"SПe!=V~>V|~yK LjϮv'FOr=MXbvzSeDžqDsY2E e!N$:HWe+nVvRECMXWv9kW! -0ZVPB_x*pj3߇\L/d1bBF8nkebouTB$T=-CLsͷ ; !BYޣ)F>V؂?td;ҚtFh GV fJїZC'6};|Ќޮ}TsZDs@ V C*s%Idiuc(WM"H=r6pB-L72B)U(@`n LZksA5ފ_uf_`eM~"( 5uyce i*HL% z[՚ƺD FP^/TV Ki4ILwX{:HšgxrqȰ1iut0q()4KrFmM1QpV\GyVjNQ vj䱈{D YNQrEKZ⏻{sJ|C<|]W=r1ASIJTAgKa0ԉC7w!K4T B{}Mx˂Qrs!|'7ϲU c|{MP s|OWH 1 S_˒<ӾJzo7TD-U} ˰jP[/e?E";DŽ-Vs2ϦO5~mSq}|i9|s)1c <(E0au(ELy8`ytRZKoQ0x٘s,8eV ,WvV:їaTwbI;\~2o(QR7ˏR#yǂ/VxO~L7JāSs_tQJ4b\usE&&LciKsmv,M֊êLS=1l,a3YޑaW'=1茾d{Sq];j2g02Q>aSADZ%*H>[*U$txDt|̻i+{ 'B+M( pU8 rԝUN*\LyZ2F@ZWe(kXt&g_tРMР=Avy!sTlhAt,t+.U|n$q2CCɉ&ZJd{E%%!+"!T5[+뾆qzLO|3d9֣k^ؤ[22Zӱ: jtq:*P0,N%,_~% "fMXA\/R%_Ǘ?SXJ-t7Z]_Md?1f"=O$_\a)RĠRgw}n0}MW_W]I2bAk(+'с,/U͇9=J&f&Pa+:Z(^a(w8lL(安ް+T!&n`~|nCtdX#Wk5:lLa [fVJǸgE]5eEt&E| pqjw QAeݜ,UW$MeDȱ$1/ņ5|qgD!y;Æ !,)XHMe`VۆreDA IDAT)+z I hIBR̮\Rl4yO+E5zQ%8ks|:h cV֍G!>!c Xs@FlI6U*s)'ԃOrPJB&b:HUE NZvOGAqzRcr\9 XAd?hO?aCQP ݩ!};VsMJ`a,a%u:Q0p;P\eF)0ʱCY0o,NE t9pf LXZfbc[Gz((&mJ0{y!S0U^'#/f1hՄJaJO+7e?ku8țt`Rd5qƧKLfѠfCC#oa\)%TzEvcDXS4f )% >8S^d͍Q;ϷW܊2x` 'JA g5 .})$+RbB9FxHR+ЯF3-qmo7΅z@̯5TI.Yqي0ЃP:Z%< ⵁZ4y Q[UIAsPe>zbG"!RRD{噎"NGsTQ8úZq9~F[]QVQI:Hz^š-ri FnHG}#}n<S,k4EmAE!MK.:ff<:iw-FM84W]cߓsX]M4C`vERKr: `n+XXu~-:A"J/@'IȦL}W8BN: /gVPY$\iea _i_@|1td Un8 bGaq d E7wHzF"fy.Ia=1y 3j@E?:1G(Bs,w9ՖAyUv-n5="QMϮHht)d .f .kLfK ӡ(Rڶ5.> 7ItJCu1u|zF#r9- Ġ _H;} :X:,; 27h) E0k9,)gpak<2b!EQ0."MHS⋫HS[E!/v:rEq4@0ÿeJ0t/CYI)]X? eƁvS2M3ʉ :@; n7r:o SYj]iqiآ<{m0aUP ??B8z EY"U/QDtdn '+PdOշ_--R5$zе5\j'JVȞakQ*J" )Eͻ^SPQ"-Ʋw6aI6j(MEʎ~eJ _6JCNt|_0B8ȸL.36VnդlɚSN-y&ۖ؀2 Aƥ=JyuؗwlI*ڒČ'ʄpz[`(~Ld-)xb P{<b9,xX2@QȣKK&)H2bڣMF,/pd/x:ZWtU"b62YVA;uEf\ڏ4ŮCcQU&?Cˤ0 f^>cW 5}{#GRB<&uO1r?i= d]%d]`ß(lx5X=UFYPyvgX>p ]E 2+3}-w' 23cxgW0o^V-a?HQؤ Nft:&,b"WʃRC{!ae`_G <O]DSPJft6 |GD4|Ќ>"mHJ*M(G wl1{JUqBfN{^}y4`u]h01 Ⓞ"|CB9Aqc2bx/*Lwa,-W $ئ7aw{ OJSTHK1:J`'/W LL !EGJL?D,sn9KZ*qݪWF9/hx;"D"]2R΅W癈H8҅*:i M_ʼn+<VEb %r8U'wEP~._+TT MG1VKIi;֒2]qĭ5Hsn(5c9?sPZF֠5+%sae ^GZ9I ,(q8a qQ*;WpLakn^H^Ħ*o4 Y9lɾb5/<`*}eЋGց#){DdTU“!p RuH*:1/uVc"^͑u2QKu8!Ld^rh6j9 Y u]^)/s-Q[[iJb|Q(Y;L $SGr[GMO*E sbR)> ZܽND&9^~twt BeDt8e`Ắ:#<)%ht|^^!.ցoȯܦ MϢ͡a/ZCl+_DɻCs2$m˒BN/#Nʐ|y %М i( r 0 (Z*irÄ4Cr"0'Cd[Y4Cܜ᝘ hE+Q]I"M<6#)xN&xg~TMN|fh[W*RB$fhg.b)zS}WNE/kw XWP_J>QG8My|N9"ijڍ\E9r7 |I9M9"`Aa8 ;pZ9 /RfqehC"z 3y.UbK )BfNx7-[⼶X@[2TSч"xOVV%' E6R2_lLd EjkWQ9(A،AuYbԂI  yL_d9g#'%bSpP yWeL7X%&a`!03th$E{a,BD V-RĥF(|:ңV]Su7*+"k|9< h-,E#|R0DmDS9e,Gw"oGU҆^r~НPaeǷHGNvSM ku0UlGQUCh$-{QjOX؍io> Zhԕഠ 6H32 9`௶f*`vvbXôkAS-rf ,#q@\} fbS4}͊bki?ԕȍp9CcٽM{͙ }FR=ο(-'k \OCg*ܦ=($ɢ_p;歪\hH~EARn.twIX-̿uDQWفK¢o+䐩cm:oY;XaON_@L9ҍg2uܓ Xi&tʮbڕF 5G¦:"i-dH;t4R ~;0!7 TD4ۻbΤ" ;+r  Zf17=mXG?Vp9\"|o`~6o 2RACEr qLJBaD32vK6IuS,/?LHF_/~adEde|# H:ƻ/@T&Gu W@!QT#ͦePٓãFՈEcZu"Gyd*3 Ś9ܼ<>>}E3sHUQ u ~G2@Ejf4\4DW@r.]!)M~$-KӢhR~}r2tu_o<]1hR|:R ^/aty#q46vZLڄG1SԦ$~ [̻d}`&I}?)nvE"#eFez-G_wvՍ̚zCΙh`<)Ѯ؄GHek{I$Fҍ^X0|ع&mw,n҆VD|x:vSc[@M:L/v*SQPsTVbFӢ lul+S۪z:=ձ=OVޜR<^bǸr%U^7 ?ӊow/~faeYIG(8@LPS, .!Kq6=PNt#hbJ:Ų:ɆPlt"ME3 O&9YS:s  ф,,G#?i N8!4GI)۪H)Q2!+9(F&bD!vZ ^)Qf({v57z~ ax8&ԯDV)PjH"zD!E Z֟PHoČKcw,ֿy$IEJzTE>xdSj&~8^֘l0 A╆߄#)Z}δA~!%wxXΑÍ/Yks$\W_`~rn_܋45h_܋4H78]l_ngUKnq~`p_C*h陸:7jirzu-G>ۑDJ_x3oCW8$9 0]KwO X&LCN auMr{E9(tUUt#{oܸq6+TBv/sQ Lr#чe>| w]7g_-yi;v>/VG,"m%#wC7}bHxz&to*[׺B=[ |Jp^ =R<2nη]FFOj"0$+{ʫԭlhYDvI~#,EQ+7!!b*[:fx+cB{3& pj!z|W0$eFTS&%Eܦh7\|K) 1} "?fu"7@ ݗ `{GcwAH7nܸq4!IC`{_^ɰJ$AN6Rn5NUgd@.6Їw+dgNn&mio:s|&Cе.O/_@eV-7Pٽ y3>AW 84в2 ?$mjܵ^TU^LBR„fGΝX|* }%ˇt0JJ37!&3eu W*^*MBZZ/+;KQP*7Bt:7pȘ1Ӎ+ OpBD&9h<^9_2- &aojMq&kL^b "hUi%>>x*Xw{S]x:=8ۨyMp\8xz,p*uHqҏ^į,CV.1pZXa 2 D" )D-7 m$oPx 66B'Bp6Ͻn\8x4CskwIMIYgt|e*| {6X̢3D("tSJi M҂\O!S8HVAyR: 9ܛp 4C# (pC>  +|f Kن;[YnYD`M,O(£, !LHqo0KwT$o"WL"yӄ%41A/G1BWjqwuWs7Nua&"y3I)BxG!-fc8awC.ssŨ{jd!W=Pw@RO_ SϢvϝ|')d;NMd˞hG v(E; 3 TQT2M PbZ\o1P!7n U1mЍh3nܸq9n|n $e4hĮ +M w$f<]f̴?dc:*.i 2xh-G.}('ס\Ⱦ?;*! :tg;:8k䆊Q3y Y)fXqc 2ݽnEW}ё^u^$]K;[镠{#G?Dx&bhn"*Xp'W8 v՜A:1ƍۀxrRE*.(K4VE:D&Dw3PP!EPuͣE&0 J8H>K%P\%`rd8V$+b{$ #<ǸGN|ލ5ϜK&λK%>  |'R"嬩̹-Z(ȋunƽ˃VʬxwskSSS) ?€eL0Sg5W(IDAT$!ZY H@0:Y&Qpopedm&'"|=*Gv @Eʎ2L\>Av1mL @iLa32NfML7n|T {Zw{G ^'W< H7n NwW|hIm]u'?|7n`Syu5{1t J' vvOpR":bޡ^:R+mhGTlF83H1 ՑD9hWlH Rױ[Hž! Ցu3Z#휧э7.^^@q$ z-ďd33MGpdi@^n88gA 4} ?gR7 "P^)|_v8P (G FSo8_ۮd6g1k sxu>_0rq:'jy&rSo{)'?<ǪYuCE%CP4gצLGd;J6wb_m p2 -%rB8nLG`;J7}z&g8L gdyd?"a:bQ+~q2m1 m8gu݈@DYIv$h# a^N~+e vcˇ pjtÖrl%6)#bfr Յsf,h],7m Yҳ DYA:.-? (K$Z*oKFX~K7n? vN!V"=^έqICUCfD&dR *K#D:ocF rOc:Œ7 Y8)Z^}U8꙽O{Dn7/=Ek+}HwC*s'<_jAݏ/AEoHmq E s0n&{`"E/ccXjsg{u[!25$1Z4^~|"7e5Xr`OGxHZaf!vQ3Tqy6T`N0ZcpCU--{Zo#\HtD`ƮhzR{iQ3t=X5y93Rzc0f_EZ&6}8/F,^JṴHvr-䬛օ^Kd>ݚ$Y%ҺuSҺku=,QYi^κEҺYw MZwA^_䯃RN'P{ViHv͔nNgA^$^;3 {ϦvS:_x2ݍƕPblk zx z o\3# 뺂^v5'UWPz zV>\Պ'k&8eWп _pnWЍpa*W%ρgap0fL '..PLjqkԉV::Jb0 l /d+5468qy\>~CtH%<KoK\;ncUpyTsx7)f؜79@Ba%l͜VH9"/y^3IG '/%}/\`οEZ/\=tzy"bC"͟wlIGpc?ȋD۱4˦4x7fq)09@_^PɄ%3vG>9W6FU`<JNnʁd_H%3!-8N!zB R6)l@|a& yؗJ&(Y͟b0a _(gEKt.ـ8Qoэb wŋU,,?vWGb|Xc{o\dI\6ZYϧQָ W7n, l 6s+Keۧkg:zs4=Q\uhJiS?}Qф}st|<Q_:)ka^RBL,e%P|46vk0L3,̴CkZbfp]<8/|LVnng 1aL(ki.s(R8ĆPnӍ7,?ksHV(z`bF,hZ#R3T H{`'FJx6$`Š!pB(=zQ?aT?6&LT{`NT(@JaQKg.lƍ\UUXYhW\A$PΞ?s=7VGg!@"G-2jKr2զrޢv\ƍd!)v2Wy<\W.v"_ &JN)MZ YeZmj̞CnV"wQ@]R"=xCK51Lz. B*) ;U(*8W.)peR{]2 7n\Yk6Τ _DgJEU^s1#9R7zW5 @ [5`B2?>^fՆ8a3Ix/),6~%"Y=sS.ӨP ~zkPڶ$/!cr+. {<>x[PYCP9R#"'@/(Ί\60 P1; ӛ( ӒL'澡xebQi>gR~gI!Lfp?"nE_4!ϔƮd3ƍ\u ޳xe u B7/5Oh5/5Ps;/5fq%gpNm>I̅*7pdIXby6p*7a8q @Хժ~6i*xlr[3!+ \$>Hcs*م50F k'HH6F}'"o cOq# #$@I#ݘ8YC?ڰU"ޑ&ԕ@~v$Tc,8R'boV!^z;6[N<7/RB+L4OoC*_9 }xp."t;zz[d+M7Eoc܅$7!\%9~x4xaz zvs؟:QKj1Nub?% Joq>Ћ8ơq&KS670G8h_pE_ɯ1gLGky0[~'Xe_-XxČLjy>cԁ+l7N8 8x5`SLGnS]',<"1w&k# v,'@nH3񛡈Yߢqܫč7Ƌ1Wz?Ik}XCDH!^:rnT_i,d[؛pδ'n&l*ΡmpYH[F8pM7!rM7T#ΡN] fYkxwWqlũؙ8~xOKĵe7Xr\pjBcMlCwS͔8U<&* y3.Ϧ/!c|љGDbo(y{ qH,$5$ߞ#D+Ə=9:xoIENDB`perfbook_html/node3.html0000644000175000017500000001160611672746161015500 0ustar paulmckpaulmck Preface

Preface

The purpose of this book is to help you understand how to program shared-memory parallel machines without risking your sanity.2.1By describing the algorithms and designs that have worked well in the past, we hope to help you avoid at least some of the pitfalls that have beset parallel projects. But you should think of this book as a foundation on which to build, rather than as a completed cathedral. Your mission, if you choose to accept, is to help make further progress in the exciting field of parallel programming, progress that should in time render this book obsolete. Parallel programming is not as hard as it is reputed, and it is hoped that this book makes it even easier for you.

This book follows a watershed shift in the parallel-programming field, from being primarily the domain of science, research, and grand-challenge projects to being primarily an engineering discipline. In presenting this engineering discipline, this book will examine the specific development tasks peculiar to parallel programming, and describe how they may be most effectively handled, and, in some surprisingly common special cases, automated.

This book is written in the hope that presenting the engineering discipline underlying successful parallel-programming projects will free a new generation of parallel hackers from the need to slowly and painstakingly reinvent old wheels, instead focusing their energy and creativity on new frontiers. Although the book is intended primarily for self-study, it is likely to be more generally useful. It is hoped that this book will be useful to you, and that the experience of parallel programming will bring you as much fun, excitement, and challenge as it has provided the authors over the years.

Paul E. McKenney 2011-12-16
perfbook_html/node365.html0000644000175000017500000001576311672746163015665 0ustar paulmckpaulmck D.3.1.2 Nodes in the Hierarchy


D.3.1.2 Nodes in the Hierarchy

As noted earlier, the rcu_node hierarchy is flattened into the rcu_state structure as shown in Figure [*] on page [*]. Each rcu_node in this hierarchy has fields as follows:

  • lock: This spinlock guards the non-constant fields in this structure. This lock is acquired from softirq context, so must disable irqs.

    Quick Quiz D.19: Why not simply disable bottom halves (softirq) when acquiring the rcu_data structure's lock? Wouldn't this be faster? End Quick Quiz

    The lock field of the root rcu_node has additional responsibilities:

    1. Serializes CPU-stall checking, so that a given stall is reported by only one CPU. This can be important on systems with thousands of CPUs!
    2. Serializes starting a new grace period, so that multiple CPUs don't start conflicting grace periods concurrently.
    3. Prevents new grace periods from starting in code that needs to run within the confines of a single grace period.
    4. Serializes the state machine forcing quiescent states (in force_quiescent_state()) in order to keep the number of reschedule IPIs down to a dull roar.
  • qsmask: This bitmask tracks which CPUs (for leaf rcu_node structures) or groups of CPUs (for non-leaf rcu_node structures) still need to pass through a quiescent state in order for the current grace period to end.
  • qsmaskinit: This bitmask tracks which CPUs or groups of CPUs will need to pass through a quiescent state for subsequent grace periods to end. The online/offline code manipulates the qsmaskinit fields, which are copied to the corresponding qsmask fields at the beginning of each grace period. This copy operation is one reason why grace period initialization must exclude online/offline operations.
  • grpmask: This bitmask has a single bit set, and that is the bit corresponding to the this rcu_node structure's position in the parent rcu_node structure's qsmask and qsmaskinit fields. Use of this field simplifies quiescent-state processing, as suggested by Manfred Spraul.

    Quick Quiz D.20: How about the qsmask and qsmaskinit fields for the leaf rcu_node structures? Doesn't there have to be some way to work out which of the bits in these fields corresponds to each CPU covered by the rcu_node structure in question? End Quick Quiz

  • grplo: This field contains the number of the lowest-numbered CPU covered by this rcu_node structure.
  • grphi: This field contains the number of the highest-numbered CPU covered by this rcu_node structure.
  • grpnum: This field contains the bit number in the parent rcu_node structure's qsmask and qsmaskinit fields that this rcu_node structure corresponds to. In other words, given a pointer rnp to a given rcu_node structure, it will always be the case that 1UL « rnp->grpnum == rnp->grpmask. The grpnum field is used only for tracing output.
  • level: This field contains zero for the root rcu_node structure, one for the rcu_node structures that are children of the root, and so on down the hierarchy.
  • parent: This field is a pointer to the parent rcu_node structure, or NULL for the root rcu_node structure.

Paul E. McKenney 2011-12-16
perfbook_html/node18.html0000644000175000017500000000574311672746161015573 0ustar paulmckpaulmck 3.4.4 Interacting With Hardware


3.4.4 Interacting With Hardware

Hardware interaction is normally the domain of the operating system, the compiler, libraries, or other software-environment infrastructure. However, developers working with novel hardware features and components will often need to work directly with such hardware. In addition, direct access to the hardware can be required when squeezing the last drop of performance out of a given system. In this case, the developer may need to tailor or configure the application to the cache geometry, system topology, or interconnect protocol of the target hardware.

In some cases, hardware may be considered to be a resource which may be subject to partitioning or access control, as described in the previous sections.



Paul E. McKenney 2011-12-16
perfbook_html/node359.html0000644000175000017500000000560711672746163015664 0ustar paulmckpaulmck D.2.7.10 Detect a Too-Long Grace Period


D.2.7.10 Detect a Too-Long Grace Period

When the CONFIG_RCU_CPU_STALL_DETECTOR kernel parameter is specified, the record_gp_stall_check_time() function records the time and also a timestamp set three seconds into the future. If the current grace period still has not ended by that time, the check_cpu_stall() function will check for the culprit, invoking print_cpu_stall() if the current CPU is the holdout, or print_other_cpu_stall() if it is some other CPU. A two-jiffies offset helps ensure that CPUs report on themselves when possible, taking advantage of the fact that a CPU can normally do a better job of tracing its own stack than it can tracing some other CPU's stack.



Paul E. McKenney 2011-12-16
perfbook_html/node70.html0000644000175000017500000000617411672746162015571 0ustar paulmckpaulmck 6.4.5 Signal-Theft Limit Counter Discussion

6.4.5 Signal-Theft Limit Counter Discussion

The signal-theft implementation runs more than twice as fast as the atomic implementation on my Intel Core Duo laptop. Is it always preferable?

The signal-theft implementation would be vastly preferable on Pentium-4 systems, given their slow atomic instructions, but the old 80386-based Sequent Symmetry systems would do much better with the shorter path length of the atomic implementation. If ultimate performance is of the essence, you will need to measure them both on the system that your application is to be deployed on.

This is but one reason why high-quality APIs are so important: they permit implementations to be changed as required by ever-changing hardware performance characteristics.

Quick Quiz 6.45: What if you want an exact limit counter to be exact only for its lower limit? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img9.png0000644000175000017500000001460611672745773015170 0ustar paulmckpaulmckPNG  IHDRW%suoPLTEAd{$8D6Sfl*3-EUQ}wcU3"VHoZ<\r~ ;[p?awfGmu݇D"HatRNS@fIDATx] kaYݓy3o?OTL{-h|xD@[ L{=YI @T~ٟ  ^H=mEi5-"jڎ7GJ /.ҦiCIҪxSfrb=wP OQ9>*P=PӨS:{Z[y)Txt"yX/ M7608?(%=z`MB[El5}3 XuvnJURׂes{Q<6'ׁˬ Ȟ6 B[3d~m0{.Xdd Xnclyvԑ ,5PM"RX]SV >)"'SnPC/3OAk`ulHi՟Suuم+4 ,&1⚠H0 ,SrЪ$܂*X(zď"":`k1Ǽuolέ^jlbr6k6sVJyn֘`ƴ]6́@kYA^KEju.W{[kŧ&*C'̪vkըktYyE\(-(>Lg9}.#~ U nIgg#xK)Q^nqsڧJ `C2Fczi#[zH\hhzk>n|.%.'h;tGc!?c-3Q.Od,㦝 %@핇,(`M)KDS[}h.TX*sE?DqɟU%'Db|wlu(O5<򡺑+H0;_"밳np <-QhHL]쟝OtߞAr7D!.k5lʪ.%:Dx^ݍWWNd3?畡=FV Kv|T*%{;PsIOv8]axAv)Xݑ=@x ,x^rœp8byd'SN} cezcf\Ts]ڳ΂:4s; j,V1FZPz5 0]m:a7Ux^xޙl X@b({[d*E@g!x Vª) 2UXKbkq)Tu@fB{FAh0U/&kX  k4&b"0 jKΙZ GamJXkN h;vi2uј-Ӷ"m#S/4~&aUŨ vh 11UDd>!1 k*_ wwօ Kf[8XU*ŽI)T|/Ec*yR`ȇ 6Vxp#X!+)&`\A{"|Bhu\lS@X.Zi`m$,J[WfOєheVTJ&vZXf,"`tZflAPU|wCV##˾7if0? 03^uV_\S틫?_36Gx(+ubnػQC ~kXyT fPG&<0峙la<blKvcɚX&bUѦ+3kρף1JYʽOKKwrw6TWz&Sg " 1Nx&\r/*X<ӈ? 2v9T˽lԯi@Ρy1f^uBIX2FsW˶hMy%wc6la4&h,XWeu1ؾV0vCX}4ԆCq|z><Ros@>r&z%dºOv|:[\څ b/c#ן| 4||d%C3LD38m྇~X5,5; |x]D^f\xZ;1[5^#ryG3?"-rD=q:c{F8U,'?wkw {7ϰo[s-[2"/Eo+&EF;1{OjYףxlɷ«V3;I83| O|V*qXbNpyZ;,O͑+.lMl9{oܲCd"v౛ZnvSX(#><򳇃83ʏpvoSYhyUc̦K3egR+Dp9g~,Zuuy[#)G<.)bU8t`(e%6" ,d_Z&e6E^ XnHʌDj3N/*}pC]}_z:5*ө]ٯZ&N,o6ız_mg#7Ge eb2ۚї&%KKPV+.BBTC-? $}~\bДKw5pǮV5Oyx81qjTL9ك|D+X|)n3~y%Ngy_NG1S:6Z|\֗-j} vHQ$ y) . 'KqM#쫇]'u]C[|2T \mpχgkZW,i* UZ@*>W'ckmPjm}xJRcm6W {E,]=p86cfB~C:cLRamWduŸ=hQ[>(^𭺨e4 ^7mAShF\} : <4͠ߙhxו}Cm9o=5k+|[rqDt:*3xiv'6q4ܺ,l>xt$鼆֗=R)]N:EyŹBHӐqqPuI+]J:t^;*\i xe4f# H=dn>eґgJ3.ƥAςWgVx$4wPZΏIG!+vG S{߯>eωj^̖W&w]w *unFWq^/KXg$=a]Wsܗuд&e ;Gxb(Dɂ2"*u+(sK}<k?\G)а`wxZ9{N6ߤVDぶ;Kۼ팩̍s &YؠU|zb,zxݮ,h.KiX^Y%D)6s)L~S JU?pp@aYj־Ag׺+vlaz&vV4u#âZa7k7>Y_u>ڄE $]O=pv*^"bԯ;Ʋ^ ThD%Ԡ"b_S=Ʋ^ +^蒪AeĴNbc҄*Aetf|5ZWD nFL+_eü.**1zFdoCC։2p%kI>.#^ȇedcF7|~zZ~|5G;.C-ΗQ`/Y狳[G\V_O/1yJke5E֋.?޶z%^#\ze*kR^,l/?޶z%^YѻE&^,K_~mDl?ćj~cumՄѺ-bJk av;R*="IENDB`perfbook_html/node165.html0000644000175000017500000001224711672746162015654 0ustar paulmckpaulmck 10.3.5 RCU Exercises


10.3.5 RCU Exercises

This section is organized as a series of Quick Quizzes that invite you to apply RCU to a number of examples earlier in this book. The answer to each Quick Quiz gives some hints, and also contains a pointer to a later section where the solution is explained at length. The rcu_read_lock(), rcu_read_unlock(), rcu_dereference(), rcu_assign_pointer(), and synchronize_rcu() primitives should suffice for most of these exercises.

Quick Quiz 10.61: The statistical-counter implementation shown in Figure [*] (count_end.c) used a global lock to guard the summation in read_count(), which resulted in poor performance and negative scalability. How could you use RCU to provide read_count() with excellent performance and good scalability. (Keep in mind that read_count()'s scalability will necessarily be limited by its need to scan all threads' counters.) End Quick Quiz

Quick Quiz 10.62: Section [*] showed a fanciful pair of code fragments that dealt with counting I/O accesses to removable devices. These code fragments suffered from high overhead on the fastpath (starting an I/O) due to the need to acquire a reader-writer lock. How would you use RCU to provide excellent performance and scalability? (Keep in mind that the performance of the common-case first code fragment that does I/O accesses is much more important than that of the device-removal code fragment.) End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node163.html0000644000175000017500000002622311672746162015651 0ustar paulmckpaulmck 10.3.4.9 RCU Based on Quiescent States


10.3.4.9 RCU Based on Quiescent States

Figure: Data for Quiescent-State-Based RCU
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...= 0;
3 DEFINE_PER_THREAD(long, rcu_reader_qs_gp);\end{verbatim}
}\end{figure}

Figure: Quiescent-State-Based RCU Read Side
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...nline(void)
26 {
27 rcu_quiescent_state();
28 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_qs.h) shows the read-side primitives used to construct a user-level implementation of RCU based on quiescent states, with the data shown in Figure [*]. As can be seen from lines 1-7 in the figure, the rcu_read_lock() and rcu_read_unlock() primitives do nothing, and can in fact be expected to be inlined and optimized away, as they are in server builds of the Linux kernel. This is due to the fact that quiescent-state-based RCU implementations approximate the extents of RCU read-side critical sections using the aforementioned quiescent states, which contains calls to rcu_quiescent_state(), shown from lines 9-15 in the figure. Threads entering extended quiescent states (for example, when blocking) may instead use the thread_offline() and thread_online() APIs to mark the beginning and the end, respectively, of such an extended quiescent state. As such, thread_online() is analogous to rcu_read_lock() and thread_offline() is analogous to rcu_read_unlock(). These two functions are shown on lines 17-28 in the figure. In either case, it is illegal for a quiescent state to appear within an RCU read-side critical section.

In rcu_quiescent_state(), line 11 executes a memory barrier to prevent any code prior to the quiescent state from being reordered into the quiescent state. Lines 12-13 pick up a copy of the global rcu_gp_ctr, using ACCESS_ONCE() to ensure that the compiler does not employ any optimizations that would result in rcu_gp_ctr being fetched more than once, and then adds one to the value fetched and stores it into the per-thread rcu_reader_qs_gp variable, so that any concurrent instance of synchronize_rcu() will see an odd-numbered value, thus becoming aware that a new RCU read-side critical section has started. Instances of synchronize_rcu() that are waiting on older RCU read-side critical sections will thus know to ignore this new one. Finally, line 14 executes a memory barrier.

Quick Quiz 10.55: Doesn't the additional memory barrier shown on line 14 of Figure [*], greatly increase the overhead of rcu_quiescent_state? End Quick Quiz

Some applications might use RCU only occasionally, but use it very heavily when they do use it. Such applications might choose to use rcu_thread_online() when starting to use RCU and rcu_thread_offline() when no longer using RCU. The time between a call to rcu_thread_offline() and a subsequent call to rcu_thread_online() is an extended quiescent state, so that RCU will not expect explicit quiescent states to be registered during this time.

The rcu_thread_offline() function simply sets the per-thread rcu_reader_qs_gp variable to the current value of rcu_gp_ctr, which has an even-numbered value. Any concurrent instances of synchronize_rcu() will thus know to ignore this thread.

Quick Quiz 10.56: Why are the two memory barriers on lines 19 and 22 of Figure [*] needed? End Quick Quiz

The rcu_thread_online() function simply invokes rcu_quiescent_state(), thus marking the end of the extended quiescent state.

Figure: RCU Update Side Using Quiescent States
\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_rcu(void)
2 {...
... 16 spin_unlock(&rcu_gp_lock);
17 smp_mb();
18 }\end{verbatim}
}\end{figure}

Figure [*] (rcu_qs.c) shows the implementation of synchronize_rcu(), which is quite similar to that of the preceding sections.

This implementation has blazingly fast read-side primitives, with an rcu_read_lock()-rcu_read_unlock() round trip incurring an overhead of roughly 50 picoseconds. The synchronize_rcu() overhead ranges from about 600 nanoseconds on a single-CPU Power5 system up to more than 100 microseconds on a 64-CPU system.

Quick Quiz 10.57: To be sure, the clock frequencies of ca-2008 Power systems were quite high, but even a 5GHz clock frequency is insufficient to allow loops to be executed in 50 picoseconds! What is going on here? End Quick Quiz

However, this implementation requires that each thread either invoke rcu_quiescent_state() periodically or to invoke rcu_thread_offline() for extended quiescent states. The need to invoke these functions periodically can make this implementation difficult to use in some situations, such as for certain types of library functions.

Quick Quiz 10.58: Why would the fact that the code is in a library make any difference for how easy it is to use the RCU implementation shown in Figures [*] and [*]? End Quick Quiz

Quick Quiz 10.59: But what if you hold a lock across a call to synchronize_rcu(), and then acquire that same lock within an RCU read-side critical section? This should be a deadlock, but how can a primitive that generates absolutely no code possibly participate in a deadlock cycle? End Quick Quiz

In addition, this implementation does not permit concurrent calls to synchronize_rcu() to share grace periods. That said, one could easily imagine a production-quality RCU implementation based on this version of RCU.

Paul E. McKenney 2011-12-16
perfbook_html/node435.html0000644000175000017500000001242311672746163015651 0ustar paulmckpaulmck E.6.3 Alternative Approach: Proof of Correctness


E.6.3 Alternative Approach: Proof of Correctness

An informal proof [McK07b] follows:

  1. For synchronize_qrcu() to exit too early, then by definition there must have been at least one reader present during synchronize_qrcu()'s full execution.
  2. The counter corresponding to this reader will have been at least 1 during this time interval.
  3. The synchronize_qrcu() code forces at least one of the counters to be at least 1 at all times.
  4. Therefore, at any given point in time, either one of the counters will be at least 2, or both of the counters will be at least one.
  5. However, the synchronize_qrcu() fastpath code can read only one of the counters at a given time. It is therefore possible for the fastpath code to fetch the first counter while zero, but to race with a counter flip so that the second counter is seen as one.
  6. There can be at most one reader persisting through such a race condition, as otherwise the sum would be two or greater, which would cause the updater to take the slowpath.
  7. But if the race occurs on the fastpath's first read of the counters, and then again on its second read, there have to have been two counter flips.
  8. Because a given updater flips the counter only once, and because the update-side lock prevents a pair of updaters from concurrently flipping the counters, the only way that the fastpath code can race with a flip twice is if the first updater completes.
  9. But the first updater will not complete until after all pre-existing readers have completed.
  10. Therefore, if the fastpath races with a counter flip twice in succession, all pre-existing readers must have completed, so that it is safe to take the fastpath.

Of course, not all parallel algorithms have such simple proofs. In such cases, it may be necessary to enlist more capable tools.

Paul E. McKenney 2011-12-16
perfbook_html/node471.html0000644000175000017500000000572211672746163015655 0ustar paulmckpaulmck F.11 Chapter 

F.11 Chapter [*]

Quick Quiz [*].1: 
What about non-persistent primitives represented by data structures in mmap() regions of memory? What happens when their is an exec() within a critical section of such a primitive?
 
Answer:
If the exec()ed program maps those same regions of memory, then this program could in principle simply release the lock. The question as to whether this approach is sound from a software-engineering viewpoint is left as an exercise for the reader.



Paul E. McKenney 2011-12-16
perfbook_html/node212.html0000644000175000017500000000613311672746162015642 0ustar paulmckpaulmck 14.2.8 Device Operations


14.2.8 Device Operations

Some devices present their control interfaces as collections of memory locations, but the order in which the control registers are accessed is very important. For instance, imagine an Ethernet card with a set of internal registers that are accessed through an address port register (A) and a data port register (D). To read internal register 5, the following code might then be used:



*A = 5;
x = *D;


but this might show up as either of the following two sequences:



STORE *A = 5, x = LOAD *D
x = LOAD *D, STORE *A = 5


the second of which will almost certainly result in a malfunction, since it set the address after attempting to read the register.



Paul E. McKenney 2011-12-16
perfbook_html/node11.html0000644000175000017500000001100511672746161015550 0ustar paulmckpaulmck 3.3.1 Multiple Instances of a Sequential Application


3.3.1 Multiple Instances of a Sequential Application

Running multiple instances of a sequential application can allow you to do parallel programming without actually doing parallel programming. There are a large number of ways to approach this, depending on the structure of the application.

If your program is analyzing a large number of different scenarios, or is analyzing a large number of independent data sets, one easy and effective approach is to create a single sequential program that carries out a single analysis, then use any of a number of scripting environments (for example the bash shell) to run a number of instances of this sequential program in parallel. In some cases, this approach can be easily extended to a cluster of machines.

This approach may seem like cheating, and in fact some denigrate such programs as ``embarrassingly parallel''. And in fact, this approach does have some potential disadvantages, including increased memory consumption, waste of CPU cycles recomputing common intermediate results, and increased copying of data. However, it is often extremely effective, garnering extreme performance gains with little or no added effort.

Paul E. McKenney 2011-12-16
perfbook_html/img253.png0000644000175000017500000001071011672746114015307 0ustar paulmckpaulmckPNG  IHDR+}6PLTE\ZZMJK# b``mkkXUV856iffC@@wuv.*+u!tRNS@f@IDATx]I;iRUD'@8/@R #]/ ||Y#ӥ;΢Nف#YvTчFơNu;z$Z~uPN'e?|8x!WviBZ kzY xϴxX,w$C :p{H4d'[{7§@is -Yh! Vj`He\=z]wgPMPʑlaڶ Ht¿{,LV ع`Xc\QԇOP.fAJGR6Wh4@,Ĉ@f$8;8I .@~"@!@"hyK *N"۰8I/MTqJ>@v('5$2AQ&s ?u ɚɚᢁ+qɔ?˔> aMC:MC6Mq&&IT&uvrX[;%rQl:&;/%uh#Kf-97j}k◄fRR N7с)-ТجE42 &)lsY!.:nFWrJӯi"c^h\ !/DRhTVBV{ݝtqT#Bit]ޭC,[1p3He,nȻ;bsӦ닑ݤPh<ژXmBc%/@\&!jjMKE-,̊I"Q;҅!%ZI.ש#M\4z|wM*[[r V -垕P9eU{:O>3Zވ.b՘TSәY/nfXTh-05.@.q)n_phOЂs ]qrNA %`BzkbڷNFP=AU(ת `6qlSN\7ۗn1jtsdc$VLҦ|EM]z5$[+Չң},Py-"q[VNT^RrO}ErftI?~oJZ\+ Bt_:|#pYww n{ R,9y7&_GryQӢBo 4:{J2s(]V7Qmaڒ3 &'h2M}HaD׿烘H:oB;qGb A_4*ʁ2${31Eͦe;]hɳggqųkQt|ze&WܹbwvclpXWRkِ@T1NŽJX{t; +]:|#>æb8%tw]á3h@QH=@aE|2%,zHa`CW>.7'/'GܔKo|yA6yVLvN;^o c8K'@,}5},1np״e{`cVZz!(,BT&!ҵ;_窔ٜm#D'= bgqM`Fw(|CW$̲ +譈,O3`6uڽJJ`2jǓ3( حHm8h!0KΏ>5)8DC%t#% C.:  n5(xaZtQk(\5r݋_s 2hRvwD_]O3h{XѣM.dܗz9oZjg$;:i~ʨJ~FZ| 5e͔.86'"])DƂozRQ:W,ˑf>(L"+)2#Z!z'sĩ <\ FDZ>Ro#q]+A+NY8H3zΟ'pQ(Ddq0[P|yUl7 /ES5^BW.|m)|"ֶi!Fըك1P\=^uH=urrDZ0tw)2aKb,4HDI!ʩ]kv^&edsQeSQIuCb܊QwfU;+SmΞe¨sU)ElG<9.m3LǢ>RCVmju[Swy1X_IP%SdV69P0as5C>?c.KrM=M+(rWJJIUR!I o&U <-ȽӺy`zIͅK=Yxi#GWn[K$\(q:̑ݣBҘӭ< 8b{-Yg99q7w>?m^~9У@;Q݊39UOmap ~ý}Hf%:)%crRQ:+01(O3(Ay8(㧰C+Wt0 {0lJ.L S_WC?sJ*\e_4 `حKQuRZbqd.|n~Yw2GKwf\3?IKw>|U|#DڴQU^tm:ĮUe9Pkɺs'IHֵugN!֠.Ѿ{~6Sw!na_Ҧz3!?/bTaֱ;\?'TlWGq,]8x¯A A*ٖg>_,κW) u`^62 L)v \z]Teų [ n½y59kWq_Jݹs %m7xm~~ލ3?`_`v-a]rp|g޾zOPsUxU}Gw/mqt'οz/YhǑZkЏ]Nt=Un,Tv5>xNʗ_=600|JLWT7*OatW,:j$(ytX?pp%A|0xQ1E0i=\gԑ2.L+׼ ENd IENDB`perfbook_html/img292.png0000644000175000017500000002073311672745754015331 0ustar paulmckpaulmckPNG  IHDR1b[WPLTEb``^\\MJKKHIPMM# hffywwmkka__XUVVST856C@@A>>wuv.*+VtRNS@f IDATx]rJ-•235V#IXg9nYc4k9gEy Cà^4=_?܁BU\teX jTol-ϻgY? y}]?Je+54"6^GiϹ)`@TKs~/rp4~Hm7.+}/jy۰nq%7)?mqh$E|M޽8Bz%7" ^U/%qvc' lfF(Ui)8ZoZẑ= ;fWlFrkL7̨T}:w%ޭ )0e8)9 9h2fhI+:?~X@ V_bv->9!j.Sd_ԉc7 A{OVG ZPB8qnonOk*7 Fl!U`Ib?{n?2gZ\2'N4[`07 <8wWjT.Aly2%yb=9+)oWR:Z0)σx ڴD#+:gh$;΅% ۱ 8^3[0VleDuwjrUmj0`vaX_5Z޶Č'aJi3͘mO2@4hc59,<zUt It@+DV(j$Qt4@71;Y^H_NXv*7+LNw}; ~&y e ,;FCi vrTV=.Jj Q%$lK}ޯ6hVڧW~t[v jUک S^ۊDW s~ =$(8ZV:tZ:ɟ۵mblg BJ@55y|k EG)jp͙ʁLUԉ_5(ԷJkZ|#m,40;)h#c|eyTኇ];q H?O F4i Oﻊ3S/.uz W16'89}PvLU \'\Tr2(a\s׳ v<a9&u45:Q#WxqHkpBtW튏 ~(CRcsɎ?6̪};NҎq7Qa2z&p~&,5XfRe݃\\jպ0z`Z^1()9_"B.ec*4>-4%DuJ, >Y\$Jl }>{:c~ ŴÂgSW j(͒SC='P]kŘjhHF5lkk73!vigxMIJތN m3C/$#qpxkxٝȹg]TlM 61ԣ 2( qKy SSĐ-c+tAĴvT@Մ"OOY@d C4sNE-{;xFO`趠*Keo`%C./> ?=}*>zhH~G$#-@li)Z&nYӧE58էzN$|YN[&";`fjH Q䖜o3RdSf*9.0EkvE>H](7aF)>Ӣ'8nvX)/kse(y&TRˆ*Y^dt̷صh$FWq8uo]-+8ٺy 25nVA1A^ %4OKd a0#T0O#0=*=I6$,.^օԭsڶ εD [YSZ>~N4) @'-4]p[8љys0Ipo_Ӝ&HcS@Ŏ~*RbxAQcJ$"P%Jy 29x=XЅ){ P^I*S^ |dHg "eliHǏjwT1+%ѪL86ӴSSxJ} Sf)%-1sO3;DMm}>}I^KRʙ{^LRބ؝!oP++ȜVw'b!Oַ}gGetNĆjmkfC?;/к'F]\mGiCHa˰x^0/tコUNA9=I+a*pH..kr|φ Scbìe4K*QI1VPzzs5w]oCF!D~ɦ~vfr̳+jh606qVv,ojq*{c Ģu"ysFyS"a,vh^7 Qkj"z['}VAdhSub~V6]߰7TxVϷ &QXj z "p'7K4\<+ۗ4eFY2p/RU#9B%@$=㳱07OaADžVgqUr-,^~XP-z5A+ ~-->%X[VKy`b¨7f۠f]07Ta!賄'B%.5dUf7;H(<4ޥ0D Ċ"kވ"( y?o I8ׁ4@I ;'W?R+#YyN|;\2c($i~e(U<+֜+^"k3B\/(T j}0 yՍb #k ^TDxIN bK'|.p [S ;UKX`}?q>}6jQ*l5af]ݰjawT3}ƚ>ze۞Җ8SC/ /ܑ܎3*3cJʼOqEQۓS  97CnFhx0E$c_nGD.'=8Rd, UCͳB>HްAFcsDϤ}*g\E bqx9b ]2$3!2g|Y9{.&R}>;wYYaA湙.T!Z$R-XU3 g텸^\;utg؝ Ģ^>?|mcSäLs MR4d',6``s̹:/xwUݥ4w4{`pUZ'qY[.')vTb^ɱV^vT-K?q)^0{vFic/`oѮڤЃz /@4?K۱j:Th`ZSgN3_u0j' l=6-ARs Y->}eLU]([ij.}N;{OL,_ ZX+f?y) j٠]i(=4'y8$"#W 5P/еeD+*ٙep֎Oȫfep|FiYYƿɨBcjKue"Sk35L%M,Q@c<ij BvV!.NxŪ6(hfJ IbdCe7Jedv}TW})]()#كW.͔P]DE{̺Ƶk%pSu+_P̈́niY(cPL@TFFFƟ xfdٕ( Jo.ͅ>6Yҝ_#9+ .s! ~'t-w5(h_5$~TюvlZyP+iBThA l &#ǐg>ҟ9Xc-|` ;գ6q!QpWRR3ӯ}kf&&Kg/T|LX8x}gal>~߫a@V%. #|Q_ţr&-_l8g^4BMmlSi,*(;B5 ÆWZNrёj"Z#יa}b Yݱcl^|;Κid;kaԇq;/a>0_ `ȸ !7ȶS~07jF+ߵeqY"YFAQ4,###c#'$ s!URK[ЪeiĺMdG qUO\%1SjFL8՗Ռ#A˅PEA9'U&PP]jMXMZsY+k198 =&-g߅Ƥt&*ǍוS^Oׁhx0f >h?irx*^n!9& )a1w@!jz1lt%[-~RNrL+Ժ*c3qg\)#كWrݯ䜒]YUߖYk vQ+a1;8poP U&qwސ?DgddbBtc |3?fKAcH!q^1⠁\^d.9c;:_?a3HVZΙZ&.de ;e6#Jy_1,cEYDzWsXY, C[mQi@vlo#3ǨՐ6)]XYKǢC X?DJCQ(,ESTne#3}2ưeջ)]5|̞@ rV9xY,eȭRҪFX9Azͬ@ɳ2#~^֣Y>yYPT7c( ?}nIENDB`perfbook_html/node127.html0000644000175000017500000002504111672746162015646 0ustar paulmckpaulmck 10.3.1.2 Wait For Pre-Existing RCU Readers to Complete


10.3.1.2 Wait For Pre-Existing RCU Readers to Complete

In its most basic form, RCU is a way of waiting for things to finish. Of course, there are a great many other ways of waiting for things to finish, including reference counts, reader-writer locks, events, and so on. The great advantage of RCU is that it can wait for each of (say) 20,000 different things without having to explicitly track each and every one of them, and without having to worry about the performance degradation, scalability limitations, complex deadlock scenarios, and memory-leak hazards that are inherent in schemes using explicit tracking.

In RCU's case, the things waited on are called ``RCU read-side critical sections''. An RCU read-side critical section starts with an rcu_read_lock() primitive, and ends with a corresponding rcu_read_unlock() primitive. RCU read-side critical sections can be nested, and may contain pretty much any code, as long as that code does not explicitly block or sleep (although a special form of RCU called SRCU [McK06] does permit general sleeping in SRCU read-side critical sections). If you abide by these conventions, you can use RCU to wait for any desired piece of code to complete.

RCU accomplishes this feat by indirectly determining when these other things have finished [McK07g,McK07a], as is described in detail in Appendix [*].

Figure: Readers and RCU Grace Period
\resizebox{3in}{!}{\includegraphics{defer/GracePeriodGood}}

In particular, as shown in Figure [*], RCU is a way of waiting for pre-existing RCU read-side critical sections to completely finish, including memory operations executed by those critical sections. However, note that RCU read-side critical sections that begin after the beginning of a given grace period can and will extend beyond the end of that grace period.

The following pseudocode shows the basic form of algorithms that use RCU to wait for readers:

  1. Make a change, for example, replace an element in a linked list.
  2. Wait for all pre-existing RCU read-side critical sections to completely finish (for example, by using the synchronize_rcu() primitive). The key observation here is that subsequent RCU read-side critical sections have no way to gain a reference to the newly removed element.
  3. Clean up, for example, free the element that was replaced above.

Figure: Canonical RCU Replacement Example
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct list_hea...
...t, &q->list);
20 synchronize_rcu();
21 kfree(p);\end{verbatim}
}\end{figure}

The code fragment shown in Figure [*], adapted from those in Section [*], demonstrates this process, with field a being the search key.

Lines 19, 20, and 21 implement the three steps called out above. Lines 16-19 gives RCU (``read-copy update'') its name: while permitting concurrent reads, line 16 copies and lines 17-19 do an update.

The synchronize_rcu() primitive might seem a bit mysterious at first. After all, it must wait for all RCU read-side critical sections to complete, and, as we saw earlier, the rcu_read_lock() and rcu_read_unlock() primitives that delimit RCU read-side critical sections don't even generate any code in non-CONFIG_PREEMPT kernels!

There is a trick, and the trick is that RCU Classic read-side critical sections delimited by rcu_read_lock() and rcu_read_unlock() are not permitted to block or sleep. Therefore, when a given CPU executes a context switch, we are guaranteed that any prior RCU read-side critical sections will have completed. This means that as soon as each CPU has executed at least one context switch, all prior RCU read-side critical sections are guaranteed to have completed, meaning that synchronize_rcu() can safely return.

Thus, RCU Classic's synchronize_rcu() can conceptually be as simple as the following (see Appendix [*] for additional ``toy'' RCU implementations):



  1 for_each_online_cpu(cpu)
  2   run_on(cpu);


Here, run_on() switches the current thread to the specified CPU, which forces a context switch on that CPU. The for_each_online_cpu() loop therefore forces a context switch on each CPU, thereby guaranteeing that all prior RCU read-side critical sections have completed, as required. Although this simple approach works for kernels in which preemption is disabled across RCU read-side critical sections, in other words, for non-CONFIG_PREEMPT and CONFIG_PREEMPT kernels, it does not work for CONFIG_PREEMPT_RT realtime (-rt) kernels. Therefore, realtime RCU uses a different approach based loosely on reference counters [McK07a].

Of course, the actual implementation in the Linux kernel is much more complex, as it is required to handle interrupts, NMIs, CPU hotplug, and other hazards of production-capable kernels, but while also maintaining good performance and scalability. Realtime implementations of RCU must additionally help provide good realtime response, which rules out implementations (like the simple two-liner above) that rely on disabling preemption.

Although it is good to know that there is a simple conceptual implementation of synchronize_rcu(), other questions remain. For example, what exactly do RCU readers see when traversing a concurrently updated list? This question is addressed in the following section.

Paul E. McKenney 2011-12-16
perfbook_html/img244.png0000644000175000017500000004023711672746065015323 0ustar paulmckpaulmckPNG  IHDRIv0=`PLTEb``^\\TRRMJK# hffywwvstommmkkiggXUVJGH856C@@@<=wuv.*+[YZmjkj;tRNS@f IDATx}< !j2EP {/"d"ªQ*TeU7=jۺ3ĠT l\o~R5r\7X؏SeycZM6"C8ƸR%7*R;dIԵ. Jj2 GZƋ_Q賗*7SFn!/]wjX Uڦۻ0qԮnW{˪ 2yQXS%4_LU`}}uvb{R<]ٺ nT tQ3oozVEU8wzٜglWpbKs~f[in ߌUg4{}vlH,Qw~Vk [_c?T-'H1/t?iAxh>en~ za|:4_2l֙SMyD Q)_v7TGMi=47'9$qu4gmу?(S𪓺?$=v,l~MYew3D//QAu쎧P޺Iu~󾇌~iR_*-i:¾sA{P s3*T<(Bia@VO?v{ -TX(e0.݉~oOKjG?< b~y+#d 7%j/~ר:AYzl?1v{IϏN/F=}Ce^Oy0 jᵪ[[ {z{"ᕚ o-x6'>G\4~yuNC~5ğ,L]7N\֘'I~t8)Gꠔ0ZikXtYxmEZNZXX/:I;w@m^ z-ڏɿ6Q ;U.:Ȓ!ᙂ](/ ٫6V%Xٛ/Ҡk?ZIT!OyAa𺲃uh-'*ePݔ}U24C|`j-xYƦ8 4Yˣ6v@=8{1(3u98b7q C ;;kdY0u/z1VzMGT_Ǣ^mKEo~ KCi"}٦Rk?_Z \}vMP5N=xH4ts IF3-sL&boDp?~Ûy1Z&h ɢ{9Omr ,00@e>նFn ۨ3(Ao! ~:s9E6a r]⋽EY]vX:bvʊZI~DWTuWГ^_;K:W'V'Oꢏ n蕿ƨ4a|[?b"^ĂF zd_<i?/Yԑ;Ǣ7Qtħ^Ȉz ~PcSzi ;CtM->%t%dֶ[iW!Tx[暝_yZπ|5B5hUXю[ZjlUzUƾ460 `-dD)!ܙRS/JQETq 6p QGCU_W\]d%.uUtC[~9L^sa0Ǥ21 2ij[&jb?ΑV8>UKj=ulgJo0A ;t|i"=FvHʸ{])u"MR@~5qDhZ\|LGPW20T`0p z;FG_v%> yW ޟb4)$^_2* O Mm/\ua: 9,'$؉ZёhKm% pAĄ^?2+V1/UW]m qd!0 e\D ߞ02Q8}`~3ݍσk_D~R4З@KaAٛj䰜ptœ.Ae/x Ρ 0X 󥽍Z#ea׀,_lKCCЇ/Ypb&J#FaAtp4sXxM0LAԥ )bG "<S/|Q Ra?{WD,_v0uky٘/@s|[Rij5=pHy;QY/?X%%kg$R+G !D7+P,i, aWN}K/(*SubZmh"d(Ȕs@Κvw,R%Y(x䕠iINJOTKnE^QR/ʭv@RIwҗ f5AD&_VRā$Vt ̮CQ: Fx06rt3H]0LgZC\~=7۷\ͳ˅9,fhk5[7 khN2x;~}&x>u xzv)PTBěC?H;@ 5t{_H.k@ )z@WwMhY|ͨJ$pyJ&fV%ײ϶o -SEtLw C#4;gAkւ᪶O>ɑRC2R]cvPbZbX(ɿSW mMj*p17!f^EU#|i«ߨpb*!85d7TKߟC8/VJ÷? ej ʨ_ЈLw4 q =QuWzHk`o&ɀH Z7@:Z`.܁ /q]CPϡ?,}KG2[j}g[cuKZ.4zu:;"=[(sx2ne@/YT4H^DuȚwǝ mqٱNd3P^q/&u'ѯ4 H;VeB٣r bv20;JYDj,1/PZz7ܔQ4=|pl,T]N딌fӊ߸ $SN~7,[ 9Fuh~T묙zAFTy쯖@3uy]Ԭs߂G$aHrՔ MPF޺^ʺK릫 [eS+rq ya7v:U _^Ƿ_(8ѕeA| tuA{T7h8&ԉi/ !ʱ׵ShhK8}{(t [@!=7K_c. 6tUFj%OӝplBcWlT}g@n_ѲjZ=?[JQд0J.>$OR #V-DPֵ_j4p^x0PcJʼn]ᯄY_%QlĘA#דVxK"QT4 W;ϛ<}L_+p֗M;V[ѕ-keKXm0I-WXt_(-^g(ty{qqoQ r"-" &bB>cb [cjVH/Uɮ.Jﺐ/ADg;+ Ө)^!ݡtyT}HѦpiUf[&"1}Ryv]wə-K>F/\ZhTih;PNIj?ƥ,|h gO=sB\q'KR="'7(_T=.˕|YSj1:.֌rܒ/ Tâ;븵6X{^ǨʶioG;mwcbRPzJ<7EY.FR"EiW~~,A`X8CEaiskr']w ^, hbgLksl:Yej3C^Pt$-j٫I0/3$-Vq_h<IE3v/Ɏ8_JrRŃ2onN#4 %CNL.VSFNqo|J¦BMR/L, 5)O>Sj"V1ɛ$65 s .lHG 5'[Cn&_ < KYZ\ƃI1O}Um,U&<ò$ݳy !zPk'McLuīB뀅N!rՆn-WϢ||-5s9S2zGtO boAk`#q2FQIsç˵W*z^-1b=a ֏H^dI /,dL{gsC\mUA&C_~p~;Kpw+jyTKa|[IzaoCX7Ȱhl2s/^jm!=sՁĎ1 '|%4oI~&~ \(jR'5 P@ XygjVgRKWyɗݛDݚa9W/ \&@F ՚[{/rbu﮵JE\]brX=)̺Ć 7W!86?uHK+O7'C䴙6;E&jax7˝^tKA۔4LfL!zs:` cD![kݮL|]LlSt2=j[R-h3!.SD`DvQ::t4!ܭvv}D$?B*;-.G/cf?XG-D}eZ}I(fM? ׷тw m,8]!g<6"\G{Ew(kY=ʗˑ{dϚ y.cnæ"(GV_m{j$5 t rN _0M A5[X#Qt tc=圐o3s~uv;L2`{$O{\R>gU+ IQm+,VLhx4eY jй6pgcĚnRCJn2j@Xpɚ ݊R=0FlNN<2Y&V=|BHYLx˱'F |d8kZIQ9]A̰ Oz-0l)q=_>l+v;V*;3USrA) )S@ⴙw;94e$(Y++ m0U-ȘL5NbWb5o$> %3儔}BB/LjvPoglNxBxs -J<.a;t6Ma2*~A@W_ҟ^Y^55~b\}}R,+Ir? ӕ Sq1^}L'hoD\.|_?W+?RLVsm&ِ}>.x,'>:CvX\ֲQ4v=fПlFf26 'ipv) )M$S`L^RLBJm[=vc:`JV /j p!0PY0G}+ oU)<Pf7硏xؽxØ;0ʍU#354ztA?ea-6Y *X% T,GD&(ܷxCܒh*P mtY:\7=1!8AHp!6X on$b(:J0\QoD8R y&뵂`60d7ŞFgױV X ڒ6A$WXg gu[݋)d'rf%W|5O +rcMp OFnX*dݴ@O%{Tڅ0FՖw^++TΨcvfQI(s۝P k1yyb ?2и9SArG7 jʦ)7⪂Fw4q[Ҫ$_PI-ã{7>9/]:/=> ؂2Ctw3d' P `*g3ˆȜ*zZ I!JRa&|GKza4ZMfɲADdU9pЀWx1fupq#o  (/u۪$1:5? <4'rT*Bͪ&y9.uLQ_c5psKbzb>Q%?iыw50S*lY2(p}v>Bp*4jsS{:uy01gK`r%`t( c^ <+c-,X!@э>/'F`0lTWgz /dK򓅭 0 9f@HZK2:29H=" []^/pٰŽ'Nuc\Ր*Nc$ͼ~`r-WttaO'ԼOQ*<ۣG+96᧣}t9n>}W,%KY\U`ǕQIDATͷ8Q򯲛^V5:?IYDQIx#sE7-r@=Z %š31IP2cCQ, a4WOuѲAb c0, n"? _U0UF*{mUDxE a $nʀ9nb6נ)^?CH bכ~\i9?1M7T,#=U|jIe#O˅իR},LIC{}N1Jlw- +z9SőjON'a:" 6S%CPb 'FD eA m[n$H^Y<1oej5E=ÚÀtQjG;pn)"I}Jp>>$d8 r>1bϪ UFhJK=T&+a жӘ)sikR],2+yYE'|1Td+0 #l5nhI\ru^WWZ&-JSzю#rJ5w&n + \z HcyॶƖcxبoL\A@aBLl.s4'|UR[T)2@!bpΚ=O\8@Q4|ŹU;Q:gtm`}#۾տ;K{Q ;FN"[$/x c &_N9Eʩ߆hkljI!1mHaѸ٠Lp*1Z&+4$bp-~U!EA?g ϾLaE jlew^Fηchn,{aj9؃9uu::; _q ,_SKZvC߬%t Vł6KjQIrn:5Q$Y<`wWCz5ޡ̭?JJ5XzU^m7c#c \.,CDAk.QL9tkIܰj"z݅DqTlI-9ղawEbhyB>)2*l#Rk.QOˉ+sc(/(s`NjFV>~ՅϹG)D0gP%wt6wģlz>w7tO jZ`WK>/ajvǺp… J۝yĜesoF%[`$XoGu8Zt+]>[@gC2-Ysc[/@j~dwVb^—Oek-k5aiu Gb*hGRAS| 'd5c]; m7[EgPg8~aZkj;b]@4,3Ɂ)L~w<ՅnR:[lщ|9x:+hsd9^K.75.toTa!*'avVka7Ch tof .vrT7CKviLܙnjߓ Udp-5fkLx_kp(k$>f!.pT.]h$݁4;N>5TÅ )4?I ;<߻^( Ȍ묝:zh\U6NB#,']7|pbh: \](?\:f7u%p=W;}a{"Bf^b*,#"Az`1y@kP Rpؒ,k!UB!ES[XI^bpЮLR{t Aw \t F\RexTKD-u !Ǫiz~lf +CyrG'ȳ=>#Qp(ߟ,NSr[{$<>/Å?d0'W9n#~y_Z'e-dAZ"@>;Dn $?Q=rŠ&D"XW2œdAZ"@~0L?Zm<0N$ >i$8 ;ݞd$Xc鿬] oo(.f[z9[B^$$^3-Ҝ! Wv>]v~?jkY%<'{ +d5y}8 RN0=lВӭKxY8f(!d{`غ| K kgr2`lX"e{X?6ye%p)Оfc F}tUfm1 b@HX+ƯNFnDb3Llί+;El#z?|\Қ`&]m9#txbXW̡|k0-? " o{~L; tp *1t ,#~~}fW|MCE2rd2CdMX%'Hf0[$PJU^zVB"T,"wX^X k=wnvWJ͟|!9CdS&%3>>d}\2"H#t ZRƘƎM])VmXۃ\zf@ӊOr='9Aj+  eI,sheeju ~}YuD*Ƌ&t*$ք=SH#I2J k[Zo6":R;J,tdUr? ΄LAyb xEQBsX?? xL 'R;,J]9 %\.XO#.2G<"?;{>?#s}J_]d˅/mx ֳ1 Mvn\ɻ F )›rђƱI1Or\6Oa0Xsq5P٢Ck]rE}+\@kq9pΥ~S* ICBJ.mKCfpedjJkCNwoA@W"t?2k`Υ#oBI{/06 Z/bvoEIԒ{-4K׌^چt#(x#}CK-ɛPFWPLޔ Z9f_Q.h 0oȖ"WBhS?F xd] N&QKj790ۖ1)CO%G斌lGߎ=/^"9\2Kdg/% W0dW%;Qϋ\5厛n }n^m JYێ>?ɾԒx$[1;<%j7RJpᏂO]`"ǀ '-R6=  $EJƴ/NևCIeaև+)ÅORh*g~rFJ.?Y4$d[7t8]<R8*@R{e"͛~rh.?I9`7E 7iH? Z+5Ύ8Gʻ"qR:GKӌ#3ڢ@kv-p.#0wrF,ڭ'%ytmێ>"@ ߆Ұn6h5ċ''ww<¦|H;ӯ[YiƪВu$BSDKN]RR[m47c[[kut.$FoviH ~%OƸE Ғw`rXY韫MT}+@*Ϧ](;pɠK5Aâ[Z.8fNXW`.^OuGPmGѳK ߴ> )OAv q+hc] T=?`ɹJ=PG廲7𤚲*X:J'^_ژXb7eo Irv3h;`D'/@2tTd?ڼsrr`C %A>]S A{!?V# oA 12dZX562b?v\O7d>C OR&b?…#عΫz/d ݴ2SjM~OWX;|LseڼSbG0< L?7Yl@8 %C>ؤ?lw`Q/ʠ<D#O} L*@q h%a{Hy/X (pWrh]#NREC(y ,*KdnN,]-i|HUTѰC~@bD23Y(b.>*=7$w,fh_S!lD!! BOrWq3*=dfx΂@  O*ڋ@' $**s9>e'37'E=K٩8 }& ={FcmAO!s.hY\K)9^zI@WelfAun -r`XA+BGn ,|mjǘL,lDbg/\AL.M7r_͟ pljw NicWKAA,4M|%…  Ymx ߞZ/?9eߒQ'8x  B<Ѡr;S w4O@pt;rd4{v|Qh~G9oW}/һtDChZ?yN\יK:Q̗ 2rdgǵ+u5(ɠ^v|Qh¢QJz]̏! Y7mo~>:|"_MяwL~-E"oG.cEkiak}|׀-a':7g^kL q-^'-m CYЯ|s&a គr0Cʎ%B"wӉ䐲#*gu `ܙ2D-X3]2SA"AO޳ F:DX]5Pb* Ğk9&uԴv'sG|03/QΥ,)m`a#;6'_NT3ce@{d^K}j6HNbj7K߀FS93 j/c6[7a]rȈэH?FXME~9UЦi}IJDqc@ޕ-[U֏p? /lP㹣׸2|z?eLQG`L3AHYViՒchM0{eqfմocIM@!lo5)lVb3Ȑ$@q+=4SZ]N(S)4f ah&}2y3BgKqw攞Φ⧓(;9Yc]QoJo !x &cH{55g*l|xnOb r{c  A|MNX͓G~Q .]LE`dOÑ8:Y!g+Gl7sF׭Q4P$HZD+zQ \E]f b*гXKt4#2$6h+zm5B),j1?~e=!2ej?EϐG? U@OMO0{р#BuB,>G,m* PZdzivvLZ2[Dr6nRYS)lJߖ͒JPukuѕ&ٷkIlFf>^M7L?ڈ%G}kPe3z`,9m:ZE *-KJ`(xC/Q,6˩rPYt_:wӗ %r'4Jie0$6?5 sg\GWs>TU'MNxfM0(4Hbry\C os=bpW>{uPH Цkvm*U:>R6 ?v h%˫2;߅6u߂{vn%3XZroˉ>6=<[${H|DJ k~NO}>};¡> $ ʛN{cw眻aY1;h%iK%gЗJ'ʾD/m]/C16Iz^-8^ nOֆOП3AGG.&2Ɋq ,^6)H &IÆ5qie8std|MCT XeC]K'$|ƦqzM lH$z]D^`}s_=r͈$@y$S@}mZ /X2$ʟH`"; חS .*}KuW; Ц~9cI9.jK< Ml_UMxLiS-8\UijՉ(6%rYd䁪BsVg1t28oQoũ޻/O-H>d0DGRLqO!NӦͅoM37 ,XZ݌IW .|9"[?Jw=qLIC 5Q:Ɗ8R$C%a *!V֢](P ER<)4D/&^LHBrp}\CL&*nJ*=)\/:t¥t*i.S;$i$(ìyWq)b.{Y5wc-4Ѡ ,TJ/rɣ&]xK( Er D]]q5+"(, K 2y*~luqʫNO!,xIb)sh//`Bb0üds4&|e;_bb7XY$u'O695?sA}S (L>N/]VQvt2u$5}Sxx$P*<ƾq"Jr:Xߐa R^X7HGunoh A0S7@3 7iBt?ʕ0cSș1r/+IILFbʄ\"T&|r{}&$5"j,|{s'y@Lƾ]pmv3.#g\2Fθ"gwTa<;D^~{qTΞmd!+=H38.X<0E%}'WOPHP*.4MؼEj`ʢC״+"B/SZ6]jgwwO:'4j1 _/rf3Bq[XK tǏ ەpx#UW\ODUcfRIXvVUxbNmIe.ks ؿ(i&B@ `Cܵl"HOwR 髶Yg~=3z͠0ϓbv{1auLG5j.,@RGg}_WEss]rĕ1IKꐲ\DPdmY@Q(Mn'k45R#ƫvpK;/CʵXPބU*Z.BU ;c8y=Z"wDQ.D%*ShKR-mY4ʗs*C%*=h\,|\oa}h{PUO%*he+=t(;F)R^H%[\ه| b ݯYP0Bnхe 0yrVi>kfOs^ c RT 1oȬV>Ş* )#I Q+U`YjIrE5 $/lV,!l)2V,bWHYh}RjB'֌Rch2Vr)|^so(Zx2e?Q> Ĩ,2F '4W62Tka[ٛy$ 7|z%\ϷA'e3fcy`1S)3ié̖.[qYΟN 3Trg@ غ%jHïjW1.&+ˉG_Io}aӋ1; AhӋ1;FK1;?˘"R޸w1? _Ouƍ"Z#~# ӿ=?K4 {y@:=ֻgl#?6Qؿ7K~o~~10QݜH<s~Ot*'1D';}j<'`Ƨ Ojf|:FߌO!X.羶sml k/n0lx; 7eWm@x1SAJ@R-ՄFiv;6#?je'i! p sĠ0EPY{a-=@"J+46C:Ok/Qajǽ?OAQU/>Q'\އ݋q!.1wѥ Z Id VAҢXI= eiQtWmw/^^x!TE2{hEF]o}wbv:cN-iHLgJbe2{hN3eiY贪6xvED9G@.|eDǬ}}|^'>QŞjO6D}"w>#15UFY6Dyݟ@y9c1DMn-uox{0^uQuQuQu~8Hx>=e 7AU]ʂy ]WPoJ1z |o"t o |ZI}`/()&]z@_GySΟېj%Y͟jx cAs=c1X7Q#ف%۽KM\ TƁS'xk'8pv yITeMܿws>~Uxc8sW|]>.trD=m&̙lٚL]C1mruYl&,PQYH]^i{G9@]q.cdۀ#fQYKIF?VǦgDI>IңY>ۓ|LsMЛDgm-_7hK{}{3D.OyR':VГ}"N'jxRODю5<'OaEGToN':I>/dԥ;zR,p[luQ"b#=K]9r>5=]jnyctǾ.-!v&0IENDB`perfbook_html/img53.png0000644000175000017500000004763711672746056015254 0ustar paulmckpaulmckPNG  IHDRVƊyZPLTEb``^\\\ZZTRRMJKPMM# hffmkkiggXUV856iffKHHC@@A>>744wuv.*+.GtRNS@f IDATx}mڡ6|9{ep>J\gI֬YNPt@.1}ѐL}YY)t{k=,/Fev(J߷s{hO_=`g>Bd>VeVn 8P6WV(kQ_R*'Y7I+YP}x*d*{k^b8xKCbe|&jN`~8TSKH#$Ǔw@tZ\a:Ժ{M`0 o-xsf4/LK6Xr$Kƽ%>ۧkPYGPhи)I;ܐ Ya /M0uW)LWhLaN~'?A?C !vx%R'; e?Z_3>XS^=YG7)z3㖭`kC6l$Aӌ;Q+߃H>?Aѥo5n ԯ ئHR%2 ro Hzo)/=z!ariWp٪BGlD|h-؟ 4ThY8U '$h3;{Kvaڏp>*Ү U%寢 3.WLb>U40BȮ̪6#z#=ǿ:=S {8VAv;oB j*ETVŵe_ov Hg,)em  ۫\c5KK rJeK)OAE+'k3ej1ވ^VEnzCDcL7J@-z4ucddU^E~7T+Thh Hgk_R8Ǹmhg8w[*yXN>Ch&jv p "[6m\2&W h.h='PtI\_mKb*O 7}2RvRNAHnOOy T4G0A$jAYUu5I>_S^tBi/fٮ[?'\+ q[uvua\ 28ZYC8R|E݂>Xp]m<{u:ඇlBߣف1LS½}0K3DW+݁^Ε߬Z +z/'^HsO>#KbJ~=j^#~!4ȏ LZ\{i LE+,zH>CW}Pu=ĠtEyOPD}ѰOa>rcY֭*^xHT3@g0}1aXO6] ξLrIyV S1IQQw}ohf{ []p-{DŽKxGC4UvxN0׊A0ϥI tIf7A=χ\B'T]J5m1["brK+;h砑}a⁽!=QBTi<5:gdL^*K VB^ h~=x?%|Tuja`da͹u$B֍\`ѠV[Ph}XQ3 ͩ#I p]Y4"&Zj'\EcaY4CwÓVK 5>9+#hwa+2nю/*qM9 TSVg~)8!?7;T3<X<~qg6KywuLØHFH7KtEg:JKM~}$Jj\)Lu&7.SUm/(}U +?b1FBDR~ݠT,@׶=>~ƨ2W@'>x|sxi$E% َ- xޡugyeS.VͯNK΂Ӥc NÅۡ "^9;XjF㰇5qE݁Tc . <ximwoAY}X,gQ=3#$ 2"GG8YQ&Jy˪p4odexqδ [s@[Ao0LT*3T 뀫U=Jx,j3&+cʼn^}cdd)nr8ϦdTݚH` L1QkPҾ0%G nVfoP='׽ow04Z@s" _%{mVHbw&\W$‰2=p9B4C(=:'~734 L EC=:̪  E8| u;JS5LO9}._e{ZϿ?=N:wGĸRo\`[g (UQ obw4҆<*&FS4r} *e}g韄 Ar"F$;@WV _}`^~*$Xvǀ/5 4Z_wQRB+ lf2>Tl|+|đp} #Cr_z}{j28 UTͭ?;n}QA|ݛD֖$S2T&*]A<GX[GZbDOmMd $}nO.y}X%_7=f J* k!|iS+\`+!:Q; sE5> m]z`A <'y!|~ jֵ|~a~crW#Z15,xBt A3F0u_~cT!cw5esG$ƚg?үE kLFoU>73LqΘ4br  ʹ:րlUٍ (.f! C^0^#;X++ֹc]H Q X%qaRbڊ7Ctdۋ{Î&֯,dudD+D""5Jo8ϳfIàh0W\`e+ߎ G%_HsPW+0sY&ߚgN8~ܝ¨,NTNczx~.T/h ^E'W;UіyKTxoǒ};jλza#r#K"r݇mNXf_4"o n ¡3-ECv M_(#6-H}fvEu}gӉoݍJyVw}dŎp]dt$Xՙ?B%*68C2pAxLP8o T0-i xK\O3bUCioܷد,KXxј /$2Qg9ȇ_AoIBPs:=ݓ~Y-dyl`fSQ=_`ç}K tFG]٘\fjv!>兟|*%qRD^+O$2_N<7};v MMf`_Wc1xz^lG8 -JʮZwCLăY*iueXq&|b8H>5RCGO]GnlbF.jeTF$kPOM 8_C5M0^<~4Cm Q}au9{E_QDƢOݩ}g$NGA;aN;v$k04& zFzt,>lrG2By͞ªN9^+!{9 ]0wE T6Uq[C.ѻP Ν&xA= ۫FX/2 (tjh;ׄcb\/oF 1^~ 5WY!?vl6~i}=w_1Y˵=԰i:pO\e֪jm5V`Jzu44~! &(Epe}E-*ۯO,o chiӚ](?086!~T[ #,s3`?is޺$2̒øbITLײ~Ll :%*59$T3DiLA1ac0;G=UH )OB15\ ްPM򵭪cgx_Q "ϟ\Z7Tny5@u:@v@9 *ũ]8tUi&qb ̼|j4Uoj5~ 6FmcPj%'Y% & ,l+NP;U;' 5 կN/}ݝKý ^v5pa|i~ϻCDw5bn5+ %ŦXyRPat.dԅ LM^%Vk>p,g_")E~(hILv5$]FJ. i0ZF=U 40] vvʾ>8~ng8sm=79ۼN݈i_k1󀾍W @e%$D[5K`3}XeLseƍK?u69|0]eo8 ,Tr]|sTr]> 콥zye,*`8P| *ZHSA… 6!XW y`d_9ZJx IDATmok1P!޳].0KЯM{b"{'%bȳ"^Ziڌ`\bmm{~Nd$\v.`odwikBrK_1Fh.YqVfAa9q[ ]`^ 2`` !Z#<6 M1#9 'XhjCD稂+'E Y%TwEy]]m#K`6Au'%rؖ-U5RDr?ջmm94D\E,`%>L!>.~UzH"h5C\o }8 2rN@ ᤎ!+i|K?0\.̲!fix#wv4UX!E޻Fl -j)=ZV)JwÈy<˵5_RB!IzBSׂ~]Gp*뷔qء_,J8y ې o] n^t XũؽJ!R ,71*-B;hľ6sH2d́>>Rf;ۊfZ0KxCb70ւ9Am}I2C"Ϊ#Բk*ŰEu IWq?\ahhy i& /E>E&EX[]f/#̋dekaZT%E•G,̚22Tv{TJ V@1騭K8x֤ 8p1ْ;i&rwon3f;܁3mۅC`hm4U'q+k 4U KpTz$ׅƌm m6am"T=m h/BqCxmLVt g={@آq?0Y.p QKao\ab_Ms8$صAkT_5h+r&kJ2G=Q`.db'$qɇc"Í-)FmCm ,̜+y>(.4[I/X[A20LJ[Eʰ>>{=r+vYM+ ۊSr/Hn[`u9v5pN)XdN~۟FTS祽qp/ʕPcgVSn-9)V42i+2؛I.c"vh"\N.Z4YKZvΚT%pN.#/(I`g-Ko[,/w5}Ə@e=yx3n_r1uNWlkBB_0Ծk-qhpO-i 9_,]6^.&fTjzA+hyP/c@PdUHwx=)5\[ n`ImA=z2Eڽ̨ hkze0V;Ix`_*z,g'~!gk1(g<gTQ* 8I*8$_hcmK|);mބ9|'ɽoCr66竰J\S՟^, Q=cy *Pk_e]V[4ÕWRLQSu/>/ʛ]x5?!,:SBrvrƌHK.]Ir(I|V{?֌YĢ}yn"{%?n]|+i)ZEB _ hCq;q6kOoϋpJ !9'\ _@Q|v}k=u@҃Y޺> {1Pj65C$4 dNkxˣ5p=)aw50V?wz}Bq ;tMܮPmPM6=S~sx/! tnz}  ZcÅvoh\ $D4UaPg&O9]ExRD-=LLSU[(1D@<x01FDz7=j9$m)i)wI'Z+B-@TST;OHRV iD@E" B@-J~0w{dy8 J,_yخwUYcL}6# @(& ʰڃ&"Ft-G1\5A.2URBN06(=L*$&2Q.ֶ-l5U+ 0I[AQ<7`X;/.*:*|xz7d䦝ȗU9Ohk_Zs \=[ҚQVW1u%luv7`̌Ls9=`韹3`[8jCU48v[=xrhulS,';B FU= =8ihEDH%jK4;[Lykuwm ;4p"(W~HH0amp=LB¾ȹ?7(qa?),;r!Xc<@Od|(|,(t%w TKεa7bWM"K6gFdFV_Dykm %'M31V1 {9NSaXS~[5U?]Xy0l!f:V>/.b Q.!sK|h#h+^o m6h Mo8_IY; oX曨Da zir؅ׄo kt/dBT=/B]BkXR]㛬Gz#>7mp]*ݐwUukxO"#![AXܿ[Q)I+5KRwӅs]-㛆fÇJmOemdla4=τ=Z} aU!jt90/IMv&Fp] zS.Lr+~}v%nU|r^I;!s(1.F oI]xfSYQ5M ;1GLסreYNֺA zvQ 9:~ߎ"? <]P7VۓyTv /"rƠbp/_jMf°H`TvY9ݕB !:=Z x(ܳFdi[nMn9zmEޢܭnMnC. )2<){C=W'$$$ +#\ a_ ҙ>u}x2q&`~|=Z&P֋T''i)D˔6#Ƽ V(%ZNкߺw,<%З3ti "]̉Rk"H epą*UZOK?mRi%=xMC7]ػ  .I2j2>LJZjMEY/%pҊKi\i)x'ЫaC,\y\x|y0})ЙY=9ĩ5oD[$>zۉ)pwȨsk/v ui;kdܭuu/z<0pS1dx&omT9R6pŬ*1l ԀR5R#UbY%\ ,2ep:a(x M^) PI ,ۨN/tkD䟙0{>3{AHW !`ROalen < +{d+$Ep,b^3ӁȋX#:K!a^؆L6 Z<X|Э=i!DLx8/Of qI3!/Fb}d;0LLKAa^$~b1 Bޏ\_5"dP$_~hfW1yj5>)jUN?*.\( %9kSt'WaT^ xln*2\ ̌o>_<>^(K7TќB{SƘxFpTpH{92o=O@6ߚԆ?Z&iHH%ܚ&=᪹ y^ ᥮$$$$+30nS竑'yd`KىL+>i 7 dH*=HI?gj S%^ u“D؎>[ȉtfJj^tkU ހ3h躽Bß$G+4d׬P iZ_BB[Vjc6jrc"Z]-5>Zhޛ~k*&ZoME"MH@Ks ,7ѕ`$d,BW-C쁄{3]"֕iTymj]IȢ\>wYk$ah!G[|GBMcE]]-$ѶŮZvdUeŲe&'!HN?귮Z 9~벫'Z/;_2F\-Y.? .Zvh(w,.G 9\ ]`a*u aԭ- $$$$lwگ"e z\z.Br "Uu T@]KwW 4APdCwl'A:ں~]vTeъqn5RU4A`Tƚ { 1wce(l+ >_RIUuNZ^oM'4ܟzur)Q\ ϤTի;g+$rloRaˤ1HA%\T,3i`by-s +_G8yGDJ+O$wLYbxs· 3'oey]&IҊ;SRoy4Z3 3c6JOuZFKS0,/-_1vCg{-{zoZlLRc>;w+-cw*b2 5ObE,w4 {{o]V* {պ6-/Op1E D^|1"Ur` cV]*;H^X"%wh> 3j4RLBM fDWq͡gQڞQ;W#'Kو/Zeo0v|)%ȖpEyȉloMvKwn(`9MiHH K@\tk "c /:VA0$(BgO.1a'PE~kBBBB:8ROC竳/us).q (a"aV;3P񼶷ljBB9.FxTa<Ɍ\FQw{-1a uxr˰] ֬'3r 8 v,wYB*V"p_K1^9\28§?â~IEلQKDSeo-#-,~kѯd%$$l ػ^/.TsMLGߋx@7K?"hDLzn.㑍`~r~"$!.*WJ/jc{PX87FH Fd*Z e\:j.s\ #$8UÑ@ r[W]-t.Zܓ3~뢫eI=]Ar$$%Y)ZeֽwſK1mX7pIDAT^;˷gy1ΘSf\PTP5xd2uV `Q{6F%]]*$$'#{: NNcF-ЫA;_!Js=ǪWIDH$j"j [Gp;d2Չy ,btXTqXЫta= xg*K$!H<Z,26սo0 B.Mt uZa`{cl;cj)E!uT+  V.ҭ(WE!*e%=b?:Q <̄Άb;Aa;pWsVC@= ]i[{NktfEjncZAڭK̀kuoGv~2L:ʾ/;x|0Ewk<>ݣh5KT z $IK.6dݶMaA8kښT.*`ko-ln *rYnJdMNX`Щ R<a- ܛJ_il'`7ҎZh١J# UX/s]cCpo⧹ ZZ"]p(zB jM n0GI\-Vtg~p$!!!!!tD[7c27,qVke[GZ֢[kr$!Kmy@snYԕ7S@={ߊ,c2`.#+z3?/C 'L !$\ nǘI)܈Ydrd@ɝP 4^6s̓oYaA1eAɽѱ_@Wm_,wz8b]\L<9)$|Z ZEydםQ?b~kLu!".h˨Nj"Y o]V;Z]<0XT7F(t=35%~3p(pf%䌇E 32.H-}@ˀkUy C\lEZqY[LOIoWۥ*ҭJ PJ|a˰tHͫ e8e[Q!YB)_L:_|o 6%,s\`l-Au bj wh\SRA2 O>npv}Κ:\-˟AqZ aNnZsZsZW]-3"}ޒ.#Lġr\-MЭKur' ni%i]uoe )-ihu!Mb7ʇ;_vYY6yB;}*poE̽& tY̚;FEc>~YW''ߊ3#{MЛBVcȯsֽh1&RlNtxj kБ5O4(zgY>&B "5Y-|F Λuw&<xOz/2s/!J~+Tk"ZG~ G"0W1&RlϣI>wƮAxӝp>z>}&]0߅~ )h%0HZN_F]O0߅&!DŽ@AzItKBBBB> WKx*OFyM%s,^>i{`8K݊sU6kP2 /҂oR2=+P=ts.1'Oج^[G-%sI-޾K[jȫ"$X.3?Yeo K EZ<+rc2zGd~U?m׀&Mߚ.,~ka?3dBiF'1-'lnlH?uH}K@_?[Z'K 7f Ü'@lU9dF+%=xeiqX6,.s LALE/S.KM}? 6g,X?>T2& =ANm(*Vt@AʈHHHB¹[i`;4C(#GDElgEsc/qo5[ICbPPNݕ/0jμ7'3/<9wqpnL%S]f+k|8V!i$F-יdPq{re}4T?6nE''$0#z(>xؿ+پ f[@U{XtG:u: ? l]֘ȜZTӐtJ: n>o9%e$H:u: 6 섢2 K`Su޳0d1b~R-%*@);/.;mg2$)ƗA^ bkp@-%2? .;ˎqQd^0Re$eNFKh Spr -sb 3 w4#<p]^|Cf_Qi9%)%.Oc`Х~qK]`FwSS&KoMF5!A_5cp%oMj [>ˉ X}..2^w[bUC^;Ajl4ԘXWc:N&:,dAK\iINn؂-k`Lϥ=޺] -NP^?Ejl4ԘX_b:`4D>>W2X I^s`Ѕɍ18ӅC/$/(BX ɋ%$բr;YuwICбrf+iG2]K, JV<<:@n 3[ ^ve,,tbTݞ$F ހJK\ve,LAN 'gtwԍ2vfN {,qքN~k[X&$$$|$/,$/'hL>~ࠋj;I^$yk-}+xwű̱EQ^!DICPgC<&HɆ؍EAu(b`YIy>jш23Eyd.s Jj !QĺcZ(!Lb7^(ߡ J)._k s8Hļ \ۄd/ߙepn/^˱ڝ w3e Kꍗ 뉾]۸Tqf yS (/Y*L5,|yk/6<Kޙr|T/ `WKo,%Aߺ30:~I5`K 7Jtv \|IhJԭTkb igdQeIENDB`perfbook_html/img176.png0000644000175000017500000002610111672746103015312 0ustar paulmckpaulmckPNG  IHDR)!tRNSىH IDATxly?<8s.`>@4?SlIT(@1]tԿNՑNx=0 䶁5M-np6ceMEzʷ4;;K-$<;̻ϼ>o64<,γ;NPtVZC!C&L20lDYM4D w!KA # B~{9U`-a?UXL ڔa$7>-B&_ (GI@-z߰ho ,K-/3 3Բ5?GYČRMwDAA亟`OK'b 0#€ xk"bK/YYQ`g?nlxvH6i!U*p$>>0 -rNe>O=ΠYO'/Z@c0?J^|faLj d@ͯ[l2MJ hT&[Ln<6 ? s4u/fO[vbD6?E,1LوI qmт)#1i7gwk]֢XFR速/iD~_0 #:Q=pJd33\SR;A=D"oG}.VjeL=BWZ`Z`Zo4b=쪹Ǧl-uK&#JHEKc,/X*jɢΫ+xȂ|{;1%RG!Ӯ]oҸHs읷zp5- "@ %p;tkӷb' K_5}MC !cam< 6mC/ ׁ 0=TiCS+¥D9XX0H`w`oη 8i~bo55g*&Hk(N򚷗*hs¥futf/~+T`64ϒg#Ҧ@oZjeo7331T_d41+ڒdvvkpֆ,}1B$I#jYvp-g%1j@IF/Qf yt%US&/IbǢ>Ygi8QL ?nRf g"/ 2cZ$F{{P#K*V?-Y2$5I,Ib,eWAXN@M'9 <(ܲ4mp $[4Cr w4룚%Ɍ0͉Z -^-i@BE +%言lCK a %pq \ R])}vT)x 8Ҙ=ע 5MlBM3K,89u X0t•+̹s .C֫[钌λf^ LinpQ$` &%%i @דKBZ&׊\m!aԚ>ӵu$8g;-QF|[K:r9{Ն>` T[504%]F/;Ah$0-o }[Dh^KXRS$>eR$ @d>.^?ϲd4q(4J >kLFf)O8AV&pibɤUB4SMr[c[g~i拚.il _駖xzZ6j(L_Pڪv}q7?])wtZ֙Yڳ`4ؖcssZ֭~4=wr3|uRo0xnE eFu,7ﭓLd BBK|b%aCnCI-jE@=(>=RLH_X{K^8Km(K7 s!! lۯY,E._-sf#Y$?ɑKrl"Lq}{ A D̷(=^?,AvLwFʌgvM~ktP Ku2nZ&V?PŪ'3Te?#80Qbe3tIV6zf4yF=VvkdCcC@eP tǎkE67n-L/"^PC>\r9Pw=ơZ~1gv,켘 %SNǵf| Ux46-Xa}=,PONi+ju\ƵZYeaw? T/lY˰5.z2OnY}A t%e1K/RĻa(BnoX m{_Pcٍѭ$Z+O,yhgLO}n]r[dVj Bә}?\ pT9Zf:&j @FONVL') 9tO e=tCJ;vpONN\)5%Ϗ*Po (TjG@ZĜ̉1`<ѽ 4j>QoXcJebs^t]APp.{u`oM5 vYV qνW;֯*{pN@U?7 jKQp2 *OY|9/AJF,YXʿl|o&_zekCBW͛ 7w~Q~'~~s6ķ]Q])U)rWƬ`UU)`'XUq8:-F̦qw#NpU$QUP%*Tj}c*̏U*Z]1j~3?VTEXqT*;UEZQ״F.V5m*$ba8ohx櫚gūT`zM1m,c9{O0\ڴ0ǜI\@wn7-8{yug VVyW.is˧MZ>eQ*\SsՕ*_Q{mmunl`aǖh} F5& M(m<,Agu!_\#I$Ekfm_||ϥ&gځ)MBj 7"=1ǩsЙxDճr8Lez2\o_%J/- oL7}SثN}8tFKA ?.Nt;M@=q!8scmS!xXxI'R:چ`E'<Hy#]&wE<MKV2eUe9{ړAʟϒ}'?>̋O嶟=֧bixȩyLq߬ `gr&reC뤨F^JI0)V*s<)ݒBCE4)vlBCEt*)r¼Eɨ)Dxy̘F9T47F/ n^x7A`=孥k-dϰ&?W}$ee xZ;%6&8Is5a|>@JӦn2e7deRhJ~X]\bbme!;Rɽύ PiMy;qu׶ @ٙ9TMqW32`n~> 2r Dњ{HC/f䶴ȌM PͦS=|!R"ۓr*eJ9)%lZ!C)ip@SR7ΪRakSFU&U3C"'lt$JiQU*+E"tlY\Q9}H:69I[ۿ3W-"jRWDQɏ@)6UkwMu<nj>jS[)FzM/Y!@Wqp7VE3P02=P*斬 2^`8Z6P+k+AU?#*s|Ti,Fթ P;E/ݒ|Ƅ\JA21xxv_ߑ;'X)D<*|N&gY"tMZ9rfB{yޚe6kufֳmk{·N/@{n{jqEx?-GQn*#KU'oH+d޼/ko[ٗfgVۼ_^dm%6U1RΡrݳrӷzkEO Nʲ͗+LݷHCR]@3[UZT*"9圾ۼYkOy)ml3 0 0~0 nQmBxj 1uɽUXg](o{dM<Ӱ䊊lT$i*Zvj]ZPS;G;.yh+M7" >5w8[+ n;&4u ,hxMb-*\M@60} tl1^[@dwCHK#߹aù64O̓G2JNU(]8JC2_+p#7ldبIE7Z$n1x& -]!b\K)p$-TmB= lX8VV*ZQitPF4}J+vj]21V*709S [w`G(vyކkѦ7m~@]{;4LLq=4WUi.$-yih`NTyau PQT6Kƃ o9Xlm9[ YR1e&QnlbnvJAT(DU1+փU)Wˮs6+xO69}=TOe}KPPޔ8n7lʘ!p 6an>)F*)% cly|7 6Ϭ7#:򜀔J$St.Bv ɒ?@_n5)\r*KeWT6l~a;O'TOBNk^A^#MNI:r/w4(ܼe+O2n`rOwz]So#ֆү4%6Kep=y?0L'FMN)S]]\(ylO}l,o(9Ц~ 0Yg99:[ wΛa%zmqr;Ce^6 (9(Qnz2oLBN+⺻m N;Fՙ3w&')ozz3dlFryYh }_-J?Of>) IDATWVϩW_O“﷤?dZS~WݟWw ,D&ɲ|<f5ticMcRu=mS>KQqtە. ãwv $yL 9IsprWK/x_ן_Q/½_=^x\C! b4mQōGȲ,mt~Ї.p@>sb!a_ޟvrvYm^\;9;wk'gg v73,p71{t@Mc!fϷ!HNe=#M@yu2OMp8#C#nZ#vV:oCDmo㝁l{^@|PjcnE[ ۚ2qzbbbػa(?? ZJ굏2[@20zǩ0mGC SWw7OPZk[.w۷/Kճ%3wLpZ!wW–۫8L%3!Kj_}-Lx޽8y['w&Wq ]]dG;E(a'ei#OZxN;`{^'CSK@QsbjO3%rz8xk%uZ""H:s=)6)hZiu<@>yX+mN6@Vqt=(q{D|49*V݌;qfYNQYNu:=i1LG^jS wIԔ,ڃ4\-,-)4_]9 I'US[+ Ñ+طpAJ>ҕ'-G$Ǯ`? Kݒu|5'ƝƆy{KkٻFW7uiAmˏ1ﵛ2P|7n=O)>枷닗>\| kg`c{L`ۭr<}]$Y9"iJp3]8^Q4MƇˁ,ke4k_h7k)[mJQke4Kw'k,VfCVVȢ@*"W:4NZɲF q,ڮX`MҺd9Lp)]n8C8ҔgVq#M6>.84HGwCrOHSUGH*#Mzh4q)]CIu!HSzU5r/HS7">}!cm2{-kJezŹď%eJKe,[9]F{9oLJ᲎~I)2/j=}+T 'GY4gL#j}빾 SRDHSklM$ @ESr,\@h*rY%Qr^QrMAi-M41;Ծ8:^15E˯#=jHW(@Ac\ymM%W"'4.YB(kShsĪSE"D@ߒVO2?Փ̲V*IJ{?0/fYO[=*3?YӑuHeIA+%BzEl)VR`&&^@ γ6y['D1TL+xn4«8|<4Fbk3yR\&&9 J0$lц IU%MRL=) 撛ubv7Ru QMRȎH!CwP U G1i P?cR(qgWMڛ/MN>nPW$ih#a%޴f>cݜ cAO ôv]%C@Ijܰق#Č|Ηoa+ʖO)nD[ a=I1N;$Ͼtk3ZnݺV RNWȺ9ôTO&]RG! |u */0g$TTUr՛rm$h )vV?_/{re+`kՈ~Hc=o~);6`_ftK..)AH〤GE@A1GcVbeAD9qZW)Zj5|lVq|VdcE*DD7H$8)vV'Ɏqr;QXτd3S [ &]E\ JKxG;27?ILKY;):I-{W8dH]?.UD|b^#9IENDB`perfbook_html/node177.html0000644000175000017500000000431511672746162015654 0ustar paulmckpaulmck 12.5 Profiling


12.5 Profiling



Paul E. McKenney 2011-12-16
perfbook_html/img220.png0000644000175000017500000000615211672746133015307 0ustar paulmckpaulmckPNG  IHDRb)?PLTEb``TRRMJK# hffywwmkkXUV856C@@wuv.*+|zzrppbatRNS@f IDATx\b*)=@fujANw}scRI7RTMK ҕ JY)˭;䫖捵UnL/ BP:-QY_닾BF|/PG5o`>~;j=WM@.'Cxӡz/_]h%MYLn<6eoDlک =e>^ 'OJڥ0ʰ\O<8SVzztǕ`-95{Г}x%Z/e Ea#{y|V!oМ0yD,%*3& zjkM>k=n)2KĐ͸ZnHp௾t,~`EV |W5v'}C?]u\MX|GFҫ\Fgۃ3ZKTZFS,erAߨ\peAuܦ)-wX_{mV^,ǽ镽w]/ϓ#M_Nz,Yb:Qe&auMN(ҥv'EeCMxJCP5>WߴLS?P%zFUo\c$pٱR-6ވ4CeT2fkb+0,aLi.)۟o*:<37gL78" cIܱ wA/PmS@zJD_z4d &`L4XXU9ь(%s3|4Ah@L:MVeb;F%疰apQ EX&:Α Yu_IxQõBP,S1"~]mdP7jo"m{cvuڔR”(iSJE A:Z*3d?)fי㾸6`Y4Uל}5ڢ OfWSs?pN)~zAKè0ױfAM${O?XQԀc ƃ)>뇞Gƌ,,TJ:xl" sC' .P楌.:VE@}L*d.d%K X;7\y&lSylTi/r%/u A3U68-oaFvm/[B!u0ׅbYEEa7En#?uo4Z)݂WuYh;CP;:HͲ|&E뛰> &F[В&YвXb1݈aH!73RJ-;F[ g:~8eiqjekFUm1!ءwҗHJl%p1E?$"叁TLYNVK/iw_<{w>ἳU[n@~)ϧK.F>Ni4S¼مK)1sƸٞG g=>ġ n0EY,_uiԆd󒷕 ˑKq&s;np=|}Vf&Q{o=ʣ 9]6N] P 2PMq=uF{< T<㕄?k\{W@JD鬒ri9061t-}Cosq&c[K]j)1 n^6[v)pDy8$:RH{s-,/4D0pm^Q:ak ح`j9ہcHhJ #VA/,i1h 8[ xQ-7Ϋ۴mIo &N};u Bf3/0]xyW=tup{]s?S`3k'S f)9_soEE=Nr?=yq*7 Wg@WЅ/)kg^:%vώ;wW߭#ڣZq!p$92;,Nd|p8XPqDTfpkJsJO10֕Mr5"Gi`ac?{CMpLRUt STc~㇈qlRY)>ۑ灔E(y~U '1)wt?-;'q{Uk!To6($zɖ 8D1b71WBKT#U{?*f;˳w+R;o‚뛆q7>ֈ]7KЁQ(9j1Yeu゠1Czpt NC~cĮwh< M+iK$VUQ> @N[!esMom$[?=AcX{.fjF?,{iYvmOx]T9IENDB`perfbook_html/node424.html0000644000175000017500000001164311672746163015652 0ustar paulmckpaulmck E.1 What are Promela and Spin?


E.1 What are Promela and Spin?

Promela is a language designed to help verify protocols, but which can also be used to verify small parallel algorithms. You recode your algorithm and correctness constraints in the C-like language Promela, and then use Spin to translate it into a C program that you can compile and run. The resulting program conducts a full state-space search of your algorithm, either verifying or finding counter-examples for assertions that you can include in your Promela program.

This full-state search can extremely powerful, but can also be a two-edged sword. If your algorithm is too complex or your Promela implementation is careless, there might be more states than fit in memory. Furthermore, even given sufficient memory, the state-space search might well run for longer than the expected lifetime of the universe. Therefore, use this tool for compact but complex parallel algorithms. Attempts to naively apply it to even moderate-scale algorithms (let alone the full Linux kernel) will end badly.

Promela and Spin may be downloaded from http://spinroot.com/spin/whatispin.html.

The above site also gives links to Gerard Holzmann's excellent book [Hol03] on Promela and Spin, as well as searchable online references starting at: http://www.spinroot.com/spin/Man/index.html.

The remainder of this article describes how to use Promela to debug parallel algorithms, starting with simple examples and progressing to more complex uses.

Paul E. McKenney 2011-12-16
perfbook_html/node117.html0000644000175000017500000001044311672746162015645 0ustar paulmckpaulmck 10.2.1 Implementation of Reference-Counting Categories


10.2.1 Implementation of Reference-Counting Categories

Simple counting protected by locking (``-'') is described in Section [*], atomic counting with no memory barriers (``A'') is described in Section [*] atomic counting with acquisition memory barrier (``AM'') is described in Section [*], and atomic counting with check and release memory barrier (``CAM'') is described in Section [*].



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node116.html0000644000175000017500000002500311672746162015642 0ustar paulmckpaulmck 10.2 Reference Counting


10.2 Reference Counting

Reference counting tracks the number of references to a given object in order to prevent that object from being prematurely freed. Although this is a conceptually simple technique, many devils hide in the details. After all, if the object was not subject to being prematurely freed, there would be no need for the reference counter. But if the object is subject to being prematurely freed, what prevents that object from being freed during the reference-acquisition process itself?

There are a number of possible answers to this question, including:

  1. A lock residing outside of the object must be held while manipulating the reference count. Note that there are a wide variety of types of locks, however, pretty much any type will suffice.
  2. The object is created with a non-zero reference count, and new references may be acquired only when the current value of the reference counter is non-zero. Once acquired, a reference may be handed off to some other entity.
  3. An existence guarantee is provided for the object, so that it cannot be freed during any time interval when some entity might be attempting to acquire a reference. Existence guarantees are often provided by automatic garbage collectors, and, as will be seen in Section [*], they can also be provided by RCU.
  4. A type-safety guarantee is provided for the object, and there is in addition some identity check that can be performed once the reference is acquired. Type-safety guarantees can be provided by special-purpose memory allocators, and can also be provided by the SLAB_DESTROY_BY_RCU feature within the Linux kernel, again, as will be seen in Section [*].

Of course, any mechanism that provides existence guarantees by definition also provides type-safety guarantees. This section will therefore group the last two answers together under the rubric of RCU, leaving us with three general categories of reference-acquisition protection, namely, locking, reference counting, and RCU.

Quick Quiz 10.1: Why not implement reference-acquisition using a simple compare-and-swap operation that only acquires a reference if the reference counter is non-zero? End Quick Quiz


Table: Reference Counting and Synchronization Mechanisms
  Release Synchronization
Acquisition   Reference  
Synchronization Locking Counting RCU
Locking - CAM CA
Reference A AM A
Counting      
RCU CA MCA CA


Given that the key reference-counting issue is synchronization between acquisition of a reference and freeing of the object, we have nine possible combinations of mechanisms, as shown in Table [*]. This table divides reference-counting mechanisms into the following broad categories:

  1. Simple counting with neither atomic operations, memory barriers, nor alignment constraints (``-'').
  2. Atomic counting without memory barriers (``A'').
  3. Atomic counting, with memory barriers required only on release (``AM'').
  4. Atomic counting with a check combined with the atomic acquisition operation, and with memory barriers required only on release (``CAM'').
  5. Atomic counting with a check combined with the atomic acquisition operation (``CA'').
  6. Atomic counting with a check combined with the atomic acquisition operation, and with memory barriers also required on acquisition (``MCA'').
However, because all Linux-kernel atomic operations that return a value are defined to contain memory barriers, all release operations contain memory barriers, and all checked acquisition operations also contain memory barriers. Therefore, cases ``CA'' and ``MCA'' are equivalent to ``CAM'', so that there are sections below for only the first four cases: ``-'', ``A'', ``AM'', and ``CAM''. The Linux primitives that support reference counting are presented in Section [*]. Later sections cite optimizations that can improve performance if reference acquisition and release is very frequent, and the reference count need be checked for zero only very rarely.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img181.png0000644000175000017500000001633211672745762015325 0ustar paulmckpaulmckPNG  IHDR,GPLTEө{{{wwwuuugggcccQQQMMMCCCAAA333111'''!!! z|zvvvtttrrrpppfffdddbbbZZZDDDBBB@@@444222û.tRNS@fIDATx]zrVȄhvmo"N،g#}"x+CHB34EQ}Iq#RI2 hDFjC&Mwt7QȤq3ߥ/ ɠ\x-ɤgz 8+טLF7E0B↦a4+/= iȍ5@qZ+߯'H97zD2J[noPi[2՚ PNۑP%["4%Jnw-SíO3SB ԋd헦9240Xi)TSp");*:NN_B36ˆt=Juze}E~ I5*s7Zb jb(Q)V8kNB{kFDtN}"$Ғ$Dvo*Q޳5 5_ qS'ZF@wAKku]Ȳˣ/^ Z=R]=˷̼iU%wjEq {YVxN.*'qH" HsX}PRW{lM- Uk͒šL}madGwD?e6'po*l4Zn9/٪Ps;qro=V#F1:lj0YmU3KD7:)w$Q$gUg8?$agHȳ(w1xY'/)?N"/i,%Z}y۾yaW>k\-c/^ּ2^6=ʅT2䤢̋.8lL2(/"rwdM_0/p뫗uԻ3 -0!o˅$sش<%2LX|&cTAh^IH G^Ԙb+f:E$!,CyULcFxW-UQ&Ҧgf(-yxX^6A؉\䬼пʵ:'.Fԅ``^4] u E Tr []1/9w|Gc!x ՌI3.i\X(rlUOH ך"ebY|vިȏXI'Ÿ+|8}y֏SeMv_ &s՚"st$ #zl7N ^ߥJ2c#}'piDX*5V; 2>?Q'DW,A?('TeO6aD<& Zu/ B Y|nt 8?g @P{İR'"%':vcb! n=Tmg/cN wۢW|})ڿÄ#2^IgmOxâ5X,xeM'()] gs`u ](F3a/jU#{:XxYgZ4fSqrv_Xr=D VM`C0! # ~0XDd]JfnUwxPF *ʵ:7mߠ%2ZAZGgXE""Њ02w "PلY͘4BP7uFO( z"YD<²?Ym|BF=H|l'FБbbH{#˽h«.RP,՚2s@kbԔ\,%7m'2BD$ZH=1RSn#"+}4c4&6}S&#;i ˈr:],@%L3MrMfSy2m4bp#AĈ2ߛAdO="& qB13jYb͇W,! ՟@AZ,y"5b "0UP;bDlDegjOGt|򉾀{G:Dz^g oU [@2-!K of  j> <M7а!!pI%.K'Ie`$# gy em'W'W׋T =<DŽPݎW֝XTĕXk^*j2cJ%Sef3|bWFߨt2 5>X]P˺aW\ؓxW62ma|lw}y) 9b }oQ ;j66½,Hq"QI0r#p=kfrmjW@[p+w$7ʞIJ`+{ IYJ,eG)Aߓ#Q'EaF(y eܮE G~%K<["XЏ wua;mi+ۋ39z`6՛"ʂ7A0O6hfiWZ{ghbi@/-loJ=+Dh *IBADEbYNz;jen0 3mjEj~tx(4OZ0<^aeX. "FXD wTg #2BzX;2>T+y㊇O}bWwQd 腲8a ;(zo-tKTi#KIT+7- oU,eٰKUbubWtR)KMmWnCd\b6GTgI8#DJ0>T+ W.m;mz4_ߦo!?͹un+6zV?&ˋQؕ|+M8zQoIN!buBĉʼnŞՊE)[!R+g%!~@y~ˬ$!_8Jp΄|_1ZɊ20ag4 rTz,n'R#h"'eSXQU r]$NY[*C^,:(.K n{ttYv,GB;'/s"bXנۇGĕY;[ [̜ D@ϒ7IY]F:b L `wQ,G/gFbtB>7CٟA<З~0)ҹ#;jQeGBEoݡ-?:\nU$/'Ȁ%mb, lhjOC' E7Jzܪ~Df(fZ"9 `|cBt=p^+.xX,Fe=,⚝>;t,ow?{%;eݿwzw/.9#/NY.Y;kR~tArAnWɮ eNId,n^p┥G8eqSk^6x!єeЖ^b@ߋW/v1LY8q2, |m}YH> AwHqO r<-J_-Md6>mQItyp;NY.syδ_h9|K%#n9ext B:!8{uh92e)8;exPei ,ؘxSC>Q218ex}: ` `5$ȉSNYa|E)9ç2sʲL*/͐)f!ѯގXDĭzU]Q'&}19v`X[jߚn7'a{a6˸C2KL0oh.+K]2ŲeH&f_iTv ^7D$+H)#̊(K7aR7VD?bPUTܐ{%j¨F eP0tTbYi ՖޘH65J^$~r/7iCng9C7InB?ɺK9{qrD4`dWgY7дڦpxԑ|̔GxyYsH##s+ F|Cgy ŗuXrDUTzVe( 6!,IHeڍjD#r> r%Pнף/,8+4|<hE"fKQFqؠ," ϲo"sN~( ~P ^T(j9UП+ȨFCYrsaLBְGO2=qѝ+HiX1.7z,|D*3~6o%RtBlOr̰" 2Й* Qt7}":ti;c+5+5:t~Lj$8/IV)CNdEY[%ʂ냨DSWwc)LVwQP*}1A )coRu؟%@3ێ%ÆSgt})cnY9,u LY;exU8В!FCUxIY8ex(৭M`ɮf i+]6[Ux ֭&uNY.ksQSFqr` SZ},}4SG|yܴ 'NYΎe7ǿǯ3;%Ļ0.L)yӍKxŃ/TU Ӄ_4|aU~B2 K|)%_q9$[< 1坒-S)LY_eʔuaq)ZF_Ǘ_?&?~?A_RW)u>B:e<NY0*nQA/'SEmU>H"#䯕mdTV9i,QA1 K pLRx Ib3\ R^eI~"o 6 cA @H89p̰-"5e.| #A8DTE LQ3Fؗm\YN⣞vR:V"GN"(G"iM!yeUV|3!d+ÙU &QA:W:NNR <\`PA !uȠQēWx`%,+ÃP <z$ áQTP{V~Z+DV/;OF,YDڐqBxb,CeKC}($I3Q"|\$ bB2DPW{UAQAlC. RmP\A|BVPW؃QK8cDt8#eW9xŊ! E9ļENYA X5qÉ рNIENDB`perfbook_html/node456.html0000644000175000017500000001231211672746163015651 0ustar paulmckpaulmck E.8.4 Interrupts From Dynticks-Idle Mode


E.8.4 Interrupts From Dynticks-Idle Mode

Figure: Interrupts From Dynticks-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_irq_enter(void)
2 {
...
...cu_bh_data).nxtlist)
25 set_need_resched();
26 }\end{verbatim}
}\end{figure}

Figure [*] shows rcu_irq_enter() and rcu_irq_exit(), which inform RCU of entry to and exit from, respectively, irq context. Line 6 of rcu_irq_enter() increments dynticks_nesting, and if this variable was already non-zero, line 7 silently returns. Otherwise, line 8 increments dynticks, which will then have an odd value, consistent with the fact that this CPU can now execute RCU read-side critical sections. Line 10 therefore executes a memory barrier to ensure that the increment of dynticks is seen before any RCU read-side critical sections that the subsequent irq handler might execute.

Line 18 of rcu_irq_exit decrements dynticks_nesting, and if the result is non-zero, line 19 silently returns. Otherwise, line 20 executes a memory barrier to ensure that the increment of dynticks on line 21 is seen after any RCU read-side critical sections that the prior irq handler might have executed. Line 22 verifies that dynticks is now even, consistent with the fact that no RCU read-side critical sections may appear in dynticks-idle mode. Lines 23-25 check to see if the prior irq handlers enqueued any RCU callbacks, forcing this CPU out of dynticks-idle mode via an reschedule IPI if so.

Paul E. McKenney 2011-12-16
perfbook_html/img21.png0000644000175000017500000000622711672746146015235 0ustar paulmckpaulmckPNG  IHDRW)9-PLTEgggMMM'''tttZZZ@@@444CtRNS@f IDATx]M~՚dς"O `_l`c?N>bv.m!ɡM% :r` 쟰"U%U>*uUzZzgKUJ=:jB{ ( 3@lm程O0 ElT;l;WO,&-P?mP +)Bg 7tNl}-JitZHt@ؾC7{μm`}]_ Zt\.5Zŋ#"ˆו(k'wn@4G8 :,:z 'x/j 9 bBBHhx@x ᳿Z8]kp$ w_н Oa!n2Pv uB(qTʧij5tDgC|p9Ǧ2.qi9.ڭGg>I3[RY}A\>zݳ[,1ޙM4~(Kiw`?pyZ&.|R+3hp"{kCBpe.|i<ߥ-N1SokZ;/!n^ z?穿pt nT4B r..E-6;mۃ3@܏YA 0)L4Dt6dԐ>՜ԻQG!<[,*Nnn̊2:l`PAXí~T\$ߘlky㋞uwLn#:o3lku_#|2ì}wwb#sC龵t'Zs+KedYZKv&d}i1Q$4Y1>1~~Z:݌_j>DedetqȄ9MkRXۢ⇧/-k%(L!U*wƱOh6T`mhM4m*2tji{M\Yyl.G`g^3!5YKR:646i &UP]:ZaOh.y6Q?>GG!Al4,j@ ր}Pe_ITa(+S dNU7C+y ҧ-W|,,8߶*6L2\M U6&E}M4-QQJ484ULq,_ !tUKb͍e$J9(>_Se.G;7_n:Nb1$ŗ='LKբ$6laz_6JYV~߹p7IN9`MP _D. ߣw)T N?yǡPVX˗b70",e%\v>E ̧!v609 lݣm40̇ux?'X50Lt.[6V$'rdUMo'/[8(PSZljrJlO3@½>-5 iz0;pUf!rA%xUݲgmd] ܲKbs%RfUr4}fwEvd5Ʃ5!9.5ڈƩKԈ^ȻjV+*YdDÈ경e+\$k%Oӟ7!%X; Zomo=cR׵-:Nq:(Zlۍ +U*tM9"CjxGsl1GwBG+`|] dbvv&e0G rSi]5T+0T#L1ַ\x˫ff%3\N섳H=x6xt*z@ܨ<+*K5> ))QQMDէ:"o֝XMy5L+چ9ʭ`XRU4K҇X3ҕ!3UgX[H+Cpτ[WjOɊjKz&TryA ZVf+''ߧ50чn+- Q{p8 aEFTt"1kb}|N)plf%Ȼo!"%cJP*IV’,/S}؄v7~!2=أf^c1b}Ce8,w?n? Bi31r2 =nf^gDQ>bIb1j~c꺲OT.YUmVnxDL"v*]vG uI~z Jv]Xv]7J=>-At. =`f%>qџ@꺴˯a׬:(%Ӕ5F^ feM YI 93Hؕ1;|r}1dj좺'lg|Ǧs'@UT Wƹ,4;5V0H {Er[U1EXvBUIޛH;;NF2#T?<0<l]![XpQm:٢]{'Ž-Y+ˑ,"VfAevb檱puYYSX5YCMr,2kYx3X* hiDM5kDr| ^2f!0k];h6j׀L2 &k+bK,8k@@f VVԔ,lg (5 W̒Yapր<svf c5+D5 բaD׈(h]dy),@feVfMaeVISX*˕7X* hiDM5kD4;`si D\3 ?u .?:~~wы=xD#r})>c7KJv˧! Ȋ4}a;>bcI]ׯ7ohxw6wl`~3t|_&G;C% W1˸Y1޻݌x8hs5"jJ׈(,@ըg/ߌIENDB`perfbook_html/img285.png0000644000175000017500000001242111672746062015317 0ustar paulmckpaulmckPNG  IHDR?2]6PLTEb``MJK# hffmkkXUV856KHHC@@wuv.*+M'tRNS@fIDATx]bEġ'6P\Lk#Ez ZC^ɩy'(eijL)S Ϟ]>kyqR}JsC킊ZZ5&U|9\gҕ1 EUcTciR>=f\f;!ILL7'QU+0H#:tIıQdi†UЭҶUP}P>OFeoB 2q#'FuF 4Gjy^[>g^H:FMcIppnEH"t5v`+am1iIݣ A7ul!=}ܯxqGC 2etdXfֳ{Q0{cR9H Of8*#1 *>!`:. {9We?6pj&?0H퉛|M_u"ցdC_VoC=g#{"k?bRSiqB>\k9665O9<Ni?0:ڴ`i3e¥F5PMz^Ctfy@_q1WS,wcnkps2K6ԇK?}<ځr F]t|?rLrحoٓya!;yfɆ֛|x(GIT4cӵ[RV^c94=#{c3FV]JũZM|;+^ŸUkZc豆;A1kU-0Z|.(h]6tSQke.Wf\τe熺 Fmf@v~7~]! 9&A Nð2c@R{Z^Ț$ƫeHTw2r ]/:yS/{=WLoƃ:IN,= I3\ĕ4 9Sw,q;4q)Z/|IŌ]v[t8ˑif)O7NK<}J%]Z%yˣ*'Md#OQzZ%21qq\TtdOL$hL3sRA+BEDɴ*2[ W+ZKW:4 jjVG]Zcp7mr1h2!QmlW#eQ" 6nOeU1N`+2R@67J_ [J*Wˁ\1Q]?Ԑ,fdr0;ka=bVd B?@dF*D$&؞.إ$Ζzo>N]1=\=ナsāD~̻jH}"?uO~mlB: .PzdpD~n1bDUM#aEBQD{ B=E-%VVxI$_ALy`vK5W: XPMUd{#<17e9ݟ SMzgyxoWnRY2Tؗ4R_^~%XpqV]D5?(.8Nji| NP- FNcѮ ey3q]!%&dq:eb!ݔ piE*2(d^PVJ V O;΄g]ixITi5f5ts_*6 xYTh;WQmx CO`7AtY )PUV9V#h/ym ylskW<ӌ%龪=È"召v9(s @1@rv)R|~zwgq.=ڍ]|b)Rh.u'~߸BŬe* ]H?Qw5 )[>2ڋ:dKJ+ kQ}gV瘅A~4m/:7_\ Lx,5NaGmOdgŕDid5\y&Ip$:h G"s|¦2Qځi#ZR d?Z"X%oiEc̮1[zU~e}X>Fܒ&eBdaD[Dy@Z dـC׊yYe_*Ǭĕ2)v]󞛱=(n,W"a'c.99_jME9<(_Cթ$$&5eh Ck#*q>!‚ dI[kY &15KbʨORYa58`I.o>"x;rʸF cJ=@8D^+V ,~~vaQ$`e"gږ\7E~Q%Moi:*:cC75I$O4WYW.[O!tJа4RpAs4$53FI=fQ98a kBώ c8tOL y@=>:Ry_ )[p6UNr'r|WD%{wC,~}n)۲~IߒDYA!:Gh"(ImK,Ve}&"lu~}۲~`K֟#ؖ>S̄e6#fm5o_dn4sxg! ~J: 0P]]]x:෣P Mr.$ U#.T~ko^3޿=Oi;1˟$x 1BR j Tֿ_8eҖHf_ N[58;-i;\ }/(ajM 9,6{Ѩ놗3A}y[%-*ߋ6d&l':.%p0$M!`&ePqktkөAN#5emD Tܑ[52ȹ^Sg,RxS&^rV,?MÚ~V:^kŸMme42)<Zq8#_`dD?'\TuK0:=ᕃgD<?4 d6mHcR k[3\hiII3ؠVvM$/)|B'A.te7p#cqNWOٲǨBKV1cMQ~[=-Ӏ(#̥mNAppZ8A߲ $[+^icUGgEW#h ya͔ҡE~Sg_%@a[FGJT|Su)K@EH8g {~VɍO']J:F\T209winw7n3n;? Í.s6d=Zk=ż8@h"H%hv@ǟꮮ&x[ u޸:.p{F6ܳ7Vq-%1^mY4}{kȠNr5ZĠZIymڮkMvޞ׽O`ZEonP|h E)/eIهW[\8r1I `g)D=,?W%-LB-TގJN|bVCQ<ʸ[Iض*xL7\ !Xv/v^[ Sl{0"P /*`.|u>ֺde}K R]w;A@}Ȯ {čxq7{'Ȝv%qHT.j&5΋LxT>'"5oе'oJXNER@))O9LeV5:!dPh~ LxX~MyYNBQ SQR^5 ]$H)eɟˏSOLvg89OQ7}riB6s¿O7S>=|}h D)ӘDЭxv3?m0E B>YTzt 0+7]۸lh̖tjg+J[jj}uPK/huloAZ-9U}CL<.XTW(^ߍ&G?CZ ʧxޛ%^"[P6p&:r2T~XhYZ%5DF#|Hb 佯z|rN'@4y+99'"?ƍGtNCZ*Q*7&zs!-͎ˏzDoN:H;'EXgPl(n3 ljYMǐ @jBzYWdQs_>}J!< hYk" kvrqYg1;4Ux:X[rpm_Ip(@fz]I@c=_ʏU* uR~ca nC~Te#V'E}c-}cӋh\Fh#Z_qoyo:W"s/OS!$o82L=i@rWO'wkl0/9P?LB_Z7/ne8r0oi'OYʸg_DD8+9Bב}up2F̲ՔԇIENDB`perfbook_html/node345.html0000644000175000017500000001443111672746163015652 0ustar paulmckpaulmck D.2.3 RCU Desiderata


D.2.3 RCU Desiderata

The list of real-time RCU desiderata [MS05] is a very good start:

  1. Deferred destruction, so that an RCU grace period cannot end until all pre-existing RCU read-side critical sections have completed.
  2. Reliable, so that RCU supports 24x7 operation for years at a time.
  3. Callable from irq handlers.
  4. Contained memory footprint, so that mechanisms exist to expedite grace periods if there are too many callbacks. (This is weakened from the LCA2005 list.)
  5. Independent of memory blocks, so that RCU can work with any conceivable memory allocator.
  6. Synchronization-free read side, so that only normal non-atomic instructions operating on CPU- or task-local memory are permitted. (This is strengthened from the LCA2005 list.)
  7. Unconditional read-to-write upgrade, which is used in several places in the Linux kernel where the update-side lock is acquired within the RCU read-side critical section.
  8. Compatible API.

  9. Because this is not to be a real-time RCU, the requirement for preemptible RCU read-side critical sections can be dropped. However, we need to add the following new requirements to account for changes over the past few years.

  10. Scalability with extremely low internal-to-RCU lock contention. RCU must support at least 1,024 CPUs gracefully, and preferably at least 4,096.
  11. Energy conservation: RCU must be able to avoid awakening low-power-state dynticks-idle CPUs, but still determine when the current grace period ends. This has been implemented in real-time RCU, but needs serious simplification.
  12. RCU read-side critical sections must be permitted in NMI handlers as well as irq handlers. Note that preemptible RCU was able to avoid this requirement due to a separately implemented synchronize_sched().
  13. RCU must operate gracefully in face of repeated CPU-hotplug operations. This is simply carrying forward a requirement met by both classic and real-time.
  14. It must be possible to wait for all previously registered RCU callbacks to complete, though this is already provided in the form of rcu_barrier().
  15. Detecting CPUs that are failing to respond is desirable, to assist diagnosis both of RCU and of various infinite loop bugs and hardware failures that can prevent RCU grace periods from ending.
  16. Extreme expediting of RCU grace periods is desirable, so that an RCU grace period can be forced to complete within a few hundred microseconds of the last relevant RCU read-side critical second completing. However, such an operation would be expected to incur severe CPU overhead, and would be primarily useful when carrying out a long sequence of operations that each needed to wait for an RCU grace period.

The most pressing of the new requirements is the first one, scalability. The next section therefore describes how to make order-of-magnitude reductions in contention on RCU's internal locks.

Paul E. McKenney 2011-12-16
perfbook_html/img106.png0000644000175000017500000001414711672746027015317 0ustar paulmckpaulmckPNG  IHDR?1XʑtRNSىH IDATx]r Z %*- ҢlJTY`m RBA:H X].3=h.== phÂ\ߒ3]tLKH5$]t17G jwd%:pS?Tݧ=ꙉk=%/94bj$& @t8Y݄@P:YeSrbxXX;Ss'VE:TKpYv4pjƥ;kݺ N5LN,HЬ=qʘmL܉},jOmB?)wi`6t7dd w@ng^L )HZ&plM [a 4  @K1UޤCAf5 <%-&o zb@0'0e͔:?7VxR*:[0&ۡpr>@ shb=`.X쀵L]Iz&Ce(`M7)KP[֧%U]}Lh0= >aG'6s% ká9{ 0 $P۔u| TH czä@V׽AК,pFr?T.۫4'@k2mJs7Pz3*oيn< *Y=͌aÑQn`H(CE`H,?@!b\.$JU%bq{>T~VǞ.@L` Y ks={4 OpIމQk |@s׿_Mvw)`H<~ lP1M{AA ?|6,ϰem_Z*O'qQKyoM~sIQ{ p?R" ( w[%#!u{sSb1ծy/1vsvȯoX{N 9y8NBַ\ַ!`iTDn>j)hz<~zʣ@hӪPp$|+c8w g L+ҴP\=Fl`}'(ٚ/h*L haݒ%(,[q,Fˋ p[>)rOt_"4 )rH~cEw$\c&o bܩ)p),Nַj<a"yx&(dxZ*|1K<د~X4.1Pp)-1};-L \#r%NE[.z yҜP`Wٹn\瑋Yf|,2zoh BXlSۇ%/~[͆5&^*ti<ťb"(fZ_ӳOY1ɞ\ZsB'7cTռJ8lg ;ԏ8id*Ӑ#i .Orcof ӌWd[eH%Oַ;'VL[WKM5Kg*L_₾B?|^PT] 8pa& A?u{$ uętltl[G׺N3x߭nOL᭦ ¦nRиuUq&t rO'lh8fj/3K6A<$q=ɡ/Zx$T`~_zgxۏ%p:#܍ldC,O}|xEq>·m[*WT;8eu !Z{U څqӌg g{JWzg􂺉cI s6 8fWKp7J_ae&O\ aϛE^p/?|;KAτq<PL b_eM^[f-T wV6U׋>ۿB cֿìY2*o`J V7[ۿP#hW5 mC30~ gh3A!ُ =^Pxg* !S5"4P| ziUN q岼Pk7|'|Vf\ƦfD "fK}i X [ywdTUn۷yjʦ@ɫsUmM[Ҷ?C?$ \?WV>fwݜP..e4O@(7|kC5 ߨJPI› Mߩʃ8֢[G5,Ťyb|g9\߻(AV\w]w..fH[J!է=I 86)@ E)??w*&ɓ3^_b]Rb8q7a8.j-7gn hpI@׊wl#@VCM>@LtB16}7woIENDB`perfbook_html/img326.png0000644000175000017500000000103511672746125015312 0ustar paulmckpaulmckPNG  IHDR6%M0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDATX=OPAđW&L J"~ ;ĥCW8^6c4i+rjO= >.ÛstN6UX0N4u8 /7gHq2* <8:{m)3[2Xk6U <~{'#Bk=ƥ>(beC5*;WtE[> T"7Oۇ,ݹw=*?ٱHPB܌CHD jn@8=ͽK؎d-VIm~AN3HZEtArfS%oQkr,DpP 3D̓wI;`Q4Xs|GAq_Zu@!ßKEIQc+]I(&Be%z[; “1IENDB`perfbook_html/img108.png0000644000175000017500000006545111672746154015326 0ustar paulmckpaulmckPNG  IHDRYGKPLTE40& E&)T8;aHK& Z@D!  != $    $ fKOS59'&K/1K-1xegI)/9q[`18 3/0 ( 7 N9=)' F(+B$' ZBE ="%, :" \;@@&+. [=B# P17 8 D'+@!' 7 3 su@%*0 oTX)  % ! O05M.3# " H*.Q6:P49@"& F,/5! -,   64# 1-R37 hOSA#&`EK>#&$ G+/.  9!0!TtRNS@f IDATx콏׵/y"B77mv@*$}oEGZ)ט \Z 2p>)JS T_R]hO:$wNd8@gD A\{Fc$K¤J={fZ{hс[-,91v_:OrO=TqZ؃ޙ9bF*};j9:TѸJ' Bb1iBn1k>N HJLaSӈO-(Ƞc0)UЧk?uk(: TւLo/]A((P`Rar$J#y'J) *%r0,ʺ8GF?2 # 7;B'O~D=U*5cb x^X&?~%m~⪜/S~>0aGYY304f+&2ʻ ^ۮH"|QK7]C~U.<_t=ydH8T U8Xu(ަGT̯zԝ-)g]9 (xq.)9j)/xqOd/|Iz^=I_6yխ̊?bJ N6b$6}Fyԗ\g2 {1I' ڮ#IwziyT,B>2 ʂ(R"yap%!F4ITR$ oћw R6Żl}JY2"Gt/O`xqǩq['\g=苗%Hhs@\7(-dFz\SxȽ?kY4ْ,:H2Ǧr(3/+ 10GƥbN{f,ӰvV3|Ljg HhE}y>R}w *X\ӗdKXᯓ^{J:/j ѻ<~ƸI>K  _Ue k~q/j9W%Hb 2\\J5j#R1ʳ2[2ڑj?J*xe.o(} lymSwwo7Gy!2;޸#:^0)fcAL&NSF<li5{̵Z{I[0ߕ:$z;R[B 8D4󃜵/6b'az!Y5#:8n3>ȩabaZ[lK|Õ VЊ"Z΍v ,DrCČ,>g So!~T<z"YΆ͋f!f],iB,/d%"O ~ֈ{qb/\[qNBS7k&oO3Dda9O/Dϕz+!^0]qăqfUoTR-8ի=u$u$Hgd-ݨ,ڐ\mȅmP+2 c~6X!g3]hR#Mр+8B"?Jqh:4fXkWוr:2kgegQ XNRHuO_>1BRkwtSQVJn*& 1i4vݴul^f:VR- p*<ۚOԗf窉M^ӝT?W}uz̼%䨙scx+G< zNpG]+ ?C!Kg>*({&G F1ӏ63W<~/ o q G: s\6@R-̎ھ[/0th*M̊`/*Q^-| ݁ig|j_|꠿G~mxx᳙<&tds!)?lqn>-׬JPKji䔣 bqu.Ї"!00SFԴ Jiӏ8P+Y8\uc K L&SM.AgNi00s.(l:ȿ7ot seiRJک#~屰Npr E`М\쑸$Zsĩö Xͽ8׿ړ-q>kzTT^j;,Wlltd=B5Vk{LWՊx_<ܭV6G7bq(a>Vv},7}j/lu 8,HX7OXm$mkp~T֭-}rIMK߲sCV pφWfV+ 'U .ͥ*:Fτi=0kԮYd5֡ҼWv:==*M:aUk ){e=cPYU0ZԹS Vy#' Dz*Vܡ}L їL+5K's\'Z'/~:}szuQ2Zh}( e8ىm[M޿d*-ZF=\EEA,2uAU3߫g6a26Z:qX8'q rEvQuAC M&FG%Q?}} 쳗CTC9LIMFTEvU(#WSKyt/gY_axlV\rF,frIsyn ?T§j<փa;v{}w15]EՓ7"*(pR.nH/X1φǪ5ϛQ1feYH8Fl\W.&HپTţ\QOVFϽP ª SU5*D 6#)uݫ2:WpB}r6c,+T=x+^/9T# Cq,c9#EF{= <{2MY_ ]QdF..O6q33Z߲e~F K/3oɱ p xAanCzC 6qgt'Ub q3 ϻ.YSWO󛝸i/@4?D9Ѕ,C+N/0>Q!0MɹK"o߁|SьdėwT#6IA4b!A0ߌAF%'T"Tas}l_5u?/ڍ6H$Vi Xe3s?N ˦M&aeY03LzئӨ0?vmWS:ӓwtmϐի;m_jvz%iFMS #m +skhUUq$BLW< F|HRPAW7.|.QZtItmnjj]{z|{N84]$)? tjLy8ry2c擼"R7 P!h.3-?(KE㨕 fVuU>I N[N0t9`. W+>#vI /Ã۸*0h` ͈']lC9[nHK.Z^GbW[l ߤ%={,RSFsC$r/haL@3 b?Ba}J]UG~6a#-b  55o2/'`cSTĆgZE҃XcTsn;ޙQ@/ȑ IG}NfReTD.҈> OhL$͇ 0>`%#(eX3Ќ”xX pǴİ43cm4b&(44L;H迳I=}ks ʎ۰f3TI|Qf 52XS;>[w-h{eI?'R@%&O.ۼ AbdsL/\Dz" `JM !31S(pt)NWh ~ Gu7Hي[ Z0?<5GY4541B C >Y#;myԅZm_wlm ڈ[-ђ .ƙTi֎ÿyeoX?z)FZ}z5_l燶B4`: Ɲ\L RU)N.J U!o}wVGuzuc2CP, ٭\`s@aD/)|V9+K Qth&HɬC$#`#h^c PZ) e h<)FY> :m|:?}~+w*g0-|Eq^?ohNZvI<-&ƳX#gWՓ#P# 1qVRKwwڿ[tO;{ 2:vmntpnVtW:GOMAm۫W"}sj4`!:zWsw^y~;`orbZV @j&ghBpd75ܚ͖3/k^zTZv)fnoX< ‘^ýuk/.x:S^ ՐL{ ,BcM=ş8~{ ќr#cO>uM OJsVk#65WT  |QoPZd:F,e7(g%P@i^ёEfg7L wbsz>;ۋ! &6, 4̝w3A%KJBI(q# ܟCYv˙Eہ*2я]l@ɋolIZ%ä; %x>r+M3zpB[ܹ++|&Ԩ!GM^47`{8&.rFW21&2ea\ XO,`<6=E)Ʈ)n #YCF IDATEwd˵uΰ(36bFMd=Jgb ɠ5~"#΂m'e2`_Ն)$r%JV7M 20Eh@'J`7o@I,qpep1lNv\U=1ɪz]* {k#Bl4c;`_hqyVc51ܩ0vJtu7tUŊip@|0\,-Hbw省])@6"5V:zcJ" "4#Zl4• ΕK.GWV`42d~36`!0m)`d(Zy=ZIeLɌzpy @t;][kևGGKZaeYbZ6\:f6m|T,@ʫUdC.grvO BD s)E0̧D$ p[땅KB f n M9 I 9p2#sHBah2@+;..fH,NشaKJXB Rmx(N1Y 'v9h 2L{xJJ;l~מ"8QYhb e^'$H&kXnfˢh'zb&l$|*kwo~S&km<]5vkv:Yhɶ>,S. Mlgܲ_I(GԙCwǟhc;dh6|4t8j#< ri3mի4XRlt H3x:. ׬w,̧V P . pcPdݝo\8+^A[kܤSYUm1Xw}6[}TYU NWpfųKRm<y銮;ƕRtPwsZ\ 냫ZՊVswD);dK?2Þ2R멝~qu>0QNLK'hOzý1b̸ǂP r5uh`dll]vCa FRt:L0+6w1d0Ng#\u`1[jB^j FX3j:a 93zVctG. ] N` {8`^xEMU4 ⤲RYX>uEb t({-OHN4F)$BsZnv2K(y;VB1\{6!ހ=-iGŪMVU7 ĝ0_}["8B5؋[eAANTWUuArK&Xl!W|h&ex֯-Y;wwwvhC\֊$k8gHB !CUu.OpEz"VАִn4=a%o2 )!^}[VPJR?t zCz7dUs%YD^Ġ\Hp[˂DV6H;z F78qA,o][~깑2+Y'@jCdn/KDW˜ƒO )= viI-Wh0Ul eynYә@pJ~Iˌ1h*%'9lYx$llE㒒̋^5C`I|u h (VV ^l@&|(JQ&…WHBT^n lMv,ry/k>e)Ȋ"'Kӧ xCoBCNLC$@1ll[s򛴃QB_l!`Ow0z7_Jc7 (.]T \$J̠avސh(gٮUo: Dh|hYYZ W"̓)i @&?;~NZ^:,&ӟf?ظ2Ψ@'06=/,vU躇_st(qA:hNc5Ԏa}GȂmK(KHs?u @_#Hg`p}J=1oxJKꝿhہrM?¶&psŚEsY"iZSSC\h !o=ŋnsJ }OHkϔ%!$O6>2?kDQpQɞk\(*eG $lPW" f1@sH]Y@QuɓI@L8L';&AշJ42$R\sJ>HN6N?X`:oSn7,wRQ?4"*hx{rTs u;g2h`k=hֺ.98%ڰmӒ ޮ,U^Z=4],t?^\x׏}ҟ~+}\mk_<1.FSz[&˨ƴYEo0|ܭw:e].ͣ`k+l@J % H䋟Xr$ {5X߭S}TaCLcw;g1XkbT̒]?7uf|WR/e/w\̚L0C @'=x46#IMw?IEwaA^[XĘ3c뉏k clM([ݗ4vY1Wt`}́2~i v⌆ۘbr޶J$d4@򹦇 `㘼A?5n*[O4@H0l0X:O\@ )=[d(;XY#!cݹ pϲwwz^i ($es^wiwI#nAaew!Ops$Wx) 0Ӛ`paf+?M @9#6P6 mz3XV{?: # Ke3ȃ;VQ`꣢99̈́e ܑ9b`$V[chSFVT\хXI]nW)>^:I З q <W0h*<`/)v/'L3> qˌ[>QuOLdJH !3;"g=* 4=xX- aBH&p@xhk҆?'9C*K`Fcu a 53H}lNRTV^Eo8Tnyus`deQTgOcS(Б̜Ϟ~eF||;dR@jY<`ԵHK\ě_Z3}/.WTG3v̻f+(jx}k|:a:*٭f)Nu&28/1a_ujUԐ[8oM͕9wUJu#>E>#T} zQF۠61?wTֵi ߒ.2 pVa6R9P֩|lZ-hI4#`yR!VG2먐=w;y`<`lK65(RޜG54DAz'2NEYf*9c $o[i*l7 4.#H-jY1;u LBڬ̪C,g"hfM-,lOX<~gH:8$AY ]]`>cBy_*Y?P~K 'WsnOmS4ktĺhWi{d=o,yTp{h&EDo/b,HN-l vkӡC]V}<š'fbp7A$yMw^E>T(kk6#c;U\>*2vD\#?jdw2/~}1_@= '/k҆Aev"S⒠1\qbfJoۉ 4 DW $5B6Zݯ-@Զ{<\ޱ^cPM48lׂy5+I.%'CJNTaVdɀ+{Zui!j[:5T)\wYux起g3OakMYu(wޜksp!Y@ Rg7ˑ3%PfO7PYUQ%ZJԲl2(A de? OLF]:cXD+/_9:cK`{ilcGѤ;KqE򹏛Z !`f{-j9[Ac(=e.v7cxk Ob-%ҝp5zȜ^~.X](鶳z1Wߺ3h\][\8^ʈ崰 9˪9lxʋ _.8/tj#N^k\k||~;Ե_;Fg ܝ@VC;e iÊ (uI.ЈE./`ݢ[wwM9{oXS7eP6Ni;7Ymκ:wzG4 {3`Qݣ!<|F8|MXډ'M;Tlݥޘ'jW.>|%W@=ջboڲe_cVx3]tuNY'gw4^o骻Fnu#omLH(+|{/m-orzW܍94p~hoL%=I:| =r rjPl_ݛ6jܑk#jB78ӭMb!r;sEVW0(bMBDt)7!;jp8BOsVV~>qwU=V鞎f{̤.V|ЅnӺ4 S}Oxh=΂pk6qiץi:l]`8.{'y?9ZW]5&'B&).R꫎3 !SOۙ'%@?-nVk>I&km׍ilqۢE5=m|~l&:(xi||uA]@A딋cNF:ڪG{vUv/L0|%[U_h9kgĜMDu/rq`4 k*ilPsVtbTE7l}g>{EeAU2We-@۴ Jʁ:g!@E M"΢]o W,D⮻ mk(A zga jN! 188ew8˚) EvKЇ*(h /F5zbBBE,F8g;%Qxi.n 0eliLFfK@v#C VsFsۣ0o@+iB_/ϬRC Cy fBe/8KyBm 1;c`gc\cynjT[msyh~ڤJO bWO,ɉu^}_ %24d' a1.˭Qa씘 FaW9!Y6!KŠp ^ &zB2݀p[AY|0<c6dm[uQ 2 g,s%qc7u7Z,@ǝ{[0ϴfCOʜ7 &fړpD[xWO[myIG ) Ȼt c+4`=lujޜm .V,4):W8Y㤅\kk+=S.U1g0L㬟-r],nNSsM9Rh>sk1, %) v&΢uI%7I>LvDȷ>uq9nhd`i^vW"`l,QTP~ىXeWU*+`~b}'zHvaxx IDATZlnth/Sh`wҲYq[P 38KQ]5& }Gd e`m%Ɖsj g3m;FL0JYZl+t㌩nU@ EYTE-n}=U~dhOJNLbrXQ#(C"#lHW&o y)#g.DHZfjflm>G0Iݮ(q99b9۪w=k7{@^f$.{h@[Ѽ 6i[fGs9<2|*cAe аÿ2g5A:߄hZ0Uar%ǒoYiWNx鵦^ý_[a2}k2\"Wvc''JMFiYqPE=1m4!n cX\UsA;PȯClVVHh\@#S_/mzmRR=v@=pu׳=^hi{XGe=GbzmZ0o?K$tE. 45 w._Ht:esoeGa=){PN!z9sp"> Fǃ7!$T5bL#n`¸ю?B`sM'#% , =6keQd Pjpj,ʺ:l"0T~C1ϱpӷҴ+TmrIqqOZ99uE8,͂q\,. kY~P;W €kAu"{7|K+r`:ҩKQ7L3:Vʭu{3'G8y]`Qu5 IEuXĺD7Mͳzlw"doh笯~zVwU`HOn%% XŎ0%o7[ǘ}VeRMac@yBu[ϭ U;C8/ Pv/w_hfU"qȆVaa[G,-t[{ m?| :ҠAfL&o\lHB:2S.m̵R^v aC2:Kߺ/ .~ٌy~:6bܸ/Ndݱ= 1Pm&2}cM%{~ ٭9lNP}k>Yfj qu7ܹrlܬ$'h!ֳUTY g "9tj_y<[*n)l<*9ӥ#D6L>mBEpG;,*m{'/Pꤨ@` t0AI2xM) HgYąf?ֽі2LjM(??jGu) ']ó.oh阋m$|<>@4`|[pCGvQ2?$hs|>~56set5`F4^Wtns]wJ׍Nm].N] PY ~@)ť>IO ,Ie] (ƌO=VǨ, UZvM J;];srdkwQ&R|o]B<;5˸?lXvDBw6Eb1TŤٌ0Ht^N`ZrO7'AU 2T6>Zu<@\eD[d缢$͊hc1 _9W{cFhA(gNv]A }[a%KIuyV!yt|""OK*%(OU@Sκc Tr ST3~id//qe/_l;@$TaE?lW8?QZږ:K5*]?D4/fkt<؈Њ/&GGl=8a.;kzK;1;a#Qu-?6A-R.Uӂ@Ng~rUpLWد] QتU-qڌ0Z̛WiuTsV T#m%~2C%QeKG*_t7G!.c4 H])ſZ #0&s1յzimSp2O2G!p_ ʳTddjuN $20E-K*lpgإq$x&)7#aLyHYۧXG5N jSіss6 @ĭ95r٘(yZެH@n{.:mVxֽ)8rM8\2WRB]7ZFC J scJ"УG]@"~,[{-#eTQJtt?oWt73ڡ[o0m*[ϷwN%N+DL*0tK}EMzV"Qr Pë́+>_'di#M Swb*wMi{fW=?P/ ګ}u89\ignG6UsU*ONgK:&{s_Svau:~[+zT8~ͥB MOVS9WSˢT`,琳X2`g- wrEw0OԒMt[}olR= ՐIE U^2V`>;! Y\ \Ѽڗ6kd6# bMB=K2LաUEBT˭+WKY%$熄rp\p'g&~ a:Xzrc_]bh4Z=~r-}H,(zW뉆#mD/pM º[j;*m8gѻvRf*Z}_Ti켺@sH x24C77iw 0!ӛf1Ar-f߉^o;F]/9%XĞPRuDB+M4b A^A& K* 11ԉRXXf#j9›<)%Ud'!x0O3pYԥm;ZWu/SV=IDYwUsPr8'ߦPnr 8"ylu"{e<ۜ ְ@ M`DTh:#aJe19WVZ0 N +aVmAr/18\SY`<>5v!Q^vg*jg($/8G͡",;A=W ǰf`l\TBSF"0ѫH?%0&\ifr|7νtV>">e)jMN RÈuNDcY3dx$7)FF HUցfï.Qgʓ,8SX ,o8߉ⶍeUw>sוSnMUmk-/4X%~? I޻QFWO pA[cUOagW܊flQ۟8N7:@_r燁/ٝ? lӅvV2 tu&'7:Z^d ov!'d!{|tfsj^^ØɏϔXGo^So}њ5iw1a}=-|Sz=d̉nn{G (LC3TWV vV8DXBpaZ7؊E@fo е5G67jxgʾ0y( ^W^nao+M"lbIwKh_1 }w1+NDڧUGp0K@) \R/VRٱ ;5ew!Z,0hpĺMI9;(](-RRƗ\Ņ,(t#]VmDYoٺ@b="* ȗ1[v_=G7uxɸaq;ڑlh*$)_25x܆2Ԗ^W_^CI0֍0EXe'ls$]<9/ s 4k&iI0 wV\Qu։r A ) j=NԫFjdU;S#KQ #;̙AgsOnR-YV>2S,b,豃W':\`WDp@97͕3;">$DThs:)R颮9Lԭ9Sf+Fx{ +Yp< b7(AR YZ&94y ~wD 3!RmpcLxl:5fOkt>WB"Zy>Co;tv%J>>8H)g|O'vzt8\7/sa<1~%ybs4o\)oBk2 ̕kxʅ2l&F`OYitZ*bokc,w1V\7(7 D4!S0/8j9XJ3ڠ㦍t*$˲RL g S̷O&a?~"~tϱaU4 i== SN6qT*fiW@dk݌fM`8$/KCy[F=S//L)^n&)%~رa]#8kjg3 ezgM-rZ%Mkw? tzo͍0t}vsqo!2 T; [Un_̎ 7n~.hgFbB%mҭ,1j wZJ=(*@"boc DXbv`4p{RD:t[33@ďTi:t(ú ߩPT{d^ǻ1et7rjnYj!Ü b¬9 Z*szd%QmOLn5/}k !] )S˒YX՞җIJ=mc:Ͼ#Tgm8.՘dܳfosg8Ÿ7(q@`MK=C"zVhרĚw+[Q`2]>s5Knx .3 Q1F'Dֺ_ݤR.Q!*ßևVӪ"'րi~ά9%ih,vaa]K,Bs< bp'PL|kppLJaUmW(T6Ӭ .շ 7qClf36iAcml&fKٳMQ;}}u ,1+xv6DԚ|*{V^5 KQ/yX,$˯]U@k;ɝWQv?Ӛ̱vdpYѴe,w÷O VqT+T*3>e;?CɍnC',f(v?b:Ԩge_:5|([M `*跼R5Hܲ؃O ,f-˘V!ƵI.Iq~P6?l_>zO}@YAZ~[ht¿d]gVF!"E2@pjUXdu!2=@-1a [1B}FDhYf12Mx},+m펧[/3?@'F<|n.T>[8Y2v6ղ:*,hYT?LIDATt\{2c׭ϘRS,Q@,faE)%j:m[Y[@\]V>?WR~:+U?uXPWG?QEA,7y$'n,&FA@v~87 &q9:X'5f${jrcwg^k&lFq=o8药/1A^tO +.TI跍=DGst>6kK I0yy|F*цHc3ߤ}C{++r^ WFhDgk2.b(S-sE9U,t\YuzAO@1߆e:7n!P# NEʫM=odw2`L\D.]'I.-Uy4'DF0AOZ9k _z"NDVTW8{0?*qB!ge4P3 ҥOA(8Dj?uN[ ,\ Cټn.BыaRdZo"nLK<#Kt'ajf -UxjG;|7JJi,m:ca@\$PzTX'o9zp- s#j'Uʛ".qJ\^8L5҉آ7nEK]4R1-z=T* 2,CKcv20TVLɞނ~ѺEVysQkj*x<}2kUcM?2.Z$B( -񦽹`Anh 牨$f1{@E9/s$YSɰV^USeKh`'l>9}Ǥ.jӀl,7S%a#Lz3t7QQpq~,+e3g\`Y=<^}:1ˀzşq\ F&.`W< ivbLmڑ4 /H/251fԴI>cD')-hHޢ+J$FI 'D߼<}hu~,uH+x' h|`>vuF$wTSzN\m' 4F2ýE}7Xz DSy|p{Vu`$eyn촌2Ɲ2&1!vp3 D.2.7.3 Announce a Quiescent State to RCU


D.2.7.3 Announce a Quiescent State to RCU

The afore-mentioned rcu_process_callbacks() function has several duties:

  1. Determining when to take measures to end an over-long grace period (via force_quiescent_state()).
  2. Taking appropriate action when some other CPU detected the end of a grace period (via rcu_process_gp_end()). ``Appropriate action`` includes advancing this CPU's callbacks and recording the new grace period. This same function updates state in response to some other CPU starting a new grace period.
  3. Reporting the current CPU's quiescent states to the core RCU mechanism (via rcu_check_quiescent_state(), which in turn invokes cpu_quiet()). This of course might mark the end of the current grace period.
  4. Starting a new grace period if there is no grace period in progress and this CPU has RCU callbacks still waiting for a grace period (via cpu_needs_another_gp() and rcu_start_gp()).
  5. Invoking any of this CPU's callbacks whose grace period has ended (via rcu_do_batch()).

These interactions are carefully orchestrated in order to avoid buggy behavior such as reporting a quiescent state from the previous grace period against the current grace period.

Paul E. McKenney 2011-12-16
perfbook_html/img101.png0000644000175000017500000001527111672746110015302 0ustar paulmckpaulmckPNG  IHDRW:7~tRNSىHrIDATx]=㼖=]1v" `-.ZMd/&KыJы `:@qV<&HZ(I[O.\^^S/ A必o%7C$%y2 Vv _O,~ꢓRp 8opɟ ned7>ygolTWu d3>_F9UE.?9Cr`+me]ĥ<N/)}l_Ko ?$od$CUR lpӮ&^@"uPk^ HT~14dwG*cܦmRA-@ \65e3uY z萭EWd")j[ַUIew8p+M$~?R9Mr myñqξ+ ~EѸ}~6YyRҮ` dND dGR+%wṀ odwqYvu 7JFE5H"J/*7%}vUAnC 'ĀKn꠯vwͮEmq_u&X)'*<=U!^((ueEϿо5~AcӻSh8Sjx(Y0PK|HZd@/Da(@r7핷\!y'p?Y:Gڟ5'b.6~F(`%*la1ijd;pppR-ArV]X'V|z-o9X*o"_^0_?uihSv)q}!*9*ՒJLju¦9V$xpn;nJ Hɂe.$a+{TG֒ZR=t+PS Hexj9k+iHg*E0CRWn!2>X D !d9Cfc*o6Fx%JSLԮȯWJbTP˿*" 튑rNݝ9.6IQ2_ʫjT6Y||w(%,X0JCkPc#_cE9Yoj2?jyrhkGJu2(yLB]-Z[Wkک8-|'f0MA=L6@ \ӡ@yDv>>׎bPbG`.bc.Rp`8Wtd5չ[ݜs¤Zt چ![A>d_h'L}e>q ~) {1lfˮ4`p2I}eKy++7)aZ{A~ok}ju'a쯫сД`P6 ꭖ]~,xL<:j%vW0 0?KWm)#IVX$ mdT&,  igDwF˾Q= 8ҹБgSؑNbҾ%K͘!`\,ؚsXnW]F /}պ Z}c( 1-(Nb/J JQ4W=~$@PmpN4YOVV6hLi6؅u8n:)r?w86M V"XuE0rV J`ȮbcMwmPsl#;*eJ l{U AhRP (/aKiAIA=6׵fPQPX6[zM9։FM d5l쏍/{ES{CE/-BdﻗAԛb7)M۳Q-cKSo CC4}0w6p cJSlȦ0}ۡ8`[Ve;x֊4;KDá(N H֖sZ&:q:HHyA2oe(bUi gC4&^20)i4U8Q`5]1aQҍ 5kUUy47?U:K{722,mn=AV6'3ٗ*kY`"k Y[0J6z8--4@ =ʧ\:>9د=8`| g}k Tߵ(B{] }5q?+?׮&v0qC\s:".zٔbf@>ze0ak0'<0zG: - 7҉A bڃpkoj&[ W8?7.mAUjhN&0  W@3h06܌%0^X/LmL ͯSb(5낇`jW;^=pW簺2 j,(7(Xځ8J *l:Eb Y J *m5|epqZf]X|k@I2k 9}O=5'n<$NlǞ\"؃;k0&#{J }~DqH?yI~DG?81}`NGWv@1j{Sr ho SR8hU3)= ~AIAYlu| %yPRP偃DIA|KPQPq"6()wr®׉ՂMj nE[{ т L90@SO+chz<0qak䡡S MZ nuDVPhYB@RYkxW2 %ø `]E˝ y%ԩwJM>Ѐ„nLeV „q%J_%40vJ倁}F'$^T??R= W`go}=LX]+2;hveK~g%9([9Kx"o\&V7.b`R\6ıo2U`ՋvKXVeMLm.v0aj Jr`^H-K7ݡ$-Bf*\cw%!)S[]"PDU"񶢈&Ⱉ:ḔΙq^k&R* <$NsI ''?k#?E'<(]8rZpҞsec5;mO$Yڋhmuˬ֍dcTkˣɹB~AIK?j]l{tDwJ4. P㦢EA|Rw+ hZݰ´© `wyLqP&ȴ©|0W[ zrt`BOL vE' ?oA vu [/o]~}펾[bzbVжi"_5WMVn8߾:~ Kݝҹܭ̬bEO\zB { +;7ϯes~H笥+.!T* S)h[AۮEL)9n`M]@J_^6}큓T*J€xxt169%P_3DJ02Wo-WBGa =6Ȧw[,MGc/9+;05?:a zG|Y΁4m/޹G3'~8]*/o:t} #Mp{)v;KiG/m+h[Dtk;NjP[GŗNGRn*7ʍ2Mcuoq~ew lڡ=z c'A = C!a^Vеb44:з]nVг+ci771Q9]E Ϊ`%qG}Z0Ne%9q2?ݐ/i wPkƩ?;}x@x gw[3zYA|5Sb Ƙ`0>ViM5 8Y1`7(Q`?oȬw,zh&n(]. <T6{E}cd{Lг C!M =Qг O~#a⍞ DLK](E[)ot 6 JL@p}Nʯw]'щHGp!'eVUSL w'~k wy߀Fp@qEbp ʮҙ7̝"? Iy-QJ"1 ȯ+!qBǮm~^Y9N}<"[lXJ"1T>i 9|[_Wg}9TVWkF))'F,1>*rj M͈ Htx'3A#aӸi|LbDij Og፞L(r'0FOfFFTog0J;K<>5YbQ?ij x'0 z6ɯb$:@#.: xXQZuwN@qHVt$G{iF;1Ԁs@) WNjo?_'#Q+|'۰揲ɰ!Y6ơ?1|2< 7~y 3c|2l!YP$FQφRSv-z.;^q_z VvD兎ġjQ66䐬n( Jr6aa?޹CJ0UcHͯMna®ˆh$:` C.7.2 AMD64

C.7.2 AMD64

AMD64 is compatible with x86, and has recently updated its memory model [Adv07] to enforce the tighter ordering that actual implementations have provided for some time. The AMD64 implementation of the Linux smp_mb() primitive is mfence, smp_rmb() is lfence, and smp_wmb() is sfence. In theory, these might be relaxed, but any such relaxation must take SSE and 3DNOW instructions into account.



Paul E. McKenney 2011-12-16
perfbook_html/node360.html0000644000175000017500000003132211672746163015645 0ustar paulmckpaulmck D.2.8 Testing


D.2.8 Testing

RCU is fundamental synchronization code, so any failure of RCU results in random, difficult-to-debug memory corruption. It is therefore extremely important that RCU be highly reliable. Some of this reliability stems from careful design, but at the end of the day we must also rely on heavy stress testing, otherwise known as torture.

Fortunately, although there has been some debate as to exactly what populations are covered by the provisions of the Geneva Convention it is still the case that it does not apply to software. Therefore, it is still legal to torture your software. In fact, it is strongly encouraged, because if you don't torture your software, it will end up torturing you by crashing at the most inconvenient times imaginable.

Therefore, we torture RCU quite vigorously using the rcutorture module.

However, it is not sufficient to torture the common-case uses of RCU. It is also necessary to torture it in unusual situations, for example, when concurrently onlining and offlining CPUs and when CPUs are concurrently entering and exiting dynticks idle mode. I use a script @@@ move to CodeSamples, ref @@@ and use the test_no_idle_hz module parameter to rcutorture to stress-test dynticks idle mode. Just to be fully paranoid, I sometimes run a kernbench workload in parallel as well. Ten hours of this sort of torture on a 128-way machine seems sufficient to shake out most bugs.

Even this is not the complete story. As Alexey Dobriyan and Nick Piggin demonstrated in early 2008, it is also necessary to torture RCU with all relevant combinations of kernel parameters. The relevant kernel parameters may be identified using yet another script @@@ move to CodeSamples, ref @@@

  1. CONFIG_CLASSIC_RCU: Classic RCU.
  2. CONFIG_PREEMPT_RCU: Preemptible (real-time) RCU.
  3. CONFIG_TREE_RCU: Classic RCU for huge SMP systems.
  4. CONFIG_RCU_FANOUT: Number of children for each rcu_node.
  5. CONFIG_RCU_FANOUT_EXACT: Balance the rcu_node tree.
  6. CONFIG_HOTPLUG_CPU: Allow CPUs to be offlined and onlined.
  7. CONFIG_NO_HZ: Enable dyntick-idle mode.
  8. CONFIG_SMP: Enable multi-CPU operation.
  9. CONFIG_RCU_CPU_STALL_DETECTOR: Enable RCU to detect when CPUs go on extended quiescent-state vacations.
  10. CONFIG_RCU_TRACE: Generate RCU trace files in debugfs.

We ignore the CONFIG_DEBUG_LOCK_ALLOC configuration variable under the perhaps-naive assumption that hierarchical RCU could not have broken lockdep. There are still 10 configuration variables, which would result in 1,024 combinations if they were independent boolean variables. Fortunately the first three are mutually exclusive, which reduces the number of combinations down to 384, but CONFIG_RCU_FANOUT can take on values from 2 to 64, increasing the number of combinations to 12,096. This is an infeasible number of combinations.

One key observation is that only CONFIG_NO_HZ and CONFIG_PREEMPT can be expected to have changed behavior if either CONFIG_CLASSIC_RCU or CONFIG_PREEMPT_RCU are in effect, as only these portions of the two pre-existing RCU implementations were changed during this effort. This cuts out almost two thirds of the possible combinations.

Furthermore, not all of the possible values of CONFIG_RCU_FANOUT produce significantly different results, in fact only a few cases really need to be tested separately:

  1. Single-node ``tree''.
  2. Two-level balanced tree.
  3. Three-level balanced tree.
  4. Autobalanced tree, where CONFIG_RCU_FANOUT specifies an unbalanced tree, but such that it is auto-balanced in absence of CONFIG_RCU_FANOUT_EXACT.
  5. Unbalanced tree.

Looking further, CONFIG_HOTPLUG_CPU makes sense only given CONFIG_SMP, and CONFIG_RCU_CPU_STALL_DETECTOR is independent, and really only needs to be tested once (though someone even more paranoid than am I might decide to test it both with and without CONFIG_SMP). Similarly, CONFIG_RCU_TRACE need only be tested once, but the truly paranoid (such as myself) will choose to run it both with and without CONFIG_NO_HZ.

This allows us to obtain excellent coverage of RCU with only 15 test cases. All test cases specify the following configuration parameters in order to run rcutorture and so that CONFIG_HOTPLUG_CPU=n actually takes effect:



CONFIG_RCU_TORTURE_TEST=m
CONFIG_MODULE_UNLOAD=y
CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n


The 15 test cases are as follows:

  1. Force single-node ``tree'' for small systems:



    	CONFIG_NR_CPUS=8
    	CONFIG_RCU_FANOUT=8
    	CONFIG_RCU_FANOUT_EXACT=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  2. Force two-level tree for large systems:



    	CONFIG_NR_CPUS=8
    	CONFIG_RCU_FANOUT=4
    	CONFIG_RCU_FANOUT_EXACT=n
    	CONFIG_RCU_TRACE=n
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  3. Force three-level tree for huge systems:



    	CONFIG_NR_CPUS=8
    	CONFIG_RCU_FANOUT=2
    	CONFIG_RCU_FANOUT_EXACT=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  4. Test autobalancing to a balanced tree:



    	CONFIG_NR_CPUS=8
    	CONFIG_RCU_FANOUT=6
    	CONFIG_RCU_FANOUT_EXACT=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  5. Test unbalanced tree:



    	CONFIG_NR_CPUS=8
    	CONFIG_RCU_FANOUT=6
    	CONFIG_RCU_FANOUT_EXACT=y
    	CONFIG_RCU_CPU_STALL_DETECTOR=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  6. Disable CPU-stall detection:



    	CONFIG_SMP=y
    	CONFIG_NO_HZ=y
    	CONFIG_RCU_CPU_STALL_DETECTOR=n
    	CONFIG_HOTPLUG_CPU=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  7. Disable CPU-stall detection and dyntick idle mode:



    	CONFIG_SMP=y
    	CONFIG_NO_HZ=n
    	CONFIG_RCU_CPU_STALL_DETECTOR=n
    	CONFIG_HOTPLUG_CPU=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  8. Disable CPU-stall detection and CPU hotplug:



    	CONFIG_SMP=y
    	CONFIG_NO_HZ=y
    	CONFIG_RCU_CPU_STALL_DETECTOR=n
    	CONFIG_HOTPLUG_CPU=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  9. Disable CPU-stall detection, dyntick idle mode, and CPU hotplug:



    	CONFIG_SMP=y
    	CONFIG_NO_HZ=n
    	CONFIG_RCU_CPU_STALL_DETECTOR=n
    	CONFIG_HOTPLUG_CPU=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  10. Disable SMP, CPU-stall detection, dyntick idle mode, and CPU hotplug:



    	CONFIG_SMP=n
    	CONFIG_NO_HZ=n
    	CONFIG_RCU_CPU_STALL_DETECTOR=n
    	CONFIG_HOTPLUG_CPU=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


    This combination located a number of compiler warnings.

  11. Disable SMP and CPU hotplug:



    	CONFIG_SMP=n
    	CONFIG_NO_HZ=y
    	CONFIG_RCU_CPU_STALL_DETECTOR=y
    	CONFIG_HOTPLUG_CPU=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=y
    


  12. Test Classic RCU with dynticks idle but without preemption:



    	CONFIG_NO_HZ=y
    	CONFIG_PREEMPT=n
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=y
    	CONFIG_TREE_RCU=n
    


  13. Test Classic RCU with preemption but without dynticks idle:



    	CONFIG_NO_HZ=n
    	CONFIG_PREEMPT=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=n
    	CONFIG_CLASSIC_RCU=y
    	CONFIG_TREE_RCU=n
    


  14. Test Preemptible RCU with dynticks idle:



    	CONFIG_NO_HZ=y
    	CONFIG_PREEMPT=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=y
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=n
    


  15. Test Preemptible RCU without dynticks idle:



    	CONFIG_NO_HZ=n
    	CONFIG_PREEMPT=y
    	CONFIG_RCU_TRACE=y
    	CONFIG_PREEMPT_RCU=y
    	CONFIG_CLASSIC_RCU=n
    	CONFIG_TREE_RCU=n
    


For a large change that affects RCU core code, one should run rcutorture for each of the above combinations, and concurrently with CPU offlining and onlining for cases with CONFIG_HOTPLUG_CPU. For small changes, it may suffice to run kernbench in each case. Of course, if the change is confined to a particular subset of the configuration parameters, it may be possible to reduce the number of test cases.

Torturing software: the Geneva Convention does not (yet) prohibit it, and I strongly recommend it!

Paul E. McKenney 2011-12-16
perfbook_html/img281.png0000644000175000017500000002367311672745766015340 0ustar paulmckpaulmckPNG  IHDRu`?)DWPLTEb``URSTRRMJKZWWFCCrpq# hffywwmkkXUV856C@@wuv.*+\KtRNS@f IDATx]rń{Վ@AjY3=H#Bծ ;1Sj[ qY^pW_kkV0 R?ii{ʺfPIQ:L#^2%^: b{ǎtPS*Zo{VEux 90{tup~(jLvSVJ33;7tOMKk(1/Ps3i$7mf:fu_۾B#}Y{wobμ&7# ;JlO-5% C3m0mʽ'<6}d+hsV50D `fr]Aj*at(.Tv?@%lݎy0axnv ىqU {EZ7CjY)6'n.}M̜,h)7LSYԯ8qm r'/h6PicFۣi` eVȹI=gƷ{Z>{7a]K8|yn`~60A:qˆ¨n}h]!ABffSlY4|6̩% ɪ]P,fp?sFdldNA_ݼ&feeBdAq#$ui5"|#ŵ][6]WF!F{20~q9ѱZkדF zi2#!au[£C˹[i3Ozp$ȇSk =oUtKQyi%cks6x?.xsIom3tm nq1a`FdXz.fE(;kL7͍ۏi΃UK <*&klZ*>I 3.^[ ne%Zfi݅3fy%' WZwљ1}[zY(T4-S/I5p仵_ 2` o+TVeEQHh2 ?f~kKs3@^Ym5boK"4K:Xus `0SB)GQ(@\'!JQ-YC5 2u:-g+듸@ҕtEa7#*4(٪W.rϽoBҥ#j^ȺaG DKמ+2J9]M4w;U Ă҉keàS'_šm63Ðȳkֳ`-A?엳X7A- aS/Й)5g9_4H 26(S;Wtq͎X6 |#۪3צfPTiԚ׵˧by= 9VvMUqe:S:'u}Gy@ɝ>&Fbhma' Ǧ.&Ѩ[ ޤ<1cbyu %ՋiC$<2Tn"ȊA\ѯ2K!,p;b4g] n mvkЩmb@(7 ι杼m<5ޣ]C{#y9q=Q&V`ʙt u:$ij jcgbüBUJH.z5CF=k Muhx)fsCu8@Z5x3@Ao VO~#e}#Jsy[`$/۔,Xs5h2+P]URd4ui%@演y (MӾyV~2aqAv} {~-`b/* dzH R+3O=`fim}_!Q0S]?a&N\a6OMQ^z;c0)wQwAMf%$: #S=\u\9fk{y Mg>"Ըzݎ-jmMEjm~6mGw,^cZE;gp禮SP:Gv6oX`n>iFwe3v#y1@}N34{]YVf4WkÎ_-W ūLaWH8<"xLY;S#,2~ QZs Xkd ţ='ɢB^f8ԑc8'[K+^vwB¯ Hr iATL= ExD3{/^ɫS=6>oUB a"I|k5W*LܡTY#fo9֚%#_ N LA at,2 ԜoZT~G#Y hMշC8Fh dDWuSMPM> c`cZ^29b >KVUUE$e`"hF.1z5l:SY|J5g<ު̻/ WI|È]}6uؒxʹg7H*T ūjkW爮8WG\wφ:p2hp8 O^ y`,K>[wDfF|]ʺ"#*}4$EUYAϺREq>~&;4rXof pRGw_[mvAaK 9qQvyTϽWc272솑>`ss$m1cN+; 70?Ry^$yFm@>W/#$;۬2?A'7P PP $&L7d;`gȗA$ ^B܆BϬ'6f*P ʠ;$TBr%=~fTK0 ܟG(] EsMRyIk@y;mM$U]p+Ntܿ6t'%m5? ('0݄sPt~_&Ju!ȉe/4g lc7qbzerJw&4|KF[W񾝘{kCn rȐ*v1!3qQ¡V $s: ˗5WH wGEJYZDܕ%k| R (DTO |ܹ[2kC߂ouIޙ#P]v ),>ѱgBZuV46oM=EfE" 442EP kˡ7φޯ S٫;&o`>aky,gШ7L*P?1Ywu,zʺǜ֛tZKl |ϩ4YiJ0EwvVљ-! ګ݄S)n," Kޠ 6ΈK {ֿ~}Y it*A\<ܮ>}4?7PVL3wZ>眉T,RDm\$N8gZ-Ι'8JBOlhrs&*>yr5_sZZ4~.]HK{r]`NTmVq(čDi8i,9rn}4 N9w|wqU2\k /Q d-0 2֕FR57Qlp g- V9un"\F+`ism\[G|OLܜr뱦/^+l:'#/tɔ ^т.'-uۮx e?WkL-dz+u.K^^Ý˂Fuί{\kh"; Uo9P]LfwŪKdKRx-*_Pe09P}ZЙg<C[[E˱v;P{O-KLu JFz}Og~ I1;t< vC}ȁ,׽g4T=!R 3MeOTY Xr: 2>ÁJ@{&bxUEǽ~lP ?wPxOb2~yO$CcTpS ů1*ɂd+)ScTk[5_?@uV^S,9P75pn4۳'fiJ?@R= m䄦=0ӭq-j̑xӬ w#NSOq<+]3 ''z.aFx? V3Cz" hlN]bjma+ڙ$xpc<{6vPt0Mkт 2 ȯ:EĤf2lHc a!0'u#F @e*F9NKS$y;/l@FOBo2wpXWܹh>kGI̟'4 qM73Mb ƝVZI:b+EAnr,{'ˋu͚6 Y#I7JƊÎڝT\}-6'8T}n\ +k~ּ `䔠2SR5򭮤/띆K^xj,akx 5YY~cibYIˑ'IVaRkɜ-B5El8@yr :ݻv^ \{Lp)54HT$c}FDI <2fyD[Z~"y IRQ W9}[dei"z}3舀 ʔ+VNg pi$USqܖ_v~#Ӡn-~p?0_']iRYImpNK7_!CNPP]?Gwp@ Ԛgf  H7Bjp?tRDm C` .&Kߎ" ]*zIevu UpC-J d}Oim~lyqz'#C63Q+KaOE-Q!2ӗ#TGQFX,57Q, 峑X]:)-܏Nc1&F髶:# kp9\|~Y ,m=;S8v^0f}x6╈n_nJHHxq.MסU~)@BT^OYKl])0 G`U u^Xv3g.?ֵ->hdʨI/2vYRiK6emi+lH7|#M3Q+L ErcNrs3[ڒ)m.gokuUuq-fcˢf1J1'v̙-mٔ6͓t~̤Taі2g&$(܁N; _)Sdnq7Poܻuɣ?23.:ym9d"}2Vl=+Ssqp.g9)~IDATV\Ál}42aek[}c~gco0^S+`a,~>$kb&xo1^x7_ J瓁W}Oce|qo[:N2x}c!1^ ΩYDӝ83{;I54p[hz~@pY1~ܙ{o,I/JT^;mmn^q= .k:f{'l"7d%(V/7uP1O>.xK替qI{['@eATzekc[Mv039S==WzrY-_y2)&ezp{e3kJsIR"y]=4P#Oyw" %ŅUA.:P{ywi/CyyS9 zuIʁMi( i<NW# bfb_=/p_ Ǚa='IKyc۸׆9_ z}fg6/v߉]k͝z*1miG4^/f.oIp`Ş>ar3a15[{jv}_B ߊ MXYRPIfS3v\ȿDd-.ްʷF~ʘVIv}3.E%DacV׻1%B#`5vy!;q֬v{ٽgZ}\NfmoIJsw pj_wH S %2݆>%1JM]bX9vY! l3P6P71*"P ڞ TrO_ Ts^H]yS03ՓSA>jƋf77vTILesO_ T3^enllCfj*3/~+Ufy<]J3^ TZ ¦h׀I3_@۵.Xx[J5ڼ] ,U2`&$:+ES3!]@uj^U\F@u? 8.1.2 Livelock


8.1.2 Livelock

Figure: Abusing Conditional Locking
\begin{figure}{ \scriptsize
\begin{verbatim}1 void thread1(void)
2 {
3 retr...
...pin_unlock(&lock1);
26 spin_unlock(&lock2);
27 }\end{verbatim}
}\end{figure}

Although conditional locking can an effective deadlock-avoidance mechanism, it can be abused. Consider for example the beautifully symmetric example shown in Figure [*]. This example's beauty hids an ugly livelock. To see this, consider the following sequence of events:

  1. Thread 1 acquires lock1 on line 4, then invokes do_one_thing().
  2. Thread 2 acquires lock2 on line 18, then invokes do_a_third_thing().
  3. Thread 1 attempts to acquire lock2, but fails because Thread 2 holds it.
  4. Thread 2 attempts to acquire lock1, but fails because Thread 1 holds it.
  5. Thread 1 releases lock1, and jumps to retry.
  6. Thread 2 releases lock2, and jumps to retry.
  7. The livelock dance repeats from the beginning.

Quick Quiz 8.4: How can the livelock shown in Figure [*] be avoided? End Quick Quiz

Starvation is very similar to livelock. Put another way, a livelock is an extreme form of starvation where all threads starve.



Paul E. McKenney 2011-12-16
perfbook_html/node428.html0000644000175000017500000001352011672746163015652 0ustar paulmckpaulmck E.4 How to Use Promela


E.4 How to Use Promela

Given a source file qrcu.spin, one can use the following commands:

  • spin -a qrcu.spin Create a file pan.c that fully searches the state machine.
  • cc -DSAFETY -o pan pan.c Compile the generated state-machine search. The -DSAFETY generates optimizations that are appropriate if you have only assertions (and perhaps never statements). If you have liveness, fairness, or forward-progress checks, you may need to compile without -DSAFETY. If you leave off -DSAFETY when you could have used it, the program will let you know.

    The optimizations produced by -DSAFETY greatly speed things up, so you should use it when you can. An example situation where you cannot use -DSAFETY is when checking for livelocks (AKA ``non-progress cycles'') via -DNP.

  • ./pan This actually searches the state space. The number of states can reach into the tens of millions with very small state machines, so you will need a machine with large memory. For example, qrcu.spin with 3 readers and 2 updaters required 2.7GB of memory.

    If you aren't sure whether your machine has enough memory, run top in one window and ./pan in another. Keep the focus on the ./pan window so that you can quickly kill execution if need be. As soon as CPU time drops much below 100%, kill ./pan. If you have removed focus from the window running ./pan, you may wait a long time for the windowing system to grab enough memory to do anything for you.

    Don't forget to capture the output, especially if you are working on a remote machine,

    If your model includes forward-progress checks, you will likely need to enable ``weak fairness'' via the -f command-line argument to ./pan. If your forward-progress checks involve accept labels, you will also need the -a argument.

  • spin -t -p qrcu.spin Given trail file output by a run that encountered an error, output the sequence of steps leading to that error. The -g flag will also include the values of changed global variables, and the -l flag will also include the values of changed local variables.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img272.png0000644000175000017500000001066411672746112015316 0ustar paulmckpaulmckPNG  IHDRWZETPLTE$8D6Sf^^w<)f~fu%˲fGN":fsm4o }7h׬%#\ qI2gown]oN f5Uara fm]}w}٨YZUgX gfU-I[5fCش*v*<e-nI]i u{{'VVdWiH'SXKABumԬΉ4; A+f6*r̎A߲u\8lw=>2s_`;Ii,qYi\n}vCYz--#{ln99FyC6+pp$=`_۽\wo?f1ѐ! K)Q}fYi,Y,G͌j*LYYfԐlfTEl"5k`s\(.}ShҿG{dy k@kGvSXdV5DdQt*rE'Rp"mGbNm ۱dYlo ,&#k`3v(#Yl_8lEvdsp揟M6(/ҫl쀮AY|dG>Yzmk 8#zTmRgdɨOY-m2YTrD"@Н2ɊpUWE6o҉ +I(D6}=&k"h=6wNudהG7$j͌Yʻe7eSO쵇\[IDݝOL٧EuJTw;dK[%Od=IيJ9"(ւIc*asH\*<;~d IܫQh0WW<~|͈Al:4@&E%=~XWڡ28?u5we}S'ʏ(u5&v,#Y' +ݹؼrpkŵ趤'5ouTr[=# \Sh4sؽ*4Pu8}u'g*8PUnNWF \>e[HC1WAE|wp߯Ql.U@e}Ԩ\ @[n$#YW$-u hp vu1_4?̯ȕ(6ܯ#B=B\#AdpG5U]U6Nkŵz\nq?Ɗ;~!7drϦW,u"Sy Kse4ߘ9fq݃!+ ygGq$A9 <\o5vj.)R^e 3)!~ ܥpA묊k~qoZq\xc"7T\+'˵l& +۽F<\7x;$Aoe\5[\gƬllZWt :gq7sHޚksm 7@q޵Zxlh~6KjR"n֮?QLzۯ!o,|ɸ>#WBemdv@% ~//S.W~M|,m^??.WtM*e\eQqV\+5(tk}!irzCk9uͿ X D;˜ktº?}ǻѾ)BZW'誻pAqp)l:{y@e~$ ȭ>|"z & plOZPHXY}pq Y%_ 53{8CY.qO@k9t-ҵTJCwy뙅X%mA򺪥s@]ݩ+oe` y]9{JqpO1!SP. l+tRW\@}|5282_bu{^}OaOFU`W,|d']E霆+Ӝgd:1t: 9v]K_*O(?⺊H_?nggNJW|hD&~LU4{iRGzm{~5 /vX\׻Vbf26)ig} ߩdI*M_c_CꦿƓʯ3†*moLŏs݂ik*cb^wKB3$0fu<]͵tumq3COw=g_ ꊊi4?/g' y^bV-k7 /C4 AvXC^v-z{_i[*PR?8Vҙ9IENDB`perfbook_html/node443.html0000644000175000017500000000754011672746163015654 0ustar paulmckpaulmck E.7.2 Validating Preemptible RCU and dynticks


E.7.2 Validating Preemptible RCU and dynticks

This section develops a Promela model for the interface between dynticks and RCU step by step, with each of the following sections illustrating one step, starting with the process-level code, adding assertions, interrupts, and finally NMIs.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img140.png0000644000175000017500000001314711672746074015316 0ustar paulmckpaulmckPNG  IHDRS_ ffPLTE$8D6Sfl{{{mmmgggMMM*3Q}c''' "HoZ~xxxtttZZZ @@@?aw444u݇tRNS@fIDATx]¬r3$&F%C Jߜ{S,ˢ6 @R?$b;Yа%21晇2 qv3UԽMϻZޞaU{b7zTSs~"&؅u "d0[3`S"D7=Ɗ 5hPCzd"2 ϩcd8Iú=V~!EˇN$\NpzA7ר@/I@&@E _8S aN=mt4Fw3n϶F0ٝZ^8NN_m$[+ <;;:M*a:sCZ=6S/C?l@%*@|w|(F4'7xn+0*xYƫYLlĴdY2SϘJ?W [0e9+ŁW-l u/o6SԞ %=|$[s"&.lclqUgZ'NI%mc OVss OQ'%c^UOܪxKrƭ*Z[nօ[j]ZnV&hEŮ8wC=&jh|o'jZ}I@h> l-p`+dcnDk[P@ZiԨV SnFԨzqA nuooՋ%nκ as)=~ r;F7+ KxcB('E$S(WKe9 )38ݤo哇` cSyqbPɠǾb.nmabx# "'AR19H(0lvU##-*K65J Ao1m =aJ}V58_\Ʀ3d4905amN2hA_t6g%rII%;FP#@LtD&/Rw=[g<ju IHZSz`k{5>iMJZR1#R.%:*M|=ӂ+"uSYKYsYWQp #r) "aT '=?j_`)-aāf$'/"#m aϪtsK\kBO QL !&EQq۝U 4`m^4pšM暗&%sYf8BN sUl)4i, 5z~0󽏣J-1LN7\T\%٪FcՎU1,BkU/T3cLx^Țɦ[7'D7` 6ג(^JW 27SlYN[3t'R ot5Vʪb gn٤xT 7xs9fƬ]5[z++ٚFcu֗>f-dO/۫Q=4bSzu;nCmw>>x=NϦeF%6<jn4nP}}J,)Qq}JQ/)*tJU>< .]􂫬xU=Lck+&k"xNِ=W /0/ً| F@Ԗ0a-s  (SP OZ]O"֛9F@J|=qXّ0֟Ij5]uKapF0zL0]93)ԫ3覆Og2HkY(d*A٦w.diԩe)%u95]v'm_@NMW23zbOZ5g>|++)?IncR\ГFsyQKk2 Ciٞe+1dz.ydUKi jk24lJPj9>q[ Őܸ&8cf+26GuPh4~()d|vJa]_gթo]; z.}M4}1xJ/ ̭=aYhf$O Ni0v'`3V\MI}/iDII+pFXVd_5a1SNNMܬYCӎq8jӎzBM!Ni'ʥ$8Zarehgw\J"*uis%q~',s>։2J$J7;ݩZoLr U|u]NaZ+THu tOi"/s:IQ#_9Ȯ~l7G>9f'oB+T"WwH;gNye9PeFKfdhm.byNgr%TA'q`WV<gMaGqv^W"z(B='IJwyF\Ԏy{Tx"Κ:Bk^8iE{5'ڪ8H8qUx%2S 'кA(?lgWΟ MM).@,$_LR>_a.g]ZNXx$89E)L96RN^ Z("ًw-ͬu,ҩʋ҅*1d-\,6-J7ljE`22nDyZxʈ˦Y+Pj"H5,1JNo&}zȌ;*DoI$qM׽"qMMhr5ҢCu2NUEi_\W}8ΒMWe i&AVZtg;y_C&nf)MY}\EhvD^ҷv{8κҝTuՇQu%5F On< NeF]ހRLoŠuD܇A+rHtm(}*Q9QmϦᇁ{؏t<<Ot<<OM<%&IX%jݯw(zOZzx"Whn:^Ѧӭ j1T+ $ެ:C+u3-o W͛|8ߤPՉ>_5wQHD?ս"BL-V65jЮIw)XtKA*SI*k_zVS}gY)pM& jA!Tu*gLq_<%hРӾO< 5h,`έqenۨpa/kW9ѡ3Qi%#I9xh5ɓ(ԧD@^B:nee>廿~eMT9{AaǮ*ڕ ;}A{vݭ׺=h5~/Խ-Hv'kׁ멼ISVO`ԫJ iu^hWGSKԘӇuLz~l{S3~{+?QT s).Vro~/;wը7ƳC`p55; ߄NF|)ȑҟحs9Y4*L!oJ--L6D#j6DmN4*xVL )r?g/DEU6TQ}qۗuؤRr;.{y[#]m!Uq݅:ڴt|f*/SY#F( '5 ϲ8_OF\vt| n~/]a|T'.L(I=ӂ.;pbjdїeK)3D߱2/S}kOm<5.R 'y:RXGD_3p]ˏ̼c<]rv/L4S.Ѫt"=hfg1o5.oN< NfrƳ~2ɩ+SWd3[^2/qqϡɽ6.yU{y\|>OiPpv(܅Dln›T{Ԡ)xzޢVRcJޢWc/ٗ `794ڤ&5@щFЌk?v?IENDB`perfbook_html/img149.png0000644000175000017500000001622611672745764015335 0ustar paulmckpaulmckPNG  IHDR(GR|2EPLTEb``TRRMJK# hffmkkXUVVST856C@@wuv.*+[YZˍtRNS@fIDATx] R VL?́b$&awyvD ̡>v}J+uKԨ aAƇ6Jp9V'B^hlN%" uۓOF5XM VhwJu_̪xY5ͩZ1j<$ۇ]a SOӨi)h]σFe@?ҪW\иu[/jNsP|t{C]p1N K2 O:u3Ї٘`::I^X½PMgn@y"Q\BrZ.P7nWt}=@!: 1Z#9ua' Wt-;0!~ Q]:EfstDI V|μ8˼W8~'qByT?5j )Q?0Gv7HM CXa9Q^ӮxCwLM+{S~>'NB}W s&pgo}g@.wIi"Κv$Odh~}\}FnگҘn2)["1;Vը)myYK~Um1' ih,f. V6\t:WZS{~W;IuYD4cMj]l?ІxpKc:yTYҳ8ӑ di2 0*~>^V!vDN_ݢԁlgeiGn_Ojxag #K)U3͍,vŞ킨Mdߍ8uű6@r6";B 2 5-.viGIBXWܡVa̋ήw5n_xTSqpBoQ}XH[|TyǤ 9 <4ݝrd1fXX.1j3PJNtVY:4 sC+< inh꿸bC6AnGUFlO3#ϫ8nM#YO:?R}YH+C\UDe"6e.߁*8Lg]C JNk7*h;sc]k_nzNGpNlub}~l֭QmWcuzEnZက[7,?ӧ^pm_@2cnWU!C'l꿉:e/"fmhf[Ӈ7U@e 7Q&^Gٰ[%0遖|{5[ͼLho*];yQnXpiN!|'A!la _ET>5I(F<4^ygv@rju Rnhݣ^4u&~|)b!6,QX׿3Œ.#wC/,gk4GGDS[ʜp;SAuf Qo䜫x8MɩQY|r:C[]_ sL.qmU)y˂K֘U_"JE jqӻJK:)0Q?Tя,dhnD1i~}MVаيn3-[煉*!{7q, +#4ö &ƌ;%ȫ$5scMSBE24fF0<:6zӺARcR}hRXk}]껢PgK>CO ppzUEkK#pALqs@A<V1oĶvJ;\}g'4Mz4g߆ױ@G[Wҙ;"vኦ2=>QQ.={ ]4;%xTMIuk|P+tM>ѐA|ED7=j\맖g:۪a۔w2N]/Sw[Į[wvǵF fSm?~}o3Fv.~D@mFXG/;7GZ6ʗu'k)#RDOԚǺX:+#\aF*!!npwF! ŚrgkF ampR%b>"RZX-Sk *%s2+wLpYͩRv ;v "٠.ǔֲEv/;#q96*˞*Ѹ{1hm} 1 :EKNwc=. :*IXjh^:Fb{˖,rSL4 YcGQ0gW4Gs*9#Wdg/I3aua4`>f=u<ЙTnƩQܭVTZ -e&|#0Sh2k EMWcf.*+~KO$??m%ݜalc|!̶PǩtV q ׍5@gZ,@q-e^%=a%>\/K ެW_e\[lKh̲eS[S~M,-yk Xb^vv}]QDNQJz£hRć)m8ŀGA6 ~*(,|^Ĝ0g!mm ([$PXjWpn7˻ ԅ.I|k/j떔Ujr ӯ׹I4Un昽=iw;ձ7ky|2 TNS5*dh #LtHę{iaJ q櫉3BH%u ]["`t&TAImE· ,D?B&ܹQy;_!)ʍJVAQh,j{FfmsNMvIG SK296}g ^6f;.бNi:CRûcĥr!Xl n8 c}] J7,]b_7}TeB1}b/Z2U2OSJ%MNy a\AضaAʙ'Gr[Fw͙S5(rob~'Cz}R. `s n02"atz1 ;9Eg%;0U̯jFnI̚/fWJyȫՊ/0d㱖֣c8(gC+u&oEcQclZ Ï6OͥjJ 4 o 3 oeҗ(* ]VڴXzWJj]gD zCBwb`7Q0<+(( ՓVdDuGbnkBr%Wc=j)Q]&OsLQA/ʼni|k-Ral(mY6b"Elՠxie}$J%IE0~Qj<6r&P4tA[INKΟ3r 1 1Q6tK/3 oV5(2|'*er('L rGQ?Y NV?7A}lo2,vE~"C–i{Uva+5W@4&%pp \!u(=1]/R(;ʤ1y,PLl8k& ˳Z8m8pV7B+&-fz{uzf)Ό: (  uf+XeKG]=}s-j"=;FXuG]730]^-%ـH||ʋ u qze'Y/ImP` }% t2W:Z\"[96(84zF|v+r6vvz%Ya%D2 (I_ 7В;e{B}:vՅ\wHdT{+&rBĂD"6WPAԺ*`ha?NR~)=JUf!ޕ== ^#Z@S۳@B2~T蜮MFf= Lm."(F#6./H\geAu:L$\hX:8-w*?-zM(7ٴo|@TI(ݲ (u tH:y$~[=΋}FfhY(^^RsgFXgdvZ$>/iS~*ͩ`Ǔ΋Cac/^- W)͔GjUMyqM;kI(:ms3/0n &K].vj$? tD|İ`kh*xD[Q Ђ=Xď*3 ZPP0^mUb;X:H\>{wW t# JĂ!VaY麟 &W?E:+(aH(6n'XMTl%@(PX\R ?b7 ɮ!^kNs2,I%4騄đilĝK"T23"NC{1 &oS@ 7Qm '鏉~~/S¸ MBx t:0\iv!UphEs@ObN}M3*\s4}N>a3#MƞQ.uK܉Q$Yg0gBC:|9jJ7gJ9\:+7I!k8źI t$1;rGnNEcҜ7?Nӌ?8F{t~( EU6iN ayś޷g g /G͐GUeWcQe=q<`QZzd3g[$en~A(ޛ/k7lcL)Qʤ޷䒛 YueUVԴ,[cY{KҬYX&A8MEB1Io @g)Us7F6NLM8GGWH6Cࠜ|rAދQQN fY@Tm~9e.+hᝎ.Iq*Ofu'^%g6;,cYؾQY!x3MlRϿkʝk} w͂0'=1`R_`3.M ATotۇ *ctu*:=o%Xl~<X戵UpI%J?0EաIENDB`perfbook_html/node138.html0000644000175000017500000001661611672746162015660 0ustar paulmckpaulmck 10.3.2.1.4 RCU Readers and Updaters Run Concurrently

10.3.2.1.4 RCU Readers and Updaters Run Concurrently

Because RCU readers never spin nor block, and because updaters are not subject to any sort of rollback or abort semantics, RCU readers and updaters must necessarily run concurrently. This means that RCU readers might access stale data, and might even see inconsistencies, either of which can render conversion from reader-writer locking to RCU non-trivial.

Figure: Response Time of RCU vs. Reader-Writer Locking
\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUupdate}}

However, in a surprisingly large number of situations, inconsistencies and stale data are not problems. The classic example is the networking routing table. Because routing updates can take considerable time to reach a given system (seconds or even minutes), the system will have been sending packets the wrong way for quite some time when the update arrives. It is usually not a problem to continue sending updates the wrong way for a few additional milliseconds. Furthermore, because RCU updaters can make changes without waiting for RCU readers to finish, the RCU readers might well see the change more quickly than would batch-fair reader-writer-locking readers, as shown in Figure [*].

Once the update is received, the rwlock writer cannot proceed until the last reader completes, and subsequent readers cannot proceed until the writer completes. However, these subsequent readers are guaranteed to see the new value, as indicated by the green background. In contrast, RCU readers and updaters do not block each other, which permits the RCU readers to see the updated values sooner. Of course, because their execution overlaps that of the RCU updater, all of the RCU readers might well see updated values, including the three readers that started before the update. Nevertheless only the RCU readers with green backgrounds are guaranteed to see the updated values, again, as indicated by the green background.

Reader-writer locking and RCU simply provide different guarantees. With reader-writer locking, any reader that begins after the writer begins is guaranteed to see new values, and any reader that attempts to begin while the writer is spinning might or might not see new values, depending on the reader/writer preference of the rwlock implementation in question. In contrast, with RCU, any reader that begins after the updater completes is guaranteed to see new values, and any reader that completes after the updater begins might or might not see new values, depending on timing.

The key point here is that, although reader-writer locking does indeed guarantee consistency within the confines of the computer system, there are situations where this consistency comes at the price of increased inconsistency with the outside world. In other words, reader-writer locking obtains internal consistency at the price of silently stale data with respect to the outside world.

Nevertheless, there are situations where inconsistency and stale data within the confines of the system cannot be tolerated. Fortunately, there are a number of approaches that avoid inconsistency and stale data [McK04,ACMS03], and some methods based on reference counting are discussed in Section [*].

Paul E. McKenney 2011-12-16
perfbook_html/node94.html0000644000175000017500000001063211672746162015571 0ustar paulmckpaulmck 7.4.3.1 Parallel Resource Allocation Problem

7.4.3.1 Parallel Resource Allocation Problem

The basic problem facing a parallel memory allocator is the tension between the need to provide extremely fast memory allocation and freeing in the common case and the need to efficiently distribute memory in face of unfavorable allocation and freeing patterns.

To see this tension, consider a straightforward application of data ownership to this problem -- simply carve up memory so that each CPU owns its share. For example, suppose that a system with two CPUs has two gigabytes of memory (such as the one that I am typing on right now). We could simply assign each CPU one gigabyte of memory, and allow each CPU to access its own private chunk of memory, without the need for locking and its complexities and overheads. Unfortunately, this simple scheme breaks down if an algorithm happens to have CPU 0 allocate all of the memory and CPU 1 the free it, as would happen in a simple producer-consumer workload.

The other extreme, code locking, suffers from excessive lock contention and overhead [MS93].

Paul E. McKenney 2011-12-16
perfbook_html/node13.html0000644000175000017500000001300111672746161015550 0ustar paulmckpaulmck 3.3.3 Performance Optimization


3.3.3 Performance Optimization

Up through the early 2000s, CPU performance was doubling every 18 months. In such an environment, it is often much more important to create new functionality than to do careful performance optimization. Now that Moore's Law is ``only'' increasing transistor density instead of increasing both transistor density and per-transistor performance, it might be a good time to rethink the importance of performance optimization.

After all, performance optimization can reduce power consumption as well as increasing performance.

From this viewpoint, parallel programming is but another performance optimization, albeit one that is becoming much more attractive as parallel systems become cheaper and more readily available. However, it is wise to keep in mind that the speedup available from parallelism is limited to roughly the number of CPUs, while the speedup potentially available from straight software optimization can be multiple orders of magnitude.

Furthermore, different programs might have different performance bottlenecks. Parallel programming will only help with some bottlenecks. For example, suppose that your program spends most of its time waiting on data from your disk drive. In this case, making your program use multiple CPUs is not likely to gain much performance. In fact, if the program was reading from a large file laid out sequentially on a rotating disk, parallelizing your program might well make it a lot slower. You should instead add more disk drives, optimize the data so that the file can be smaller (thus faster to read), or, if possible, avoid the need to read quite so much of the data.

Quick Quiz 3.11: What other bottlenecks might prevent additional CPUs from providing additional performance? End Quick Quiz

Parallelism can be a powerful optimization technique, but it is not the only such technique, nor is it appropriate for all situations. Of course, the easier it is to parallelize your program, the more attractive parallelization becomes as an optimization. Parallelization has a reputation of being quite difficult, which leads to the question ``exactly what makes parallel programming so difficult?''

Paul E. McKenney 2011-12-16
perfbook_html/node450.html0000644000175000017500000002640011672746163015646 0ustar paulmckpaulmck E.7.2.7 Validating NMI Handlers


E.7.2.7 Validating NMI Handlers

We take the same general approach for NMIs as we do for interrupts, keeping in mind that NMIs do not nest. This results in a dyntick_nmi() process as follows:

  1 proctype dyntick_nmi()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   bit old_gp_idle;
  6
  7   do
  8   :: i >= MAX_DYNTICK_LOOP_NMI -> break;
  9   :: i < MAX_DYNTICK_LOOP_NMI ->
 10     in_dyntick_nmi = 1;
 11     if
 12     :: rcu_update_flag > 0 ->
 13       tmp = rcu_update_flag;
 14       rcu_update_flag = tmp + 1;
 15     :: else -> skip;
 16     fi;
 17     if
 18     :: !in_interrupt &&
 19        (dynticks_progress_counter & 1) == 0 ->
 20       tmp = dynticks_progress_counter;
 21       dynticks_progress_counter = tmp + 1;
 22       tmp = rcu_update_flag;
 23       rcu_update_flag = tmp + 1;
 24     :: else -> skip;
 25     fi;
 26     tmp = in_interrupt;
 27     in_interrupt = tmp + 1;
 28     old_gp_idle = (grace_period_state == GP_IDLE);
 29     assert(!old_gp_idle || grace_period_state != GP_DONE);
 30     tmp = in_interrupt;
 31     in_interrupt = tmp - 1;
 32     if
 33     :: rcu_update_flag != 0 ->
 34       tmp = rcu_update_flag;
 35       rcu_update_flag = tmp - 1;
 36       if
 37       :: rcu_update_flag == 0 ->
 38         tmp = dynticks_progress_counter;
 39         dynticks_progress_counter = tmp + 1;
 40       :: else -> skip;
 41       fi;
 42     :: else -> skip;
 43     fi;
 44     atomic {
 45       i++;
 46       in_dyntick_nmi = 0;
 47     }
 48   od;
 49   dyntick_nmi_done = 1;
 50 }

Of course, the fact that we have NMIs requires adjustments in the other components. For example, the EXECUTE_MAINLINE() macro now needs to pay attention to the NMI handler (in_dyntick_nmi) as well as the interrupt handler (in_dyntick_irq) by checking the dyntick_nmi_done variable as follows:

  1 #define EXECUTE_MAINLINE(label, stmt) \
  2 label: skip; \
  3     atomic { \
  4       if \
  5       :: in_dyntick_irq || \
  6          in_dyntick_nmi -> goto label; \
  7       :: else -> stmt; \
  8       fi; \
  9     } \

We will also need to introduce an EXECUTE_IRQ() macro that checks in_dyntick_nmi in order to allow dyntick_irq() to exclude dyntick_nmi():

  1 #define EXECUTE_IRQ(label, stmt) \
  2 label: skip; \
  3     atomic { \
  4       if \
  5       :: in_dyntick_nmi -> goto label; \
  6       :: else -> stmt; \
  7       fi; \
  8     } \

It is further necessary to convert dyntick_irq() to EXECUTE_IRQ() as follows:

  1 proctype dyntick_irq()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   byte j = 0;
  6   bit old_gp_idle;
  7   bit outermost;
  8
  9   do
 10   :: i >= MAX_DYNTICK_LOOP_IRQ &&
 11      j >= MAX_DYNTICK_LOOP_IRQ -> break;
 12   :: i < MAX_DYNTICK_LOOP_IRQ ->
 13     atomic {
 14       outermost = (in_dyntick_irq == 0);
 15       in_dyntick_irq = 1;
 16     }
 17 stmt1: skip;
 18     atomic {
 19       if
 20       :: in_dyntick_nmi -> goto stmt1;
 21       :: !in_dyntick_nmi && rcu_update_flag ->
 22         goto stmt1_then;
 23       :: else -> goto stmt1_else;
 24       fi;
 25     }
 26 stmt1_then: skip;
 27     EXECUTE_IRQ(stmt1_1, tmp = rcu_update_flag)
 28     EXECUTE_IRQ(stmt1_2, rcu_update_flag = tmp + 1)
 29 stmt1_else: skip;
 30 stmt2: skip;  atomic {
 31       if
 32       :: in_dyntick_nmi -> goto stmt2;
 33       :: !in_dyntick_nmi &&
 34          !in_interrupt &&
 35          (dynticks_progress_counter & 1) == 0 ->
 36            goto stmt2_then;
 37       :: else -> goto stmt2_else;
 38       fi;
 39     }
 40 stmt2_then: skip;
 41     EXECUTE_IRQ(stmt2_1, tmp = dynticks_progress_counter)
 42     EXECUTE_IRQ(stmt2_2,
 43       dynticks_progress_counter = tmp + 1)
 44     EXECUTE_IRQ(stmt2_3, tmp = rcu_update_flag)
 45     EXECUTE_IRQ(stmt2_4, rcu_update_flag = tmp + 1)
 46 stmt2_else: skip;
 47     EXECUTE_IRQ(stmt3, tmp = in_interrupt)
 48     EXECUTE_IRQ(stmt4, in_interrupt = tmp + 1)
 49 stmt5: skip;
 50     atomic {
 51       if
 52       :: in_dyntick_nmi -> goto stmt4;
 53       :: !in_dyntick_nmi && outermost ->
 54         old_gp_idle = (grace_period_state == GP_IDLE);
 55       :: else -> skip;
 56       fi;
 57     }
 58     i++;
 59   :: j < i ->
 60 stmt6: skip;
 61     atomic {
 62       if
 63       :: in_dyntick_nmi -> goto stmt6;
 64       :: !in_dyntick_nmi && j + 1 == i ->
 65         assert(!old_gp_idle ||
 66                grace_period_state != GP_DONE);
 67       :: else -> skip;
 68       fi;
 69     }
 70     EXECUTE_IRQ(stmt7, tmp = in_interrupt);
 71     EXECUTE_IRQ(stmt8, in_interrupt = tmp - 1);
 72
 73 stmt9: skip;
 74     atomic {
 75       if
 76       :: in_dyntick_nmi -> goto stmt9;
 77       :: !in_dyntick_nmi && rcu_update_flag != 0 ->
 78         goto stmt9_then;
 79       :: else -> goto stmt9_else;
 80       fi;
 81     }
 82 stmt9_then: skip;
 83     EXECUTE_IRQ(stmt9_1, tmp = rcu_update_flag)
 84     EXECUTE_IRQ(stmt9_2, rcu_update_flag = tmp - 1)
 85 stmt9_3: skip;
 86     atomic {
 87       if
 88       :: in_dyntick_nmi -> goto stmt9_3;
 89       :: !in_dyntick_nmi && rcu_update_flag == 0 ->
 90         goto stmt9_3_then;
 91       :: else -> goto stmt9_3_else;
 92       fi;
 93     }
 94 stmt9_3_then: skip;
 95     EXECUTE_IRQ(stmt9_3_1,
 96       tmp = dynticks_progress_counter)
 97     EXECUTE_IRQ(stmt9_3_2,
 98       dynticks_progress_counter = tmp + 1)
 99 stmt9_3_else:
100 stmt9_else: skip;
101     atomic {
102       j++;
103       in_dyntick_irq = (i != j);
104     }
105   od;
106   dyntick_irq_done = 1;
107 }

Note that we have open-coded the ``if'' statements (for example, lines 17-29). In addition, statements that process strictly local state (such as line 58) need not exclude dyntick_nmi().

Finally, grace_period() requires only a few changes:

  1 proctype grace_period()
  2 {
  3   byte curr;
  4   byte snap;
  5   bit shouldexit;
  6
  7   grace_period_state = GP_IDLE;
  8   atomic {
  9     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);
 10     printf("MDLI = %d\n", MAX_DYNTICK_LOOP_IRQ);
 11     printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NMI);
 12     shouldexit = 0;
 13     snap = dynticks_progress_counter;
 14     grace_period_state = GP_WAITING;
 15   }
 16   do
 17   :: 1 ->
 18     atomic {
 19       assert(!shouldexit);
 20       shouldexit = dyntick_nohz_done &&
 21              dyntick_irq_done &&
 22              dyntick_nmi_done;
 23       curr = dynticks_progress_counter;
 24       if
 25       :: (curr - snap) >= 2 || (curr & 1) == 0 ->
 26         break;
 27       :: else -> skip;
 28       fi;
 29     }
 30   od;
 31   grace_period_state = GP_DONE;
 32   grace_period_state = GP_IDLE;
 33   atomic {
 34     shouldexit = 0;
 35     snap = dynticks_progress_counter;
 36     grace_period_state = GP_WAITING;
 37   }
 38   do
 39   :: 1 ->
 40     atomic {
 41       assert(!shouldexit);
 42       shouldexit = dyntick_nohz_done &&
 43              dyntick_irq_done &&
 44              dyntick_nmi_done;
 45       curr = dynticks_progress_counter;
 46       if
 47       :: (curr != snap) || ((curr & 1) == 0) ->
 48         break;
 49       :: else -> skip;
 50       fi;
 51     }
 52   od;
 53   grace_period_state = GP_DONE;
 54 }

We have added the printf() for the new MAX_DYNTICK_LOOP_NMI parameter on line 11 and added dyntick_nmi_done to the shouldexit assignments on lines 22 and 44.

The model (dyntickRCU-irq-nmi-ssl.spin) results in a correct verification with several hundred million states, passing without errors.

Quick Quiz E.18: Does Paul always write his code in this painfully incremental manner? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node51.html0000644000175000017500000002413511672746161015564 0ustar paulmckpaulmck 6. Counting


6. Counting

Counting is perhaps the simplest and most natural for a computer to do. However, counting efficiently and scalably on a large shared-memory multiprocessor can be quite challenging. Furthermore, the simplicity of the underlying concept of counting allows us to explore the fundamental issues of concurrency without the distractions of elaborate data structures or complex synchronization primitives. Counting therefore provides an excellent introduction to parallel programming.

This chapter covers a number of special cases for which there are simple, fast, and scalable counting algorithms. But first, let us find out how much you already know about concurrent counting.

Quick Quiz 6.1: Why on earth should efficient and scalable counting be hard? After all, computers have special hardware for the sole purpose of doing counting, addition, subtraction, and lots more besides, don't they??? End Quick Quiz

Quick Quiz 6.2: Network-packet counting problem. Suppose that you need to collect statistics on the number of networking packets (or total number of bytes) transmitted and/or received. Packets might be transmitted or received by any CPU on the system. Suppose further that this large machine is capable of handling a million packets per second, and that there is a systems-monitoring package that reads out the count every five seconds. How would you implement this statistical counter? End Quick Quiz

Quick Quiz 6.3: Approximate structure-allocation limit problem. Suppose that you need to maintain a count of the number of structures allocated in order to fail any allocations once the number of structures in use exceeds a limit (say, 10,000). Suppose further that these structures are short-lived, that the limit is rarely exceeded, and that a ``sloppy'' approximate limit is acceptable. End Quick Quiz

Quick Quiz 6.4: Exact structure-allocation limit problem. Suppose that you need to maintain a count of the number of structures allocated in order to fail any allocations once the number of structures in use exceeds an exact limit (say, 10,000). Suppose further that these structures are short-lived, and that the limit is rarely exceeded, that there is almost always at least one structure in use, and suppose further still that it is necessary to know exactly when this counter reaches zero, for example, in order to free up some memory that is not required unless there is at least one structure in use. End Quick Quiz

Quick Quiz 6.5: Removable I/O device access-count problem. Suppose that you need to maintain a reference count on a heavily used removable mass-storage device, so that you can tell the user when it is safe to removed the device. This device follows the usual removal procedure where the user indicates a desire to remove the device, and the system tells the user when it is safe to do so. End Quick Quiz

The remainder of this chapter will develop answers to these questions.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img314.png0000644000175000017500000000000011672746010021635 1perfbook_html/img262.pngustar paulmckpaulmckperfbook_html/node133.html0000644000175000017500000002415211672746162015645 0ustar paulmckpaulmck 10.3.2 RCU Usage


10.3.2 RCU Usage


Table: RCU Usage
Mechanism RCU Replaces Section
Reader-writer locking Section [*]
Restricted reference-counting mechanism Section [*]
Bulk reference-counting mechanism Section [*]
Poor man's garbage collector Section [*]
Existence Guarantees Section [*]
Type-Safe Memory Section [*]
Wait for things to finish Section [*]


This section answers the question "what is RCU?" from the viewpoint of the uses to which RCU can be put. Because RCU is most frequently used to replace some existing mechanism, we look at it primarily in terms of its relationship to such mechanisms, as listed in Table [*]. Following the sections listed in this table, Section [*] provides a summary.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img25.png0000644000175000017500000001633411672746130015232 0ustar paulmckpaulmckPNG  IHDR]9s43_BPLTEQNOMJK# b`ab``mkkcaaXUV856KHHC@@wuv.*+rpp9tRNS@fHIDATx]*eWXdXuIU[muΛk)"c1&>-h[Ti 2E9SqX&Xb\Y_'wh·;n12fU\sX; "$be_x ZGh=|p[PZ/;䡞& Ky*,CxMU; Lpv_Q7Åz;TVO>^UԎ}FNWwXo|V}DŸ X1଩Bu|I;uo}[ h>$SP?iiG7~%ʶ9!% O/'q:E+;{>>ƾTX^MyMmA{#2e>LM9۟Һ$x R7䣸8m]heu{p#5/`|Lj,OS[c-4]^Q8 ZBVo;KՎv} й_Oc4:FVuR խjIq`8Fc0x h0с@]ݹQT9WSKW"§>5lsg_GV,t:Le}*h}ՠ^7ٱ(Aڻc S3 " 7 A67ѠpvWy2d6L[q: sp`Z359^qp $k},A^ q8O CJMKƗUջt46T a_x$ཾQCFbA?nb4Mg7M;i=~󾼇 Z;k0tAr;Ac.Hk A8ZК8`<\où?uK?S)L5﵋eE/TV+= |Po6q `),~h {X00 D;AQ\ C8^,gZ^ @߿iYKx<.Mhx0Z30,@ ;anJ$/FztCqN_:`_(ߴA4õ&Ytʻh8A}F4+X~&ePkFЫM3 tqK/N7=4Ө85cl Fp*0] w947}3+(}΀k4Z4*Ȍմ$ 7eh*s΀FrފAC%XEZWʋEU܄bz*~Ii=,\a@׸I$_bCCO-z©wvd̖؂|/L[xacڱL>~DqHɶ $H?6gSU@+x3Zs˭~۬""P!o6kS-_p-Komқsy M//J& CiE0MaXaD0KZ Ҳ/EW桸<2Ҽ Yt|q^[XTyĹj# yDKtu5(7R\֤m Q^Gȩ"%R;]3dၹM~Ɓy"X +bs)^ykE;Y 䖀&aa\ Ib& q $iE^0]jy"u\H"q@B˳ʠX\Ķ7Nx,9xCYß 7E|A t&I~WeFc.ԓݥѢ 3R(@6M%*#܋g  '/gQ=@_Yu5^w%݂#draVuj AE$썆9}lTw Et y؛ C5aWg\@dq}\UMx5X{{ >MJiҢ7 Bp!끜=O,squ7cjɏU9ǭBYOMh{D/Q"Uz3=imPÞq΀k!܀Sp 4l~Dv^-[W2w3g9Aw+\ule.җʶIfW򮬸b] ,9ci 󕠭G^Hfk[ͅr&:3 Hca[. v]E7Qmdh0i7݂O]ͧdS`dp1mgi#pF=G,dbHȓ&RDPqudY6bgB4(V2}0|y+rاA'A^2ƷD )'LvߚBuP,%k;ԜL[:ICh"LH9L;|Gӄ;6ɓ>9qNj HKgxO;k.b{1ւ3;zvW3a(~7!4of1#cNsϵзEvm%p wA.n ɏT+:]acr⍡huM:؝e%m=B doQ00Wk:I.h ㎂npShҴxvK婸riX̊% tR,.n|q&).COIQ(R$?(ZxiV ݳlC%p<aE$1OuKߖ3{GśRn .4!e⋖,@K?lF2|Z|K_ķ4 !.K_=β 1o vFQĦvf rHa'LMLw3hxܻ W o aS!ԽyRB 7c"j5Yf Y ޝ Ոǡ5ӢND/ 2,cZ9[f)AFPװW1Jo[PP Э sˁPMQB˭-[PPPs(}_lQKrުg}+F69 4o=r:z\eM`YSw_\-5@SAJ; 3ڼtSF`e5.o_ho7KF(5ou2|-DCxo`Czk42{ͫ\p4Hm8++9dkmnr&jї6cQε A7cwTﴔu1klX >׃[vyv{qHC[PP{lH >c,5+2) v̴ Pw\̎9_ vF 72}/`E`YpV+=]hvX!>JBo½#O%9PunJO$cJNXL M@4itYF,ߠh6B(־9ōp mڠ09,};_e-mgkVc6F7NN^e-С(k wu!'[;ne@+N:uvH4ЯQ4`5"+(('=9©Ӂ1r~dʶ̔Mw?:''O]< q19xaOtn͒T1Q ڽ'\γi\z5n%mwR?v+>߸2.|u ~5yi^ #̓ սr!:20_-5{4ļXE |⟳4:p{腍OetD2Q$ OĊB:M>YZNkؼCh#Ct'i0 rNA_$> 5cJ9ܻHA'km¬w.cE4IZ<ftٕ䗃"L@OٗeY(98p=7$8D ٯԯ2z~ ڹ*~LaH/4mxu̢1HoعgH@8ɉCG^4פ- 9Q7Z6pQ6=)x&:F|6=HLPӝ F8ի2FLqvᵅZV+Nf$ m{VEËr|^EsMbF^7Z6pMYwݡFّx\`1Nr3rWvMR?ic_AA$}l~ OlgLnS5j̿ ڥW"ȥhXZ)sQU "07Qf1-FΖ10h_XD;UC`_|x[kŋWAI_ʇ1yN%vzMyhz>1ہyb{Q ̣E`4O3gϿ"ڍksE\6xI D.3.8 Forcing Quiescent States


D.3.8 Forcing Quiescent States

Normally, CPUs pass through quiescent states which are duly recorded, so that grace periods end in a timely manner. However, any of the following three conditions can prevent CPUs from passing through quiescent states:

  1. The CPU is in dyntick-idle state, and is sleeping in a low-power mode. Although such a CPU is officially in an extended quiescent state, because it is not executing instructions, it cannot do anything on its own.
  2. The CPU is in the process of coming online, and RCU has been informed that it is online, but this CPU is not yet actually executing code, nor is it marked as online in cpu_online_map. The current grace period will therefore wait on it, but it cannot yet pass through quiescent states on its own.
  3. The CPU is running user-level code, but has avoided entering the scheduler for an extended time period.

In each of these cases, RCU needs to take action on behalf of the non-responding CPU. The following sections describe the functions that take such action. Section [*] describes the functions that record and recall the dynticks-idle grace-period number (in order to avoid incorrectly applying a dynticks-idle quiescent state to the wrong grace period), Section [*] describes functions that detect offline and holdout CPUs, Section [*] covers rcu_process_dyntick(), which scans for holdout CPUs, and Section [*] describes force_quiescent_state(), which drives the process of detecting extended quiescent states and forcing quiescent states on holdout CPUs.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node89.html0000644000175000017500000003730111672746162015577 0ustar paulmckpaulmck 7.3.5 Locking Granularity and Performance


7.3.5 Locking Granularity and Performance

This section looks at locking granularity and performance from a mathematical synchronization-efficiency viewpoint. Readers who are uninspired by mathematics might choose to skip this section.

The approach is to use a crude queueing model for the efficiency of synchronization mechanism that operate on a single shared global variable, based on an M/M/1 queue. M/M/1 queuing models are based on an exponentially distributed ``inter-arrival rate'' $\lambda$ and an exponentially distributed ``service rate'' $\mu$. The inter-arrival rate $\lambda$ can be thought of as the average number of synchronization operations per second that the system would process if the synchronization were free, in other words, $\lambda$ is an inverse measure of the overhead of each non-synchronization unit of work. For example, if each unit of work was a transaction, if each transaction took one millisecond to process, not counting synchronization overhead, then $\lambda$ would be 1,000 transactions per second.

The service rate $\mu$ is defined similarly, but for the average number of synchronization operations per second that the system would process if the overhead of each transaction was zero, and ignoring the fact that CPUs must wait on each other to complete their increment operations, in other words, $\mu$ can be roughly thought of as the synchronization overhead in absence of contention. For example, some recent computer systems are able to do an atomic increment every 25 nanoseconds or so if all CPUs are doing atomic increments in a tight loop.7.7The value of $\mu$ is therefore about 40,000,000 atomic increments per second.

Of course, the value of $\lambda$ increases with increasing numbers of CPUs, as each CPU is capable of processing transactions independently (again, ignoring synchronization):


\begin{displaymath}
\lambda = n \lambda_0
\end{displaymath} (7.1)

where $n$ is the number of CPUs and $\lambda_0$ is the transaction-processing capability of a single CPU. Note that the expected time for a single CPU to execute a single transaction is $1 / \lambda_0$.

Because the CPUs have to ``wait in line'' behind each other to get their chance to increment the single shared variable, we can use the M/M/1 queueing-model expression for the expected total waiting time:


\begin{displaymath}
T = \frac{1}{\mu - \lambda}
\end{displaymath} (7.2)

Substituting the above value of $\lambda$:


\begin{displaymath}
T = \frac{1}{\mu - n \lambda_0}
\end{displaymath} (7.3)

Now, the efficiency is just the ratio of the time required to process a transaction in absence of synchronization to the time required including synchronization:


\begin{displaymath}
e = \frac{1 / \lambda_0}{T + 1 / \lambda_0}
\end{displaymath} (7.4)

Substituting the above value for $T$ and simplifying:


\begin{displaymath}
e = \frac{\frac{\mu}{\lambda_0} - n}{\frac{\mu}{\lambda_0} - (n - 1)}
\end{displaymath} (7.5)

But the value of $\mu / \lambda_0$ is just the ratio of the time required to process the transaction (absent synchronization overhead) to that of the synchronization overhead itself (absent contention). If we call this ratio $f$, we have:


\begin{displaymath}
e = \frac{f - n}{f - (n - 1)}
\end{displaymath} (7.6)

Figure: Synchronization Efficiency
\resizebox{3in}{!}{\includegraphics{SMPdesign/synceff}}

Figure [*] plots the synchronization efficiency $e$ as a function of the number of CPUs/threads $n$ for a few values of the overhead ratio $f$. For example, again using the 25-nanosecond atomic increment, the $f=10$ line corresponds to each CPU attempting an atomic increment every 250 nanoseconds, and the $f=100$ line corresponds to each CPU attempting an atomic increment every 2.5 microseconds, which in turn corresponds to several thousand instructions. Given that each trace drops off sharply with increasing numbers of CPUs or threads, we can conclude that synchronization mechanisms based on atomic manipulation of a single global shared variable will not scale well if used heavily on current commodity hardware. This is a mathematical depiction of the forces leading to the parallel counting algorithms that were discussed in Chapter [*].

The concept of efficiency is useful even in cases having little or no formal synchronization. Consider for example a matrix multiply, in which the columns of one matrix are multiplied (via ``dot product'') by the rows of another, resulting in an entry in a third matrix. Because none of these operations conflict, it is possible to partition the columns of the first matrix among a group of threads, with each thread computing the corresponding columns of the result matrix. The threads can therefore operate entirely independently, with no synchronization overhead whatsoever, as is done in matmul.c. One might therefore expect a parallel matrix multiply to have a perfect efficiency of 1.0.

Figure: Matrix Multiply Efficiency
\resizebox{3in}{!}{\includegraphics{SMPdesign/matmuleff}}

However, Figure [*] tells a different story, especially for a 64-by-64 matrix multiply, which never gets above an efficiency of about 0.7, even when running single-threaded. The 512-by-512 matrix multiply's efficiency is measurably less than 1.0 on as few as 10 threads, and even the 1024-by-1024 matrix multiply deviates noticeably from perfection at a few tens of threads.

Quick Quiz 7.12: How can a single-threaded 64-by-64 matrix multiple possibly have an efficiency of less than 1.0? Shouldn't all of the traces in Figure [*] have efficiency of exactly 1.0 when running on only one thread? End Quick Quiz

Given these inefficiencies, it is worthwhile to look into more-scalable approaches such as the data locking described in Section [*] or the parallel-fastpath approach discussed in the next section.

Quick Quiz 7.13: How are data-parallel techniques going to help with matrix multiply? It is already data parallel!!! End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node299.html0000644000175000017500000002576711672746163015700 0ustar paulmckpaulmck C.2.4 MESI Protocol Example


C.2.4 MESI Protocol Example

Let's now look at this from the perspective of a cache line's worth of data, initially residing in memory at address 0, as it travels through the various single-line direct-mapped caches in a four-CPU system. Table [*] shows this flow of data, with the first column showing the sequence of operations, the second the CPU performing the operation, the third the operation being performed, the next four the state of each CPU's cache line (memory address followed by MESI state), and the final two columns whether the corresponding memory contents are up to date (``V'') or not (``I'').

Initially, the CPU cache lines in which the data would reside are in the ``invalid'' state, and the data is valid in memory. When CPU 0 loads the data at address 0, it enters the ``shared'' state in CPU 0's cache, and is still valid in memory. CPU 3 also loads the data at address 0, so that it is in the ``shared'' state in both CPUs' caches, and is still valid in memory. Next CPU 0 loads some other cache line (at address 8), which forces the data at address 0 out of its cache via an invalidation, replacing it with the data at address 8. CPU 2 now does a load from address 0, but this CPU realizes that it will soon need to store to it, and so it uses a ``read invalidate'' message in order to gain an exclusive copy, invalidating it from CPU 3's cache (though the copy in memory remains up to date). Next CPU 2 does its anticipated store, changing the state to ``modified''. The copy of the data in memory is now out of date. CPU 1 does an atomic increment, using a ``read invalidate'' to snoop the data from CPU 2's cache and invalidate it, so that the copy in CPU 1's cache is in the ``modified'' state (and the copy in memory remains out of date). Finally, CPU 1 reads the cache line at address 8, which uses a ``writeback'' message to push address 0's data back out to memory.


Table: Cache Coherence Example
CPU Cache Memory
Sequence # CPU # Operation 0 1 2 3 0 8
0 Initial State -/I -/I -/I -/I V V
1 0 Load 0/S -/I -/I -/I V V
2 3 Load 0/S -/I -/I 0/S V V
3 0 Invalidation 8/S -/I -/I 0/S V V
4 2 RMW 8/S -/I 0/E -/I V V
5 2 Store 8/S -/I 0/M -/I I V
6 1 Atomic Inc 8/S 0/M -/I -/I I V
7 1 Writeback 8/S 8/S -/I -/I V V


Note that we end with data in some of the CPU's caches.

Quick Quiz C.5: What sequence of operations would put the CPUs' caches all back into the ``invalid'' state? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img66.png0000644000175000017500000001746411672746026015250 0ustar paulmckpaulmckPNG  IHDRWWg!]PLTE$8D6SflgggMMM*3-EUQ}c''' "HoZ~tttZZZ @@@?aw444u݇jA,tRNS@fIDATx]b(Ĕ&zo>WDA 9w P . p5l5L.B0Q9$}l[Ur-}$TC{ ןe%/ u۰ /aH~Wk} {XD1)޺k̓KKN;{cdd{%gMeWB%bؗ,0fd먏(*= j/m{"0!`N5VѸo8%\?OkAmca&OϝlyVƅׅxA-= u|8*.b̼`\|[1!Ĭ{xdd˶뾄mM4,};Uq嶊 9կ`/}Œ0K~rdQDLļn_r=i]@6ȾZ~f?WN&OsNҽc_q2%Aaa0yNXlXkK.vpcb=DJؕ, P!oթeZmꖎE E=^}:*`qxZ,1bv+hN]X7Õ]7s}vId>_,^[~6/X\ ߓ7GU>`(9J$K˄U]:NNhލs=3*.JK#'yaϱjUŊ -i'³zBzAXMcj.0XG^bSx{L+!kz3XQqR4*J`1TBSl\j]~ Q1љbd\a2뷼h{]0@90U rv\ct6#D[){ ϐk}_zj5^#ਁɲXƜWٓv˟ g2^tzQLa1eF j]'uqTYU!y북yhYn8Y͜\,sX=^UlW &U*oktŬ?Svf)V4Nn.[{0n{@['])@ ╱A:v1@:846A3̘T̙.T{Qɘpy5IϬ g zݥZv JDU]n}`UgU9amCˈz\'Tb\͒hdufNrÞh[k)6)Şʩ쇘x$šz>A[] A0Vij@, UJ~$`1"pT,뢦8VbmjR,T^C|&2f?&>gžGb *bnf6 m{AKc$6 ˋmˍ[Gt㠋}y9Cڃ˭/Z?%su.j]Y,VdDHKMT ^Ҁsٮ(Orwm?X@4Eek鮘m~`kR뮘>ŎCi}(k,e`wtbI4b)`1H@o`حw$Ii_&k >D !Nq.zF nLlYz:<55&i"XΓ!S-]g8M4A5 ۬Zʵԭ\zQ Crpv>Bؤ sbvk'Zec3;N0F:kHR,vҲ)9ɯa0N&vKI 2/}Үum1<tp8:ľowW=|ۧ u[o;9Epʏj{C,BթUVX Tl1r(c5q쥽ILĻ b;wkS,F,8PR;@۬:݋=hթ $W{5xf3uG#z,?7G(#τ*CSQbxEty!"=xH:vYZ #ufTqQ8:AmzGr@L V:/gKP,DrDrbu"(,9c"u$XF|[kpbw_Wu,6Nk~ po:;6 {ȑPe Y;W]7m7 Pd&3|dz:T9+NH "t\ YF9ɰx ^`EDZ3HWv:Yuv!f謝>cB$&DY8vC~qMC'M*ŪˠsV)ɫ?hrvn[OEuU=uR[YqdXNYmb1&F֊:O^^y AZ߿՟/U 7y;r2*Wo}kJ j[,G*W6_ {' #*16P w%nZݠ.]Ŋ^xKr<_J,IbN *3NSZGeD}X1j-)Vk͗moԾQZ&cUPiMH-(U _GeDB$Rf ޴E\ Xﳥ;ZzĤu}sbjnZ~?כ֏򓀴t_w(LuZ_}?>JH!?/CҼpnOl= Z?wf7Z![zm}mC]ux@'Tb(7-,T"jH=a`v*% Zi @ԥ+3~=p@l8Fw U2S0Fb{"nU4_eʼnNۘ1[Eb9Aqۻ.!Jt yӿqb{"7k}foYUWj85Nؙ뫄|pS%huSOzՑ֗l?nZAS:AhM 9!^b;hyU&38ެuW6k@ӚQruWw*Z7MkbztuJkD(JG浫"Շ0fM#ӨZ ڗ:ͶͩIm[VfqM0jAR#:IB;vRO3GZ?JJC`}*a5*eZ%d$+iʧiXx>T&H=IE!;$(؍ZTkNÊ%B@sc3F "Q۵ܞ9=9uYwZUB: + 1GʳZO^T)OUYY "rD'Q#: ^?P+ݜq 璍]1*O Y}ip1i]?G ))Ɩ2dڌ{^nHn#_=cj_L!~L:Tϫx]nvsbO@!y5E,G9w=tu5ͪ-1;4֪+v&η<V7GKM'W7_|u-1z/'3[@UCa~c+K }N(+k0#U|݄~)[n+ z@tb&"D ^\0 W7_|u8n9|u8uVDtAjTF7 _mue~1yhd"Ov 3~i#7Ni>7""C7!$)͉yF$=;B[tb/@e~[h@LDRE"ӯqG RNǕ#i]Ŷ1:KOHˀ+čqW]KH}]2s"u #:<Le:l=>$RaeVkzg*"˨|x_K4S^c|u_c|uÁ @r3{sWn _<:v_B O_tkRoW)+jt/Rof辒BiIO+ʳ /o+߅z++2/wy]_xS*qф6..|%y.㽼s(|4;u)M\wm?_rDYOƯO v ys@, w+ W7_|uſtcۀ=hnv~}߾~?ުhξяnU|>׃^줒̸{x1Rx&n7au?s&Ukob[a/yyy]K =ICkՍ~|~FM?K,?Aa_hH㱹`z aAӅF悥 ZVFD{"| FMcesMo9G"VLn9C, 9[.F_׎xe-Q$Nr+Kc_;껜grH#fRz*i2$43[ը/#K2i*Wθ:)tڴ":O<} {} "{5i`ZWDDX}GD?@ֶ>:+sDD h؈a="W| F 1g#4~ɞηb:͏i~ &{b5zp̾G  "KY^B܀NV2~{C %)K[?}nDbaMZ,Q뫐t!Iw<;ǫ y`ٱ4'거D=ֈX|E%mAh}v{9GDZlQ5#*mS̐-'RIhY kV Ƙk +~]!z?\A!Q5 거!*(x,!q511zg*"˨|IPxhzFTr,xhcuI\'>7<v|OkXX9n\_K3IM襸ѭKQܤJNf?%=e4^_Q]%/o+߅zk5]]]_xqф)Kz=blﷱ? "4~EEi~L"we<-ĵvˈ>=k`DȞ}-&"J[j/ׅTf= NNi3:R lu/Y~rbP}}X \k}k5U4T_]bFB`ׄ/#7S_9^rb&Zdi[Z.UV־.&+ [FD_#Ѩj]=`Q-WG 1_QT\50Ddqw>FD􂈆1_ןDDNc)5&[:{+ _em bϓ#=Hm"Nj11Rm kBRMZ Q{i"_ԣa H G3 ꁰD=lRNǕ#iѰD4,Q 5$v`~\%vRGќD-ր+?1I/3"j_JHVMF5!NšԨ傅qV` h/g!n>JW7iŃM䉚 lkaA7'ٝPM૛BW'_`T B %ԛ1Vd1G(.bOG9.NQWnuŹf _<8%Ke}] Oʋ$b)_r㏼]3Vfu}]hLՖyJPγ.RSᤫ͞()I}/O6mٌ5 ogW7XoּvU IENDB`perfbook_html/node379.html0000644000175000017500000000612111672746163015656 0ustar paulmckpaulmck D.3.4 CPU Hotplug


D.3.4 CPU Hotplug

The CPU-hotplug functions described in the following sections allow RCU to track which CPUs are and are not present, but also complete initialization of each CPU's rcu_data structure as that CPU comes online.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node439.html0000644000175000017500000000745411672746163015665 0ustar paulmckpaulmck E.7.1 Introduction to Preemptible RCU and dynticks


E.7.1 Introduction to Preemptible RCU and dynticks

The per-CPU dynticks_progress_counter variable is central to the interface between dynticks and preemptible RCU. This variable has an even value whenever the corresponding CPU is in dynticks-idle mode, and an odd value otherwise. A CPU exits dynticks-idle mode for the following three reasons:

  1. to start running a task,
  2. when entering the outermost of a possibly nested set of interrupt handlers, and
  3. when entering an NMI handler.

Preemptible RCU's grace-period machinery samples the value of the dynticks_progress_counter variable in order to determine when a dynticks-idle CPU may safely be ignored.

The following three sections give an overview of the task interface, the interrupt/NMI interface, and the use of the dynticks_progress_counter variable by the grace-period machinery.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img139.png0000644000175000017500000001621411672746057015325 0ustar paulmckpaulmckPNG  IHDR8THPLTEb``^\\MJKZWW# gdeommmkkXUV856C@@wuv.*+-**rppD1ttRNS@fIDATx] Ń/n {2RD`>s"rZ qݳ\KVmZNNJawM+bLeO :kSwt i[-;.fJH$l?5\'3C'DL6zB"w)Bەyv_|qDk~ʐgOIo5%H'@I 06=]3gW3G/܋)8+ ȒVM9E!L~*HiqYgʼn:;`N0\1b8)vh 2^U?bνOQ4@ vN#gPt/s#3)z}7,hr֌ƪ lzYt*ccQ2XiQg,̀6>b-8䨬8=oٝ;Uӝg ]:QiKטLNYWl<{h0Q+ނQ_!ڹ亘UƼw=&Tm ӹ6h>[]XM Ye?5~Yw*Ek2".0?{Sp/CWIisUSW2չ;QTgG<<:-Jr[G:jDZ (yN1/ݡ~~VV#pͣjw1N 8cN}ıR]߉{^cGNY2P 1mz~_T2.~:?٩f<ԕw/KBuBY_dPCV:Jō/Ij +[c>OB&7 vJdy43fL&uqg1YJ^a{_J00B5&߈ϤygH|Jq?; }h~δ0>kz:E@-q Z<2:b pp x_O1TSHH^zVXJKf5j+|fUT9' 5QqDϦZ?--E4зwN$sgʺ(E,WD{묮)kQ(ʺnMZ}** N[ryKnt>ͶGw1!HHt*5\0C u'4Z]0ѐEKhE?tmM%{\HV_~|+ģUef1I͠ῄvKDs TI'ePb-M҅Wzj2OIg p5EBѬ6k\Fe)3^SB]zD9ϗ!`Ubh }Ͼ 9}dLřC| rr ܧ-t4r{ gq+GKq22OX/pFC0kjnx!27.[Rho0X 'M}o"D*4ITi RJ)l*Wa@be@W35p/_zi 3mτj5uN*"\_q:NFƪg;[PV-u߅iDߎ,|(3JzaA ` X<"d7 @ dI.xiQm?D3S M\G4x>}`$1JDo?}ˮ&&X`l,ʥw[0|lu-q(eX8Gj;M-cH zn=vVr'S y@\NQ(RLN5SRWKlO.&n9fi3)|\1O # D37z#l[WTH4J;+7(>z ;)kw>[.sD;SpӨMyjVFdK}y>ւG2-GmKXYV0.kA%%B\?].]L|x.,?p>ju &VEӔXLiJQ{<* ,׍SFTL)f>n+œB G0#\&44Y\Ojy kbrF7CS׆pr{v>`Z@8@^%?=k^V fΟK5+8'tGc9)8b@Vqp;01(:Y2r(vW;{S7ob9gbz_QUԺ$\zPrg]cj=v}Wخ:{Zm ~F7ʊĔIdvuϳ]9\a KW.lWfqv-x!OZ[>}! vRV R?IR}\j̊#Ô2G@P1cThrSHuz 6@]^Y@ K/JNZDn'c5\O%ӄ*dŮ4h.FJ^lMeVʶoT1ui8Hj-%kj>h3ҵl Nqɸ"4:_3Tn*EQ)הݥh\V} (2Ab+H B6_FE&N(XzyXUW2O@5.gDf}Ұddz~Rw罡8 2>vY j,ݵ3( []wI #m7{&E\h^jh !pá6;t#+b莱穉ox1!qSݒ함Y݅.qzX m>u 4| Q?&,{J2غP-AK ?,YKjZ!)bbpW\N|qm )I ~;rVg -~rk3_o< )Z ז}Z0.&I~tC2+X4 di2L HPnew;D= _^z-X8},P@f-^ TU]6OwrPDž|#qy1䬕a;1aBx9S<'׾xj<߂Bh949\0ݯJdp<sٵoO-jsk'ƲOA8&ixto#bP _{N'wBc3xzl=-O?b<@|tw 7v*qdGP9S.̝cΏ+= :PPPan䷣ߌ2?u'b%?0 0(ca(eygvނ7%|IoسOFW.S5<'b /`Zí/̏/a杳uSÅ}mWOO}}~D\_4 3_D 3_DO_Krm،a@z2zrz t/6s wx*Lj鷤j60|;f N2T QcS{hM|]ӔS*}V&;kH ѭogYE۽>ģ =y[dxq?5Aa<6mOq_s3Ǎ=ec? di?2ǥH}4'2~ŧ\p4GUnu)Pqu 8b~SϿ\hRDr/CA7]ĸj%yZa/SI?J]1 CWfF7m(Hv2Y[NA~1j3 z)fr3kNpn+;C?MyP ݱV(iVT-> {v4\ȷwŠӟdZ*( 4GYsw4җywV\&5OOu/r"sT9mocZ;VIm=\G< ^];tQ힐ɓ\J.N|F0ݫnnғM?c{'+ʌ?1 nO?[d䃍cˉLRT9{#@GR6{z'q'!{?a{v1eeeM2LiS}Lo;V&YY.]NONS䷓PpQ&΋#sHq}U5GJ; ?pPqfe]9ͻA2ʺ8;%o=+4*{ViOV>UKz>U. 08UKi*; ~%++LmͯkߗClu :_WP0JVւ`#3:JV)z%+B>ֻVʚq JVW8 <cVP2KssLH] -`opm'5n1_%L%G w@'TAԅ>]ۀ[+̛͹yp |8Ĉ|qJ%W"eLBA,#c%L{''y箫`fV^߽Xp}\ux)P~_KC6N1kmEfi!IX/)M+KL/IisĜ g,B[GE :uldȒ8d ^bzI{ B,1D `}h|Mko ᩔ Ѹ6oYpu*e{:;  C`׹q=++XQ=ysظ'S_so=gtu??w*!x~ܰe.xu6΄p$^\1'y(YYwy$1q%+xyJ(=JV=iLIgIENDB`perfbook_html/node422.html0000644000175000017500000000537211672746163015652 0ustar paulmckpaulmck D.4.3.3 Formal Validation


D.4.3.3 Formal Validation

Formal validation of this algorithm is quite important, but remains as future work. One tool for doing this validation is described in Appendix [*].

Quick Quiz D.64: What is a more precise way to say "CPU 0 might see CPU 1's increment as early as CPU 1's last previous memory barrier"? End Quick Quiz


Paul E. McKenney 2011-12-16
perfbook_html/node407.html0000644000175000017500000001223211672746163015646 0ustar paulmckpaulmck D.4.2.2.2 rcu_data


D.4.2.2.2 rcu_data

The rcu_data structure is a per-CPU structure, and contains the following fields:

  • lock guards the remaining fields in this structure.
  • completed is used to synchronize CPU-local activity with the global counter in rcu_ctrlblk.
  • waitlistcount is used to maintain a count of the number of non-empty wait-lists. This field is used by rcu_pending() to help determine if this CPU has any RCU-related work left to be done.
  • nextlist, nextail, waitlist, waittail, donelist, and donetail form lists containing RCU callbacks that are waiting for invocation at the end of a grace period. Each list has a tail pointer, allowing $O\left(1\right)$ appends. The RCU callbacks flow through these lists as shown below.
  • rcupreempt_trace accumulates statistics.

Figure: Preemptible RCU Callback Flow
\resizebox{1.5in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptLists}}

Figure [*] shows how RCU callbacks flow through a given rcu_data structure's lists, from creation by call_rcu() through invocation by rcu_process_callbacks(). Each blue arrow represents one pass by the grace-period state machine, which is described in a later section.

Paul E. McKenney 2011-12-16
perfbook_html/images.out0000644000175000017500000000000011672745743015567 0ustar paulmckpaulmckperfbook_html/img111.png0000644000175000017500000001305211672746141015302 0ustar paulmckpaulmckPNG  IHDRNHPLTEb``TRRMJK# hffywwmkkXUVMKK856iffC@@A>>wuv.*+rppjtRNS@fIDATx]*anplMĂKZYK:A,0:Y!b0FyrI hvlRUߥh2aHGm_z(E]O΃:NIشFN[u[.#f0Tl^\jUڸ5ү S\#C}~- G5RJXh5١ʈ֣-F8EPq:EG/'ĉJAd!L ]#* &!+kg+mhypJ4h \ &>1bbvD\Ӥ3_rd_3+ )^^ bHmì|hJ`7Ti̡o=^")ye1жmW VM?Vt#3%%ZAO5Emx#ܗf,y3z0uVeJP.[!6eK0 A媸T 0+BhCe3K>LHuekK)[ed@ uJ9 7${k*v˫,FYi[鴈,HP( ^Sv4* H<sPVjB2hƶd@ ӷ4IwC/vtt%]] &,9"ӳ};eף^yGPGnaarr4U_kx4ѷ/;14|]SM vR(|-N/3}YM+%G.VzT9sT'p*΁~HLʼn#*'{IWOBr&ce$֕dF{k,tNmoja3m܊IDṪF:%N"z 2Ġ`JdCRUߎgɌUSPt+6FZDWO"‚5l^rTZz5a7IjBu뚰?Bh lB|ӷL4dbi釳`M+wc%" C}UOJDJp}@fU"`p]lѢ}fygފ  Lj0lN&3 '܌Xto`%JH9hx'Ba^: ݱPgA{ %r+w>|d]LK/VgP[ve&Mdݑ3owdH?CԚjJ׏$ 0'`a\`͌~̱ c*9WDEHP)^՝enPcn6rkԋ9ZאAI*/(42])ீ?*5.ppL 8Oju Op.7n&[Ǵl3jNR05MK63u*ƍms.H8`L9^x%` (DYc疍Պ9!Xw:iF+LՒmĝ{uGQ1x;V= k6#M":eF>lwi;>gCGqK[Q&8 ZpW527x- n#:^q+UӠKBa'AܐMLGX׍= Hw26)vzgʻ֞p6!ZK"oV68D=_ sW4$W""+lZ|ݕAt5cE`NJm-8BkO 7ՁYSruqZzvYՉod".ʑ ڵjANev+ϋ(T7{azB'WEisRk)2OfU U&r\>}M[cu9/.ļ0ww誠*L< Ut9AlaĽ[m`#c3be(W!3NA( A0wcK8S.ֻb00Έe O`G?!'f!eC#(ke-zǢF8\Aa{2WPyBvSSKuBkbV JE D}0gWjj<7߬DҼpVujCU^C[R!Z9<,BvF<u;n*, QqGVp[emxа-Tb oN)Y t/oOJzђ M{ ÿ[M|+^Rx`>n+5pefǫ _#?v{5yk@7?Rs!XGo'%#G}hTyZ 3"k| 7 |j{1gҧ'|hmct5JGf|M!q0Aγs2B<1hf)cn9Ip?F̂W\[ c>v=A-͉3,fD,zwF?X6;kf3"<)e[[ 4;#*+ WX}c0ԔɟbO#DN͈b&[Z*[| dm#V:>^~&Oj#>|$mhw\(BdkVX>pwg4XYG&{ ݥԪl !HӢ K?JC[hRi\SM'6 IJoN| '`5jT&RStrT9H $w{N 2 6'ԧϣ†b \jO>~H7x2cTK|Q9}mMcdG8$ !ރI5/SK[0^3a5X%nSfݔ)ei'Y _(EڒVjZP9iS= TM#K (50LAUvBEמ^bAV | v6R1^RAx?g`^5<ȧןq$IovQV'e< Gɴ]nw_1WCz=aUqN wAmeV י6qi4Mxz/t+yZ`ͦkx[JSp 7j03=~\͜{Z\{ZjEVW^*;>:esؾj<(&EN,<zCol( \69\"+-$7RIF~N'+/BB"&ؙr?;V)mwNg@V/؜ܨ#'|O&:12/9Nvf"GtB؛[rCZ;VS12psRqGnz|!R1e}:|(~039:s"3Y^0JS[˘fl=O}tQ7|21eq2||5?ZLCzVAG!T S.xx'!=5LXݓH=W.ߋ${ R[PG}A i+wS~/> R v Emk 0W5UȊU(klubje=Nrv)ub"joo:PNSur)?ubMjiJN_ubzƁsu{RjvwCq0A(>̼$̒]M,ȹXO "ڐbcNYi :a愽X [pr KU'8, >8~ke[ <~;{]On9ʇ7 퐠j #vuS9 ?vvUe muہqBu殠Jj6#am[ wE`=d!?]U8(a]X'lǭ*gu{4b 'lǭe*g u{v.̥XLn$bPG;?!N"=?!A`u. =]xfT. {;qxsN9{A()УZC kTgVm1z~ Tʄ?#G,*͏>z$L~~0NllE'8`mh E$},Q \W$agC Cb\, @k8D ?^@'B>\cqNXw8WmxX߹:_I4:?achN9}|"jq~~sa):?!#9 _vM@y'd9 ɰϋ:pwN#1uT"{ݖuerqk^T!0ԲS_83oVqYjy]$VuYjyK<8K~>/3$IENDB`perfbook_html/node259.html0000644000175000017500000001530611672746162015657 0ustar paulmckpaulmck 17.1.10 Dynamic Linking and Loading


17.1.10 Dynamic Linking and Loading

Both lock-based critical sections and RCU read-side critical sections can legitimately contain code that invokes dynamically linked and loaded functions, including C/C++ shared libraries and Java class libraries. Of course, the code contained in these libraries is by definition unknowable at compile time. So, what happens if a dynamically loaded function is invoked within a transaction?

This question has two parts: (a) how do you dynamically link and load a function within a transaction and (b) what do you do about the unknowable nature of the code within this function? To be fair, item (b) poses some challenges for locking and RCU as well, at least in theory. For example, the dynamically linked function might introduce a deadlock for locking or might (erroneously) introduce a quiescent state into an RCU read-side critical section. The difference is that while the class of operations permitted in locking and RCU critical sections is well-understood, there appears to still be considerable uncertainty in the case of TM. In fact, different implementations of TM seem to have different restrictions.

So what can TM do about dynamically linked and loaded library functions? Options for part (a), the actual loading of the code, include the following:

  1. Treat the dynamic linking and loading in a manner similar to a page fault, so that the function is loaded and linked, possibly aborting the transaction in the process. If the transaction is aborted, the retry will find the function already present, and the transaction can thus be expected to proceed normally.
  2. Disallow dynamic linking and loading of functions from within transactions.

Options for part (b), the inability to detect TM-unfriendly operations in a not-yet-loaded function, possibilities include the following:

  1. Just execute the code: if there are any TM-unfriendly operations in the function, simply abort the transaction. Unfortunately, this approach makes it impossible for the compiler to determine whether a given group of transactions may be safely composed. One way to permit composability regardless is inevitable transactions, however, current implementations permit only a single inevitable transaction to proceed at any given time, which can severely limit performance and scalability. Inevitable transactions also seem to rule out use of manual transaction-abort operations.
  2. Decorate the function declarations indicating which functions are TM-friendly. These decorations can then be enforced by the compiler's type system. Of course, for many languages, this requires language extensions to be proposed, standardized, and implemented, with the corresponding time delays. That said, the standardization effort is already in progress [ATS09].
  3. As above, disallow dynamic linking and loading of functions from within transactions.

I/O operations are of course a known weakness of TM, and dynamic linking and loading can be thought of as yet another special case of I/O. Nevertheless, the proponents of TM must either solve this problem, or resign themselves to a world where TM is but one tool of several in the parallel programmer's toolbox. (To be fair, a number of TM proponents have long since resigned themselves to a world containing more than just TM.)

Paul E. McKenney 2011-12-16
perfbook_html/node96.html0000644000175000017500000001356511672746162015603 0ustar paulmckpaulmck 7.4.3.3 Data Structures

7.4.3.3 Data Structures

The actual data structures for a ``toy'' implementation of allocator caches are shown in Figure [*]. The ``Global Pool'' of Figure [*] is implemented by globalmem of type struct globalmempool, and the two CPU pools by the per-CPU variable percpumem of type percpumempool. Both of these data structures have arrays of pointers to blocks in their pool fields, which are filled from index zero upwards. Thus, if globalmem.pool[3] is NULL, then the remainder of the array from index 4 up must also be NULL. The cur fields contain the index of the highest-numbered full element of the pool array, or -1 if all elements are empty. All elements from globalmem.pool[0] through globalmem.pool[globalmem.cur] must be full, and all the rest must be empty.7.8

Figure: Allocator-Cache Data Structures
\begin{figure}{ \scriptsize
\begin{verbatim}1  ...

The operation of the pool data structures is illustrated by Figure [*], with the six boxes representing the array of pointers making up the pool field, and the number preceding them representing the cur field. The shaded boxes represent non-NULL pointers, while the empty boxes represent NULL pointers. An important, though potentially confusing, invariant of this data structure is that the cur field is always one smaller than the number of non-NULL pointers.

Figure: Allocator Pool Schematic
\resizebox{3in}{!}{\includegraphics{SMPdesign/AllocatorPool}}

Paul E. McKenney 2011-12-16
perfbook_html/node63.html0000644000175000017500000001157711672746161015575 0ustar paulmckpaulmck 6.3.4 Approximate Limit Counter Implementation


6.3.4 Approximate Limit Counter Implementation

Figure: Approximate Limit Counter Variables
\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long __thread counter ...
...NLOCK(gblcnt_mutex);
8  ...

Figure: Approximate Limit Counter Balancing
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void balance_count(void)...
...r = globalcount;
11 globalcount -= counter;
12 }\end{verbatim}
}\end{figure}

Because this implementation (count_lim_app.c) is quite similar to that in the previous section (Figures [*], [*], and [*]), only the changes are shown here. Figure [*] is identical to Figure [*], with the addition of MAX_COUNTERMAX, which sets the maximum permissible value of the per-thread countermax variable.

Similarly, Figure [*] is identical to the balance_count() function in Figure [*]), with the addition of lines 5 and 6, which enforce the MAX_COUNTERMAX limit on the per-thread countermax variable.



Paul E. McKenney 2011-12-16
perfbook_html/img30.png0000644000175000017500000002400111672746070015217 0ustar paulmckpaulmckPNG  IHDRK7q; ntRNSىH IDATx};JG1Xcu4pY  hX"+'eHrnYc5B6!g,gd6BVf"@aˆ4ΤDO^jD9`zT(viq%GSW2,mV/J4 ҍ)P'o+jM$1Dz4 2<2A`&L0fj(\y:_)`@jT+;1:Ce0b-dT86I9y/KCt\qfJؗ&8#)_hP&{ ]5RTL2FQ8UCz~ 8bppEa -M& dH#̫a-Q]*!t'hcHg"2&s3ť$|\+=IE(j)z0cnNqF 3y@MYCR P1?s6-W0-z8}֫eS4ζP"3d^kSf3;OwMVOid 멙u5mE3C T&*/WAfTq͛dի쾚*t+*VIz>QF{0k, es.#Ƿ3f) }˰䙥Y$zL CsQ߽3RE2ΐlnցqz+12cmXvKwR et 0]Wylx.{5&\z#}N=\wb%;,.پw9H@v՚([wW<"z֧C*]º??ᚥ'VB2쁗Z !xN7YWdj_R1BjT1b1P,oZ'ʯ`T2vV:(_%/19(3T:84WN3,}Źyp]o,Q2H,dP7^zClL9H_R\uJz? 7_+[GDnϳrͮxpLjk(4(TRӢj; ן岌suaZ#Z|.Ύ)s L#4pM2وc%XW\6ŵGQpܝƒ۞ˊEgEgm'9<f WNrɪyZ5׫gW"kaOЩ#$r[+6rvbZZQ)Mͪ(ZHx8=ɧr n{rs&fl3XQ>Eu%>x<z KڦzKTs"wLF̟ =8 ?ܿL4Kդ@9:56j4Mc@}M=J*}(WVol,Hߞ,o~'Q͆SFx:m+DomE:%=gzXY1J PMX_2lYF4=Ҍp?4"j*4;d׭+ZI8nĽWU`KQEŁ I o $>5w :T9=R846px0:ΛOnhWg*G٦u{f{,п< Nj93pfYf=o9&a>dpqHbzd{'z,D!SN}&=нM$_X Vxx=_@*_#uYx=tz1nt=8\tгfޯauaj٭= )I<RGa`([[]tLAa{yt~0N<5ckY[~!3xB=Ք{}'Ќ DX-("16|TץW̢z1??IfyC3^z`@=sK/mt1ZVi-'Yhz:pY oNz=Ptʤ ZqD֦Q"İ\@Afi)pĻ\@ Lm )cT-ųԢ*6 TCW h%@jX J uku _㣗=P,q,22g&V*&z0+;¶-%kc:r]ynK+:=8s"9y83"JUcR` ϭe3YxhZf)Bś{]ȗWqpgmUsͻt]WU8M ;ߝ+/ǧ@!8'o^ kohOʸb GZU[G,eZFSWٔOwuI߻Us `ZNx? |ti`cYpp~Z, w7;)r-P,!M7T0nռ(#-& f}46"9pNaȯLcMuI>h4@'#uI9nv;3 y WQwm烠n- :" }S/bFM*c5o10@Q&;}&tV,3_b3h{a\46 *11bfG`R q+w㜡p\D 5d9܎CpdGۭ] =!JWCDiɮ@"1P-T)ks?FaZjunNm w.%mN5g|;ގr|n e;e6-->tM۴dm.M0utɗi:Uu-o5xiJݬ!&p־֦iIZSqu%{Mq&0zgO#rlL,l9+to5p4x)GO"u Kvb  Kyݢ%J5NŊbt׵!&G -ٵ1yW&C;)Jiuwku[ݔfQjˁ{xhltYweE2cEU[chiy56Oq pDj c OVR_;+ nR$'JJ˘[|he0ik{עV~~z@$>]_~A%=zZCMϭ0zgl piiMgؘI?ls1 p27x*E͓[˕]g_ ׿6a^VT@!/,«xn" (\ߩH>r=I18ѝw%K Y9;bž]`Uwأ0/CĿY ^8'?HKEv?ßӥ:4 o[ȫb$Ybѩ%VeRf,NW,_sKRurjZyhA߳[Gy仂I!["FfIb> 25:CFxfwm9~r@nG`s(=ɯsT˘rAձ;/5чo{' s#nԎ7偍k-,q(<)1$_"1WPBʶMGpF[gYT0heSS@ 0K0_! zXVđɏX dlbdIf3s*`Yy< 24~﫵|9/_JZ ebX`48ǤԖ-=g#ľx{~΁{̮l>=q)wkP}H'PUοFA@h6?G=✐<"!{8ZkGL30'gΞq=/,EձM YR+2:C5Gl$'##>e?ܡg00I؈1 A3qq:?vP>J3_RǀOqeQ_wU^;IpI6vyZ5Xbq{ڦ3zoqҳdBc Hv#8EjԶ ^o7W6-/t 9Sc5ԲϋW(o=߼$.R^4cB]Y.24HXS+} n)&sZYXzjN{.EU_M#"a. zxdiw[Q%vQF2 TH'lzesP!t?5OHd,7o+ 4ZzªEg XQKS2 &:+-Tݿt??N|amVOؾ\y,fzGQ0a@ yOLS"[S7Dun!-T*$FZYyޯjr =P\1,`4N#Ǔ Ա SSH5qG*Ԓ@qL[}/h,u.83`3 !ǣЌڇT~,UF=}z{._awNJ_]EIDATh^xNvK}A1D F|I塋Pw+0y6y61nn̥}:[2wL~Dnw" v"&>S#g#8_Rn =MdSl]H-yvCɣ!yt6) ֆ?\ztbATDi '/a)mX^At6Q,)2|2\˃߾g#c"^pչ(mݻ>_p>97c9͎߇~RQ޽kRP#ЎWk  Wgק_᭏?_ʵ|6ZyMy~.@?!3sCm _VLZ}*9y&}%sfKv\QONewbH`rbRy$V6,}8[sotDvkX; S2S6cRktD[C8]Y |y} F36Du*(.&߇đ7aeBSH}W`6eͮ #ț4gDZ9DOҖ)\t$ypFm!6CZa$ $TSR- @ZN}̛ Ǫ<Ŧ g~%Z(,hIA-~poɀڴ/Kʓr|I}vֶ1m`tYF[M?t,1`#°-@661FjeY:_my(n%4YtY{mˎIQ|urhQH0 wɗҕe advؖ_M*Jz[yBuegZhOV\E A96h#ǖ|4W Kty8v1Z%3K[ղv]Y]. YQ:tAJEcA6a WZI˭z87t'UD僴slS} E!9=;!ːV2AٛA~=.k`NۖapbeC9j ,vb_,VV))O͗8} y<#@ Myw-o qu"D8墌+ 77qˀBܰq>q9Xx?'zd,X.ߧISrɠux[r#dǿ{='חWTNofyo//oOX]jTڅtoUw×:_~R6SR*.?[%P\Nq1} s$dmIENDB`perfbook_html/node459.html0000644000175000017500000000652411672746163015664 0ustar paulmckpaulmck E.9 Summary


E.9 Summary

Promela is a very powerful tool for validating small parallel algorithms. It is a useful tool in the parallel kernel hacker's toolbox, but it should not be the only tool. The QRCU experience is a case in point: given the Promela validation, the proof of correctness, and several rcutorture runs, I now feel reasonably confident in the QRCU algorithm and its implementation. But I would certainly not feel so confident given only one of the three!

Nevertheless, if your code is so complex that you find yourself relying too heavily on validation tools, you should carefully rethink your design. For example, a complex implementation of the dynticks interface for preemptible RCU that was presented in Section [*] turned out to have a much simpler alternative implementation, as discussed in Section [*]. All else being equal, a simpler implementation is much better than a mechanical proof for a complex implementation!


Paul E. McKenney 2011-12-16
perfbook_html/node477.html0000644000175000017500000005660211672746164015667 0ustar paulmckpaulmck G. Glossary

G. Glossary

Associativity:
The number of cache lines that can be held simultaneously in a given cache, when all of these cache lines hash identically in that cache. A cache that could hold four cache lines for each possible hash value would be termed a ``four-way set-associative'' cache, while a cache that could hold only one cache line for each possible hash value would be termed a ``direct-mapped'' cache. A cache whose associativity was equal to its capacity would be termed a ``fully associative'' cache. Fully associative caches have the advantage of eliminating associativity misses, but, due to hardware limitations, fully associative caches are normally quite limited in size. The associativity of the large caches found on modern microprocessors typically range from two-way to eight-way.
Associativity Miss:
A cache miss incurred because the corresponding CPU has recently accessed more data hashing to a given set of the cache than will fit in that set. Fully associative caches are not subject to associativity misses (or, equivalently, in fully associative caches, associativity and capacity misses are identical).
Atomic:
An operation is considered ``atomic'' if it is not possible to observe any intermediate state. For example, on most CPUs, a store to a properly aligned pointer is atomic, because other CPUs will see either the old value or the new value, but are guaranteed not to see some mixed value containing some pieces of the new and old values.
Cache:
In modern computer systems, CPUs have caches in which to hold frequently used data. These caches can be thought of as hardware hash tables with very simple hash functions, but in which each hash bucket (termed a ``set'' by hardware types) can hold only a limited number of data items. The number of data items that can be held by each of a cache's hash buckets is termed the cache's ``associativity''. These data items are normally called ``cache lines'', which can be thought of a fixed-length blocks of data that circulate among the CPUs and memory.
Cache Coherence:
A property of most modern SMP machines where all CPUs will observe a sequence of values for a given variable that is consistent with at least one global order of values for that variable. Cache coherence also guarantees that at the end of a group of stores to a given variable, all CPUs will agree on the final value for that variable. Note that cache coherence applies only to the series of values taken on by a single variable. In contrast, the memory consistency model for a given machine describes the order in which loads and stores to groups of variables will appear to occur.
Cache Coherence Protocol:
A communications protocol, normally implemented in hardware, that enforces memory consistency and ordering, preventing different CPUs from seeing inconsistent views of data held in their caches.
Cache Geometry:
The size and associativity of a cache is termed its geometry. Each cache may be thought of as a two-dimensional array, with rows of cache lines (``sets'') that have the same hash value, and columns of cache lines (``ways'') in which every cache line has a different hash value. The associativity of a given cache is its number of columns (hence the name ``way'' - a two-way set-associative cache has two ``ways''), and the size of the cache is its number of rows multiplied by its number of columns.
Cache Line:
(1) The unit of data that circulates among the CPUs and memory, usually a moderate power of two in size. Typical cache-line sizes range from 16 to 256 bytes.
(2) A physical location in a CPU cache capable of holding one cache-line unit of data.
(3) A physical location in memory capable of holding one cache-line unit of data, but that it also aligned on a cache-line boundary. For example, the address of the first word of a cache line in memory will end in 0x00 on systems with 256-byte cache lines.
Cache Miss:
A cache miss occurs when data needed by the CPU is not in that CPU's cache. The data might be missing because of a number of reasons, including: (1) this CPU has never accessed the data before (``startup'' or ``warmup'' miss), (2) this CPU has recently accessed more data than would fit in its cache, so that some of the older data had to be removed (``capacity'' miss), (3) this CPU has recently accessed more data in a given setG.1 than that set could hold (``associativity'' miss), (4) some other CPU has written to the data (or some other data in the same cache line) since this CPU has accessed it (``communication miss''), or (5) this CPU attempted to write to a cache line that is currently read-only, possibly due to that line being replicated in other CPUs' caches.
Capacity Miss:
A cache miss incurred because the corresponding CPU has recently accessed more data than will fit into the cache.
Code Locking:
A simple locking design in which a ``global lock'' is used to protect a set of critical sections, so that access by a given thread to that set is granted or denied based only on the set of threads currently occupying the set of critical sections, not based on what data the thread intends to access. The scalability of a code-locked program is limited by the code; increasing the size of the data set will normally not increase scalability (in fact, will typically decrease scalability by increasing ``lock contention''). Contrast with ``data locking''.
Communication Miss:
A cache miss incurred because the some other CPU has written to the cache line since the last time this CPU accessed it.
Critical Section:
A section of code guarded by some synchronization mechanism, so that its execution constrained by that primitive. For example, if a set of critical sections are guarded by the same global lock, then only one of those critical sections may be executing at a given time. If a thread is executing in one such critical section, any other threads must wait until the first thread completes before executing any of the critical sections in the set.
Data Locking:
A scalable locking design in which each instance of a given data structure has its own lock. If each thread is using a different instance of the data structure, then all of the threads may be executing in the set of critical sections simultaneously. Data locking has the advantage of automatically scaling to increasing numbers of CPUs as the number of instances of data grows. Contrast with ``code locking''.
Direct-Mapped Cache:
A cache with only one way, so that it may hold only one cache line with a given hash value.
Exclusive Lock:
An exclusive lock is a mutual-exclusion mechanism that permits only one thread at a time into the set of critical sections guarded by that lock.
False Sharing:
If two CPUs each frequently write to one of a pair of data items, but the pair of data items are located in the same cache line, this cache line will be repeatedly invalidated, ``ping-ponging'' back and forth between the two CPUs' caches. This is a common cause of ``cache thrashing'', also called ``cacheline bouncing'' (the latter most commonly in the Linux community). False sharing can dramatically reduce both performance and scalability.
Fragmentation:
A memory pool that has a large amount of unused memory, but not laid out to permit satisfying a relatively small request is said to be fragmented. External fragmentation occurs when the space is divided up into small fragments lying between allocated blocks of memory, while internal fragmentation occurs when specific requests or types of requests have been allotted more memory than they actually requested.
Fully Associative Cache:
A fully associative cache contains only one set, so that it can hold any subset of memory that fits within its capacity.
Grace Period:
A grace period is any contiguous time interval such that any RCU read-side critical section that began before the start of that grace period is guaranteed to have completed before the grace period ends. Many RCU implementations define a grace period to be a time interval during which each thread has passed through at least one quiescent state. Since RCU read-side critical sections by definition cannot contain quiescent states, these two definitions are almost always interchangeable.
Hot Spot:
Data structure that is very heavily used, resulting in high levels of contention on the corresponding lock. One example of this situation would be a hash table with a poorly chosen hash function.
Invalidation:
When a CPU wishes to write to a data item, it must first ensure that this data item is not present in any other CPUs' cache. If necessary, the item is removed from the other CPUs' caches via ``invalidation'' messages from the writing CPUs to any CPUs having a copy in their caches.
IPI:
Inter-processor interrupt, which is an interrupt sent from one CPU to another. IPIs are used heavily in the Linux kernel, for example, within the scheduler to alert CPUs that a high-priority process is now runnable.
IRQ:
Interrupt request, often used as an abbreviation for ``interrupt'' within the Linux kernel community, as in ``irq handler''.
Linearizable:
A sequence of operations is ``linearizable'' if there is at least one global ordering of the sequence that is consistent with the observations of all CPUs/threads.
Lock:
A software abstraction that can be used to guard critical sections, as such, an example of a ''mutual exclusion mechanism''. An ``exclusive lock'' permits only one thread at a time into the set of critical sections guarded by that lock, while a ``reader-writer lock'' permits any number of reading threads, or but one writing thread, into the set of critical sections guarded by that lock. (Just to be clear, the presence of a writer thread in any of a given reader-writer lock's critical sections will prevent any reader from entering any of that lock's critical sections and vice versa.)
Lock Contention:
A lock is said to be suffering contention when it is being used so heavily that there is often a CPU waiting on it. Reducing lock contention is often a concern when designing parallel algorithms and when implementing parallel programs.
Memory Consistency:
A set of properties that impose constraints on the order in which accesses to groups of variables appear to occur. Memory consistency models range from sequential consistency, a very constraining model popular in academic circles, through process consistency, release consistency, and weak consistency.
MESI Protocol:
The cache-coherence protocol featuring modified, exclusive, shared, and invalid (MESI) states, so that this protocol is named after the states that the cache lines in a given cache can take on. A modified line has been recently written to by this CPU, and is the sole representative of the current value of the corresponding memory location. An exclusive cache line has not been written to, but this CPU has the right to write to it at any time, as the line is guaranteed not to be replicated into any other CPU's cache (though the corresponding location in main memory is up to date). A shared cache line is (or might be) replicated in some other CPUs' cache, meaning that this CPU must interact with those other CPUs before writing to this cache line. An invalid cache line contains no value, instead representing ``empty space'' in the cache into which data from memory might be loaded.
Mutual-Exclusion Mechanism:
A software abstraction that regulates threads' access to ``critical sections'' and corresponding data.
NMI:
Non-maskable interrupt. As the name indicates, this is an extremely high-priority interrupt that cannot be masked. These are used for hardware-specific purposes such as profiling. The advantage of using NMIs for profiling is that it allows you to profile code that runs with interrupts disabled.
NUCA:
Non-uniform cache architecture, where groups of CPUs share caches. CPUs in a group can therefore exchange cache lines with each other much more quickly than they can with CPUs in other groups. Systems comprised of CPUs with hardware threads will generally have a NUCA architecture.
NUMA:
Non-uniform memory architecture, where memory is split into banks and each such bank is ``close'' to a group of CPUs, the group being termed a ``NUMA node''. An example NUMA machine is Sequent's NUMA-Q system, where each group of four CPUs had a bank of memory near by. The CPUs in a given group can access their memory much more quickly than another group's memory.
NUMA Node:
A group of closely placed CPUs and associated memory within a larger NUMA machines. Note that a NUMA node might well have a NUCA architecture.
Pipelined CPU:
A CPU with a pipeline, which is an internal flow of instructions internal to the CPU that is in some way similar to an assembly line, with many of the same advantages and disadvantages. In the 1960s through the early 1980s, pipelined CPUs were the province of supercomputers, but started appearing in microprocessors (such as the 80486) in the late 1980s.
Process Consistency:
A memory-consistency model in which each CPU's stores appear to occur in program order, but in which different CPUs might see accesses from more than one CPU as occurring in different orders.
Program Order:
The order in which a given thread's instructions would be executed by a now-mythical ``in-order'' CPU that completely executed each instruction before proceeding to the next instruction. (The reason such CPUs are now the stuff of ancient myths and legends is that they were extremely slow. These dinosaurs were one of the many victims of Moore's-Law-driven increases in CPU clock frequency. Some claim that these beasts will roam the earth once again, others vehemently disagree.)
Quiescent State:
In RCU, a point in the code where there can be no references held to RCU-protected data structures, which is normally any point outside of an RCU read-side critical section. Any interval of time during which all threads pass through at least one quiescent state each is termed a ``grace period''.
Read-Copy Update (RCU):
A synchronization mechanism that can be thought of as a replacement for reader-writer locking or reference counting. RCU provides extremely low-overhead access for readers, while writers incur additional overhead maintaining old versions for the benefit of pre-existing readers. Readers neither block nor spin, and thus cannot participate in deadlocks, however, they also can see stale data and can run concurrently with updates. RCU is thus best-suited for read-mostly situations where stale data can either be tolerated (as in routing tables) or avoided (as in the Linux kernel's System V IPC implementation).
Read-Side Critical Section:
A section of code guarded by read-acquisition of some reader-writer synchronization mechanism. For example, if one set of critical sections are guarded by read-acquisition of a given global reader-writer lock, while a second set of critical section are guarded by write-acquisition of that same reader-writer lock, then the first set of critical sections will be the read-side critical sections for that lock. Any number of threads may concurrently execute the read-side critical sections, but only if no thread is executing one of the write-side critical sections.
Reader-Writer Lock:
A reader-writer lock is a mutual-exclusion mechanism that permits any number of reading threads, or but one writing thread, into the set of critical sections guarded by that lock. Threads attempting to write must wait until all pre-existing reading threads release the lock, and, similarly, if there is a pre-existing writer, any threads attempting to write must wait for the writer to release the lock. A key concern for reader-writer locks is ``fairness'': can an unending stream of readers starve a writer or vice versa.
Sequential Consistency:
A memory-consistency model where all memory references appear to occur in an order consistent with a single global order, and where each CPU's memory references appear to all CPUs to occur in program order.
Store Buffer:
A small set of internal registers used by a given CPU to record pending stores while the corresponding cache lines are making their way to that CPU. Also called ``store queue''.
Store Forwarding:
An arrangement where a given CPU refers to its store buffer as well as its cache so as to ensure that the software sees the memory operations performed by this CPU as if they were carried out in program order.
Super-Scalar CPU:
A scalar (non-vector) CPU capable of executing multiple instructions concurrently. This is a step up from a pipelined CPU that executes multiple instructions in an assembly-line fashion -- in a super-scalar CPU, each stage of the pipeline would be capable of handling more than one instruction. For example, if the conditions were exactly right, the Intel Pentium Pro CPU from the mid-1990s could execute two (and sometimes three) instructions per clock cycle. Thus, a 200MHz Pentium Pro CPU could ``retire'', or complete the execution of, up to 400 million instructions per second.
Transactional Memory (TM):
Shared-memory synchronization scheme featuring ``transactions'', each of which is an atomic sequence of operations that offers atomicity, consistency, isolation, but differ from classic transactions in that they do not offer durability. Transactional memory may be implemented either in hardware (hardwire transactional memory, or HTM), in software (software transactional memory, or STM), or in a combination of hardware and software (``unbounded'' transactional memory, or UTM).
Vector CPU:
A CPU that can apply a single instruction to multiple items of data concurrently. In the 1960s through the 1980s, only supercomputers had vector capabilities, but the advent of MMX in x86 CPUs and VMX in PowerPC CPUs brought vector processing to the masses.
Write Miss:
A cache miss incurred because the corresponding CPU attempted to write to a cache line that is read-only, most likely due to its being replicated in other CPUs' caches.
Write-Side Critical Section:
A section of code guarded by write-acquisition of some reader-writer synchronization mechanism. For example, if one set of critical sections are guarded by write-acquisition of a given global reader-writer lock, while a second set of critical section are guarded by read-acquisition of that same reader-writer lock, then the first set of critical sections will be the write-side critical sections for that lock. Only one thread may execute in the write-side critical section at a time, and even then only if there are no threads are executing concurrently in any of the corresponding read-side critical sections.
Paul E. McKenney 2011-12-16
perfbook_html/img6.png0000644000175000017500000001275611672746027015162 0ustar paulmckpaulmckPNG  IHDR<WtRNSىHIDATx]H!vsZ$?@B,G%4&l *-!6jd^bAd˒J|ϩJ232PdaTDbqT _XQ2PH (Mk"2 P'9>(n@^t1r "1p:+c7Ip^!!v(q,ܬiޢIʢumw27Eo cu%ʾtn^D[uH*@IQk}Y,\a@z^n?܍ƢQo ge+sH>7Lwg,Q> >z[tY5ݠ|:Q{맻ҟ,ᜢ94s۹EmCE=&iB{Rj#m߶YZ ]ɻtS0:PyP4OIqM`,DsGD˹JAS鏤H D42#G!M˅o^Bi?i.0X~־"bHyIDZ_4_|[4?ͥ?]^lJs}R*NHQң?^~?'D 0jˉOu][@ g{:߻uY(YQn@OF!\#>a㩅s~]^nP"|TN3HN$(kGuzY<܀TEb(ŰR#DRG»]\fr^f}L@"ÝX$d8@žD`;Iς aS=m,W)&cL}I `'&`pU8=@:j0Z'r^,2?([V2xp,'1Ns vƠ7Odϯ; ʯ6?d7|g`תl~wEXIJ khX̹)ZXV2 ~|7 M 0궇նފ'mꋳlp@iZ4#͈ylSAZ0/=Dp~ -zy Wz l 1'!r^DqWP|5{gW` Z t,Κq8X~Ewu<\x&,*_S]7X OM@O'}`3el%́{%㜤fJ{pړTJW@F!} ߣ(`a|kd\`Y#$a8Ns{3dᭂ87;qOيWb!VXXCBo 6t} DlːkhqRAܷW9@D@˃ZAIb8qW}(e^;As`7`{g^1 ׺ 6-v7]?̓x ,]+S\:p$xoʺ%n^!%J;3A7`Cq5Me dFi̒0*pdfHJCkB4m3C=Z œteeJuz5]svA=-"=N=jBR褐r+ۭxܰrΦ ր <ūo)B!W< <梀؁Sg' ~o1e="b?pJDf`o~=qe G;!Ow&^˓yO-,sq +I/h]HxOZy_w.iA[ O7BB - lHᙽLM.6] @< ,aOSP 2)m#4uk_.6%g.zw4ˣJ UA@e,54abm[r-B`KQp [;|Ps\/p@ng" b3l&3lc(k.c`2&'\p(Ī ŷچhO\4ÏEW?QT`!<O& ׷i۶bY˂M 4({cnܪGB7 נm$ `lpzzl8T,t.Qh%<`X:QT]wumQNfKA)ϩ'-fQ*"OZQ]mV- 攁RJ+5BrPЉ;1eA*/R"&(rկx<ީX=F%2(R K6CK<w6j ڱ@(=oE&QhR ώ2UA)f!k_Q߱ΛT[B'^R?Rfrʪ2K0ѧ;qS5Ӕ .l>-ZA-SI59|AhIU)^<ū,]|Fs9A/5;j؅e~{/°bv6-Uhi8ڦ'BS`גm;;HR2|Z贌@a`ͣ`-&{3hw+1@BSb Pm!2[¨d\錍(<ӟL@B~/(/0d !z>]~8&H:= .kqf[O=<98/SyT^<*AsRTyc _4?!ݕ ٠}fS onalN^h7>Lna]ATEQY"0C%vN02a/̵}#m㢙KV*̐=GT*:}[;5EdҐ[e1(>3Xp ?\ݖg$b}EyWpܾKn) G(7r*u3U 6UiGfm߳Ϸ  j{5W^eOl<09T+jZ^IC6OyvA [$bkZVˑAaސ@#\ +3q\Y4…4^tzl6Ak僜fx5 cFWj $\Kx9_wm1~2 j&A<]}0ZMsVOy?N QFIͶʫ*I7xּ xW_=+ F/ZC;VVJk ( yxО򸵒ZsR_5Ts.W:cq*ZMP%Oekf y U'?5´Z\Ne곀*ԩ FP c?p?` #ϻ&Tolծ<6-7Cmq3vƑ8߂rN8D]f۞ax8, S6c7jo0KvNӥHvZ"ϛl 7&(*X59Ca7Iٖd 7zs>\<wT}*Ώ8qMKMj'AWq8 '^ɂR-/ qyǑjy4dۄ*‹*NwuGB ?.)#?_W0%~q;ǿ^k5ÏQŕΨs'Wc3q+/\^z+Q`i"…S?cy[Λ}ȷ-g 7+ 5~ Zck}fE'xӑ;%oMf]BOIENDB`perfbook_html/node350.html0000644000175000017500000001122511672746163015644 0ustar paulmckpaulmck D.2.7.1 Start a New Grace Period


D.2.7.1 Start a New Grace Period

The rcu_start_gp() function starts a new grace period. This function is invoked when a CPU having callbacks waiting for a grace period notices that no grace period is in progress.

The rcu_start_gp() function updates state in the rcu_state and rcu_data structures to note the newly started grace period, acquires the ->onoff lock (and disables irqs) to exclude any concurrent CPU-hotplug operations, sets the bits in all of the rcu_node structures to indicate that all CPUs (including this one) must pass through a quiescent state, and finally releases the ->onoff lock.

The bit-setting operation is carried out in two phases. First, the non-leaf rcu_node structures' bits are set without holding any additional locks, and then finally each leaf rcu_node structure's bits are set in turn while holding that structure's ->lock.

Quick Quiz D.11: But what happens if a CPU tries to report going through a quiescent state (by clearing its bit) before the bit-setting CPU has finished? End Quick Quiz

Quick Quiz D.12: And what happens if all CPUs try to report going through a quiescent state before the bit-setting CPU has finished, thus ending the new grace period before it starts? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node401.html0000644000175000017500000002273611672746163015652 0ustar paulmckpaulmck D.4 Preemptible RCU


D.4 Preemptible RCU

The preemptible RCU implementation is unusual in that it permits read-side critical sections to be preempted and to be blocked waiting for locks. However, it does not handle general blocking (for example, via the wait_event() primitive): if you need that, you should instead use SRCU, which is described in Appendix [*]. In contrast to SRCU, preemptible RCU only permits blocking within primitives that are both subject to priority inheritance and non-blocking in a non-CONFIG_PREEMPT kernel. This ability to acquire blocking locks and to be preempted within RCU read-side critical sections is required for the aggressive real-time capabilities provided by Ingo Molnar's -rt patchset. However, the initial preemptible RCU implementation [McK05c] had some limitations, including:

  1. Its read-side primitives cannot be called from within non-maskable interrupt (NMI) or systems-management interrupt handlers.
  2. Its read-side primitives use both atomic instructions and memory barriers, both of which have excessive overhead.
  3. It does no priority boosting of RCU read-side critical sections [McK07d].

The new preemptible RCU implementation that accepted into the 2.6.26 Linux kernel removes these limitations, and this appendix describes its design, serving as an update to the LWN article [McK07a]. However, please note that this implementation was replaced with a faster and simpler implementation in the 2.6.32 Linux kernel. This description nevertheless remains to bear witness to the most complex RCU implementation ever devised.

Quick Quiz D.56: Why is it important that blocking primitives called from within a preemptible-RCU read-side critical section be subject to priority inheritance? End Quick Quiz

Quick Quiz D.57: Could the prohibition against using primitives that would block in a non-CONFIG_PREEMPT kernel be lifted, and if so, under what conditions? End Quick Quiz



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img301.png0000644000175000017500000001722311672746000015301 0ustar paulmckpaulmckPNG  IHDRJ!Y)8TPLTE^\\MJK# b``vstmkkcaaXUV856C@@744wuv.*+|zzrppmjk'tRNS@fIDATx]Zm m=n($sfg%˜]4ۧqX 3]u}o 0XTM=xo53E7wo}3!*]M3=ZSyqj;}uRύu-n_uCnh,CAOhOߟy0_f+x4aM^N~/yߛ[p8zCvu9:W;|#`C0ZUG@ڰz5|[~ct8TΌ穀Vq#k uh5tcZ*ڏՀ#9ޓ6Da6/,\UYZI%qw4pnm8oHCHSx:C7jCÏH%h*KwaGX$my-SscZ>^#+|qDUojd9x偎9wrT)?Ju䞱Zz|r$rXUJN^w}2MM6FXi!HBa'Ljo=jY 9ġXs_ Ҁk$Od_Pl'-]oƚ'KHU6nY#xV]ڪ!_ՐV-QO7<݉ޅ%>z~iyT#J$!@$}3< 5Dxɲ[A4M'F5N B(Q;egd>oe!JHlOvCނ9ܪrmJ} u%槜}['u5d5׬U3hL;2 NWV6Y8U';y)NXR( lyJ3Ui*lV;,C;P5S'X,<=1vǃQ'UuZ9ERH^%zS Jz]BEմ8Ig{_ `)k'FLuOteتk 9q Jr7؏}&9;IG^!-MK nmi1MR[,ђȒjy2l4,׳93iwq?jȬ7΂D,fZDd{k}#(0B"# H \,[6(!L_dM(+} M`)B ' Ͼ,l)7FZVѱ'XcV2>`:@QKĔ7geAIhz1 $',h6.PMt [2K١6 oY Axf|(cխ4QAÐiȿX]ku>>95Op/&HX=8%$Y_^:3w[IOqI+)bZG*hb|A"%N7ͯ|A;&CsIqR57.)AaA(]e(b$@>+ĞR(gG`P{a_- WV"=̑"!cvS\X AD,4&Dդyd̽ZɺVHzվs`͚Lזx*rm,$YGi C4>W=ح0(VR2ƨn+i!8f9J)iUɸ:Ň0KRڼ$r*P7%C P Up,Q,x?f/jK!P Q^!F4" nhi&i6J'B<&N5- M%Tu@eVH{Mmj똙lyYOϭb},B*nYL+2̖w?.,>qה~5;.HYl\ߒZb/x8CFyg4C䇊6荋7%ܬJDIp(O@bFtb?~1Rpj:Nx]`B0WQC}r ą-af%<9 j ,m`<`@-*%h1"kxkπ]xm=EnOԗ4l9;#;L#W[@C\wԼ[1?VJtc'(-^>u.̱x&,}/jJtr {q/pWvCKӍ0 XZ 06.$A{QΝǻ~JsW'8q5 of2e%AOT )*ڝ^!Z[*%O7A\ͲA&Ǡט /5JN1K ʢ>q5j`p[C֗oNHQ@9'1,iځS+)֋7.~XcI]"@ x!SdJ'G0򖄀Ԟ8Ƽ_IEQKѨ5d8UɡfYRBIfSe>2hh_{Ằ7BN5Aj?DqLp@[Iʼx^\i+(ePf^$^9[n uت%HN\|HYH6SVgO&Iڸe0)\Z%:yJ\^ ޮ2^ 8Q#JL[eźtj?\27~7 VB&l. %>7JGHf I;-y4-QV#$N"Q܅O6&)!q1Oykބ"܆az3n26p(-a6I*l &T{P,/hۡ[uOj_}%M(ǻ@^ڈAGgTAQ8.W37mߟHR5zBM~ Uvpj)lC)~Yy0)'aʤ'CcO}ΐ_0ruFAAAAAAAAAAD|k ^NTe Unśv ,49o/)z8ɚvb 綅T~$TSI )f" 8z?)Ey-Jρj/Fs n߉HF,m 6T:I2(Ts7eiI;RD{r{*{̊q.A5m@LmS6-R/P<ØkdMGIOC(4i̓9M@32C8|olf90#Kq^-U߲v>0b~21YnCƞ_' 'Obׅ'tΓ)~0'ThA֕d2`¾=sX<EW[, Ϝd{k{y {ڈS?ZTI_b#/Bp;'n+/y#Cq5DE4d~)LѢRrΉ$ XkW:|mĵhEV L)ir*aΉT23]hb|mĵDؤJ)3md .rN츮Y?!z,ڈ}>GI#Lf6<șǡ("}kj̅Q;8<.^θ-XضO9"LӹIfԬlxt`CC>)~G]$A#!䌞_C,l[tS途$)/:?%qR4vRt ro1^QqYt/jq* ׫w_yyHK{5ga4Jf{Kidԩ2IH5 +EWoH)\ 6u0tPWloQ;I2%DrHgߓ ⎄%WDm03!$Q{"HR\;#)x1A_L]rBqF/RV)ǁs4h:8H`I% g!< q^ 1+s>ŏoABRU略&OdP G$ ^Vg*~~YKu; SE zLWH32]Ŏ:Cr73IENDB`perfbook_html/img64.png0000644000175000017500000000306711672746145015242 0ustar paulmckpaulmckPNG  IHDRT:a`PLTE$8D6Sf3!!l݌VV*3-EUwwfAAQ} c"aaHoD++Z~wLL" ?aẃu݇llU66dPtRNS@fIDATx훋v0Hd#A$rs " Tw9G0r3 Z{XSoA } Ρ ĬsN'j߈2D/4~/^aJa-s>Q4KRW_  lQ]S+7_:J]\gfQPQ+=A9`[4i::ʋXD,QEJUR55ҸTQ ߑ ?0ȼO!Gp xU!l_1]-&`m&'ĘfcRsd ^YqO֗z=<@V"5GAuŹ:j,i3ƥ-׳^ 0"ۦ@6@n&`,TBjFKb9 x(HIENDB`perfbook_html/node312.html0000644000175000017500000001355311672746163015650 0ustar paulmckpaulmck C.6.3 Example 2


C.6.3 Example 2

Table [*] shows three code fragments, executed concurrently by CPUs 0, 1, and 2. Both ``a'' and ``b'' are initially zero.


Table: Memory Barrier Example 2
CPU 0 CPU 1 CPU 2
a = 1; while (a == 0);
smp_mb(); y = b;
b = 1; smp_rmb();
x = a;
assert(y == 0 || x == 1);


Again, suppose CPU 0 recently experienced many cache misses, so that its message queue is full, but that CPU 1 has been running exclusively within the cache, so that its message queue is empty. Then CPU 0's assignment to ``a'' will appear in Node 0's cache immediately (and thus be visible to CPU 1), but will be blocked behind CPU 0's prior traffic. In contrast, CPU 1's assignment to ``b'' will sail through CPU 1's previously empty queue. Therefore, CPU 2 might well see CPU 1's assignment to ``b'' before it sees CPU 0's assignment to ``a'', causing the assertion to fire, despite the memory barriers.

In theory, portable code should not rely on this example code fragment, however, as before, in practice it actually does work on most mainstream computer systems.

Paul E. McKenney 2011-12-16
perfbook_html/node123.html0000644000175000017500000000671111672746162015645 0ustar paulmckpaulmck 10.2.3 Counter Optimizations


10.2.3 Counter Optimizations

In some cases where increments and decrements are common, but checks for zero are rare, it makes sense to maintain per-CPU or per-task counters, as was discussed in Chapter [*]. See Appendix [*] for an example of this technique applied to RCU. See the paper on sleepable read-copy update (SRCU) for an example of this technique applied to RCU [McK06]. This approach eliminates the need for atomic instructions or memory barriers on the increment and decrement primitives, but still requires that code-motion compiler optimizations be disabled. In addition, the primitives such as synchronize_srcu() that check for the aggregate reference count reaching zero can be quite slow. This underscores the fact that these techniques are designed for situations where the references are frequently acquired and released, but where it is rarely necessary to check for a zero reference count.


Paul E. McKenney 2011-12-16
perfbook_html/img92.png0000644000175000017500000000134411672746000015225 0ustar paulmckpaulmckPNG  IHDRM)4V0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fbIDATXc` ,@HҀSP&tJI1H NzR0`̰8@FHqbbf'V!0 A A  Hvi`&?ZIMC j \daqd <`g N V  Fn eP5#hA(V?dA PH0]Fl P3 TY* s_@s˩!Bl36d ahqQn6l1`3cd n&ccgPh}Wɷ` 6.2.4 Per-Thread-Variable-Based Implementation


6.2.4 Per-Thread-Variable-Based Implementation

Figure: Per-Thread Statistical Counters
\begin{figure}{ \scriptsize
\begin{verbatim}1 long __thread counter = 0;
2 l...
...[idx] = NULL;
41 spin_unlock(&final_mutex);
42 }\end{verbatim}
}\end{figure}

Fortunately, gcc provides an __thread storage class that provides per-thread storage. This can be used as shown in Figure [*] (count_end.c) to implement a statistical counter that not only scales, but that also incurs little or no performance penalty to incrementers compared to simple non-atomic increment.

Lines 1-4 define needed variables: counter is the per-thread counter variable, the counterp[] array allows threads to access each others' counters, finalcount accumulates the total as individual threads exit, and final_mutex coordinates between threads accumulating the total value of the counter and exiting threads.

Quick Quiz 6.19: Why do we need an explicit array to find the other threads' counters? Why doesn't gcc provide a per_thread() interface, similar to the Linux kernel's per_cpu() primitive, to allow threads to more easily access each others' per-thread variables? End Quick Quiz

The inc_count() function used by updaters is quite simple, as can be seen on lines 6-9.

The read_count() function used by readers is a bit more complex. Line 16 acquires a lock to exclude exiting threads, and line 21 releases it. Line 17 initializes the sum to the count accumulated by those threads that have already exited, and lines 18-20 sum the counts being accumulated by threads currently running. Finally, line 22 returns the sum.

Quick Quiz 6.20: Why on earth do we need something as heavyweight as a lock guarding the summation in the function read_count() in Figure [*]? End Quick Quiz

Lines 25-32 show the count_register_thread() function, which must be called by each thread before its first use of this counter. This function simply sets up this thread's element of the counterp[] array to point to its per-thread counter variable.

Quick Quiz 6.21: Why on earth do we need to acquire the lock in count_register_thread() in Figure [*]? It is a single properly aligned machine-word store to a location that no other thread is modifying, so it should be atomic anyway, right? End Quick Quiz

Lines 34-42 show the count_unregister_thread() function, which must be called prior to exit by each thread that previously called count_register_thread(). Line 38 acquires the lock, and line 41 releases it, thus excluding any calls to read_count() as well as other calls to count_unregister_thread(). Line 39 adds this thread's counter to the global finalcount, and then NULLs out its counterp[] array entry. A subsequent call to read_count() will see the exiting thread's count in the global finalcount, and will skip the exiting thread when sequencing through the counterp[] array, thus obtaining the correct total.

This approach gives updaters almost exactly the same performance as a non-atomic add, and also scales linearly. On the other hand, concurrent reads contend for a single global lock, and therefore perform poorly and scale abysmally. However, this is not a problem for statistical counters, where incrementing happens often and readout happens almost never. In addition, this approach is considerably more complex than the array-based scheme, due to the fact that a given thread's per-thread variables vanish when that thread exits.

Quick Quiz 6.22: Fine, but the Linux kernel doesn't have to acquire a lock when reading out the aggregate value of per-CPU counters. So why should user-space code need to do this??? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img175.png0000644000175000017500000001732411672746067015331 0ustar paulmckpaulmckPNG  IHDR)tRNSىHIDATx]_lyȐ"C>D!#E\ QM(Mpfu@.(P i&fRlvofffbP!_.@7XpX/%RݔLnghVҩzJL r1kLGX2'@)T,Njv P@cC)^8婎)5S<)|*& lQX0@/N劥%Uj/I?ʓ¥V++,%7h1E#{ mM}ʈIN|t<%TAQ+ mތ$BdXdu\;62FPŒ\ NBwfG'BٷҌlYi˄rncl"f)hT.'uKNOXׄ=s2>6$9\$O`7plw%Ko$x?'ss6FKY l&(nJ$ӷ\^2r kKcwS&A,8  iX: 3ZJkT7$Xl(^1y#4%yzr`AYIiw`eL(QhKGWOЦ,^H =$yAbW$I&ۙ eky@:I Mw&KFC5|$S@nqOL:;k(:gt7g7U/Pd8|6 XG^/d2 X1G0ܕpvKglVƾ >IB?)R#$LsoX!LKb~vXU*̘Sls+"DNzqX~zd*0fHd+jjq"p&6&U-e&[]VJ~mQVKrFqY~=H̿U2.Di5$'NJv˥Z$n`|O^.mnmnT8?8\j:V( ]#F?z R)E LXvFYgxP`$:i2'1S@$b33`2kE5A0NjFg v)> XX nϡA/5 `ꃺ)]) ڙQI}gWl=(2&}cE@R+<]zy@![crfbCo `bEwު9"GZElhT$/:mw@(N[2bm`[ X1C"gZV2%~:U@1\;7~{ XUW\EC+59 QF tT4PfНAO=g_|I#8c3ᲅ9pɋ`D!W֘>MYɇStЋg^?ڃF7]%K.L`iʋ{e"[ ܳ`9Eo^v"6eQ>ȵu33=dDKP\cdΐ! ˻@}5;6D ST@-|l[Yյ]d~@7hbK\d MWWJ uFG?hRژALfXc&..t3+T]Ա-ۻp2Τ!š8v$3P6^nH^ ɡYb`ώTN~__6GrDe׃]op\^3^w*oܩ\/%_l~}>K?ڷqpSwp֥}II >zR}yeIZq-.c.N+>yC{n jB6Y^ДuY;;btz0" SJ 2ҡ)7sJM,A \ @7$vfD"{cm^+֑0dRIgtd?GZ<ߒ'3@$FH~H;j{Vzbs5c޹J{0zhxIl= ocV짗2 ^-ד U2/m;7@ HKK5,ke&&fd]5`C⑉ qW ֊5Q͉/L!*{5j{rHD[@ lty [d/[ڬA=݊n9Oh8>y2gpg'+@?HŁ)<0[oP/^rR KU+Եbkf`"9' 2uZ$Jj!ړn<5 L2%IBV+ |ht` <!M[V@m]1sc|iH)ǹwyۚk{]ۮ|lzW' u?Hp&ؠ"jW1'H@9=`9-BrLq^3c_6gYк{ =5&GXxVe@oMt iǩQ9-.yp+H:)N @IixGIH+#Q,C'ekaBKmΒ TbXB,}*bbBemΒK>|]I\lٴJi+ %{Ŝv}C2Պ2$ EB{>%mz@h3 zJ@uJwr޻y 'taϬ?8>0{۞tx<;c?aPړ.ysMw.%$퉎̃aT9%=+oK1%͊7-K\rC򘓙7%KӦmyZ^%Y6g .3zh81X+o9yjE 5 &yij9;bf&݁԰D8 HٛV!]0c:Ӎ$.S؁Cf&nhĚVhFkG3[HdݔD(]<{q`fb Ll1 B@&$"7PZΈrG5> 9S5UmeukJ@c何o.||=BVwQ8*tE8R+$B@xO SGO]ݸwMtvChŵnjjMu/B"`%Ǚ1C}<JgR! |>6%X3)?Ҕp8l7pp8>ӑd3[ڨj&YڨjRFU3^'==]lU L.)@rN2sw{]l)p٪A7 ZaBOITlsۧ2Livz]s$L4۞pU0@ ׈CA;i"G*8\Wړ{1"s@*šY9Q :(7Gˀ>ŮU᫔ZJa{6Mw56 jFnbB(ZbwAkhih}=Lpd7j[-CY)VHƟ"tJpԺ+>J`^hpt8>'v%YYݨ*PLlPZvKq(aЃr)[q|yu/|e ? OBh=UtJx/N9~MWY=gd9'% :89T QsYogTנ3'ie*F6r@4e_ޡNa+4z >aBԦ0,+_)+!4%®)՜&ooIZ\nqp1e|cWҹս0'8 G"oGdrAX^QySOQy@rHP{ZYSC4} )^w`!chpQ[_܈4 U[Ejv:5pk_CTݫR~i SO FW\Gl!Ҕ}&H؄nZ4vsB%kϼ=Y D1?-?% ~[+~h&82 ]\!@ _.˺ש\ww?|*O r{>J Z^yq5Wx(igAt1RA\s9+<\~7+]q kbsY4"!BebqZ0t !I QlZv"LĨ l)NLG̅4g2/kΦ)߱ܩfn%+e>@EQҮ4grp}+P W>4\Ǜ_A8|_9oK[>?bȕ|,߹IbRYmIr.5˭Û1ϼV rMߕrn5% WOS ;/]*OWV|﷮'K/_KWVY 39ň+ OH۹\.8,B!E6?-wژк۹\}?VMl7rⷰzM76OJ \|no}>?&pΚmV/ p8="M 43onLɈx"MyRLwdp+|1҆dY"M9>px#ewvy3{#RZ(J}xC}!+)qAȣ8"mRSqK nwxً`'ݽ `ct 0iՋYH򉎶F68>sC8i>Povt[Ъ1LDm"<'9p!1Grޔ㝵űzHub.JA\}& 0 ca e/Sf?M r8& S?AZ>d9$82^?' 4c ջ-.!Ҕ8&n(z)F# UhJQy(FIDqL~8fr8MHdɡA4e"QlV|g4ԩ-|+g;$d>EP_PSR5%Aqvʷ!T'%SM Y!i]n'*;[M N?'kґ1=T&ҔB.z hZ3oT+)Oi$1s)qi$Q( ;s @9cG4eJ(Z!,޾-Ch{1+xaD)6Yݫ+X-~yIX)>Lc9|FaQi G 6%(hٺ;ڏ{i0F ԀSq6f s9_"M r@~mSm 'e">²h)AA'n>~h8Z$CHS=} &,,wGi "Q='zrHi \]aGBhd񼩵"Dbhgqv)٧<>c8$Ka~Vă^'{!&tkDgqiVYZ+K3Es+!`qF1i mulOs"(Df)MaFo-J#Sf!Y-~(yn"VHRqkM_)b~gaٶC 631J7RN@04'W9c Q+ݻ S"!Ҕl씠E5hgTڒs(#X8 ʊh. :7&Gc\f!GQOp8cQ(8dIENDB`perfbook_html/node421.html0000644000175000017500000001635511672746163015654 0ustar paulmckpaulmck D.4.3.2 Conceptual Validation


D.4.3.2 Conceptual Validation

Because neither rcu_read_lock() nor rcu_read_unlock() contain memory barriers, the RCU read-side critical section can bleed out on weakly ordered machines. In addition, the relatively loose coupling of this RCU implementation permits CPUs to disagree on when a given grace period starts and ends. This leads to the question as to how long a given RCU read-side critical section can possibly extend relative to the grace-period state machine.

Figure: Preemptible RCU Worst-Case Scenario
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptValidation}}

The worst-case scenario is shown in Figure [*]. Here, CPU 0 is executing the shortest possible removal and reclamation sequence, while CPU 1 executes the longest possible RCU read-side critical section. Because the callback queues are advanced just before acknowledging a counter flip, the latest that CPU 0 can execute its list_del_rcu() and call_rcu() is just before its scheduling-clock interrupt that acknowledges the counter flip. The call_rcu() invocation places the callback on CPU 0's next list, and the interrupt will move the callback from the next list to the wait[0] list. This callback will move again (from the wait[0] list to the wait[1] list) at CPU 0's first scheduling-clock interrupt following the next counter flip. Similarly, the callback will move from the wait[1] list to the done list at CPU 0's first scheduling-clock interrupt following the counter flip resulting in the value 3. The callback might be invoked immediately afterward.

Meanwhile, CPU 1 is executing an RCU read-side critical section. Let us assume that the rcu_read_lock() follows the first counter flip (the one resulting in the value 1), so that the rcu_read_lock() increments CPU 1's rcu_flipctr[1] counter. Note that because rcu_read_lock() does not contain any memory barriers, the contents of the critical section might be executed early by the CPU. However, this early execution cannot precede the last memory barrier executed by CPU 1, as shown on the diagram. This is nevertheless sufficiently early that an rcu_dereference() could fetch a pointer to the item being deleted by CPU 0's list_del_rcu().

Because the rcu_read_lock() incremented an index-1 counter, the corresponding rcu_read_unlock() must precede the "old counters zero" event for index 1. However, because rcu_read_unlock() contains no memory barriers, the contents of the corresponding RCU read-side critical section (possibly including a reference to the item deleted by CPU 0) can be executed late by CPU 1. However, it cannot be executed after CPU 1's next memory barrier, as shown on the diagram. Because the latest possible reference by CPU 1 precedes the earliest possible callback invocation by CPU 0, two passes through the grace-period state machine suffice to constitute a full grace period, and hence it is safe to do:



    #define GP_STAGES 2


Quick Quiz D.62: Suppose that the irq disabling in rcu_read_lock() was replaced by preemption disabling. What effect would that have on GP_STAGES? End Quick Quiz

Quick Quiz D.63: Why can't the rcu_dereference() precede the memory barrier? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node167.html0000644000175000017500000001011711672746162015650 0ustar paulmckpaulmck 11.1 RCU and Per-Thread-Variable-Based Statistical Counters


11.1 RCU and Per-Thread-Variable-Based Statistical Counters

Section [*] described an implementation of statistical counters that provided excellent performance, roughly that of simple increment (as in the C ++ operator), and linear scalability -- but only for incrementing via inc_count(). Unfortunately, threads needing to read out the value via read_count() were required to acquire a global lock, and thus incurred high overhead and suffered poor scalability. The code for the lock-based implementation is shown in Figure [*] on Page [*].

Quick Quiz 11.1: Why on earth did we need that global lock in the first place? End Quick Quiz



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node207.html0000644000175000017500000000516011672746162015645 0ustar paulmckpaulmck 14.2.4.6.3 Only One Store.

14.2.4.6.3 Only One Store.

Because there is only one store, only one of the variables permits one CPU to see the results of the other CPU's access. Therefore, there is no way to detect the conditional ordering provided by the memory barriers. (Yes, it is possible to determine whether or not the load saw the result of the corresponding store, but this does not depend on the memory barrier.)



Paul E. McKenney 2011-12-16
perfbook_html/node161.html0000644000175000017500000002442211672746162015646 0ustar paulmckpaulmck 10.3.4.7 RCU Based on Free-Running Counter


10.3.4.7 RCU Based on Free-Running Counter

Figure: Data for Free-Running Counter Using RCU
\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...);
4 DEFINE_PER_THREAD(long, rcu_reader_gp_snap);\end{verbatim}
}\end{figure}

Figure: Free-Running Counter Using RCU
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
... 28 spin_unlock(&rcu_gp_lock);
29 smp_mb();
30 }\end{verbatim}
}\end{figure}

Figure [*] (rcu.h and rcu.c) show an RCU implementation based on a single global free-running counter that takes on only even-numbered values, with data shown in Figure [*]. The resulting rcu_read_lock() implementation is extremely straightforward. Line 3 simply adds one to the global free-running rcu_gp_ctr variable and stores the resulting odd-numbered value into the rcu_reader_gp per-thread variable. Line 4 executes a memory barrier to prevent the content of the subsequent RCU read-side critical section from ``leaking out''.

The rcu_read_unlock() implementation is similar. Line 9 executes a memory barrier, again to prevent the prior RCU read-side critical section from ``leaking out''. Line 10 then copies the rcu_gp_ctr global variable to the rcu_reader_gp per-thread variable, leaving this per-thread variable with an even-numbered value so that a concurrent instance of synchronize_rcu() will know to ignore it.

Quick Quiz 10.48: If any even value is sufficient to tell synchronize_rcu() to ignore a given task, why doesn't line 10 of Figure [*] simply assign zero to rcu_reader_gp? End Quick Quiz

Thus, synchronize_rcu() could wait for all of the per-thread rcu_reader_gp variables to take on even-numbered values. However, it is possible to do much better than that because synchronize_rcu() need only wait on pre-existing RCU read-side critical sections. Line 17 executes a memory barrier to prevent prior manipulations of RCU-protected data structures from being reordered (by either the CPU or the compiler) to follow the increment on line 17. Line 18 acquires the rcu_gp_lock (and line 28 releases it) in order to prevent multiple synchronize_rcu() instances from running concurrently. Line 19 then increments the global rcu_gp_ctr variable by two, so that all pre-existing RCU read-side critical sections will have corresponding per-thread rcu_reader_gp variables with values less than that of rcu_gp_ctr, modulo the machine's word size. Recall also that threads with even-numbered values of rcu_reader_gp are not in an RCU read-side critical section, so that lines 21-27 scan the rcu_reader_gp values until they all are either even (line 22) or are greater than the global rcu_gp_ctr (lines 23-24). Line 25 blocks for a short period of time to wait for a pre-existing RCU read-side critical section, but this can be replaced with a spin-loop if grace-period latency is of the essence. Finally, the memory barrier at line 29 ensures that any subsequent destruction will not be reordered into the preceding loop.

Quick Quiz 10.49: Why are the memory barriers on lines 17 and 29 of Figure [*] needed? Aren't the memory barriers inherent in the locking primitives on lines 18 and 28 sufficient? End Quick Quiz

This approach achieves much better read-side performance, incurring roughly 63 nanoseconds of overhead regardless of the number of Power5 CPUs. Updates incur more overhead, ranging from about 500 nanoseconds on a single Power5 CPU to more than 100 microseconds on 64 such CPUs.

Quick Quiz 10.50: Couldn't the update-side optimization described in Section [*] be applied to the implementation shown in Figure [*]? End Quick Quiz

This implementation suffers from some serious shortcomings in addition to the high update-side overhead noted earlier. First, it is no longer permissible to nest RCU read-side critical sections, a topic that is taken up in the next section. Second, if a reader is preempted at line 3 of Figure [*] after fetching from rcu_gp_ctr but before storing to rcu_reader_gp, and if the rcu_gp_ctr counter then runs through more than half but less than all of its possible values, then synchronize_rcu() will ignore the subsequent RCU read-side critical section. Third and finally, this implementation requires that the enclosing software environment be able to enumerate threads and maintain per-thread variables.

Quick Quiz 10.51: Is the possibility o readers being preempted in line 3 of Figure [*] a real problem, in other words, is there a real sequence of events that could lead to failure? If not, why not? If so, what is the sequence of events, and how can the failure be addressed? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img211.png0000644000175000017500000001617111672746142015311 0ustar paulmckpaulmckPNG  IHDRG*ʊHPLTEb``\ZZTRRMJK# hffvstmkkXUV856C@@wuv.*+rpp[tRNS@fIDATx] ƖRe\Y@q7$'O1*0 JBs%h nJRtӹg̬P{tܠU.^oƩ|7vg>h4]|{M0#wV%|]>PUoR|VK-gmMɺ{\q#IV a;&>49H憽Uas+(ٱ3Z3-6f ZiWIj7tEksqs̓ZPqȕFz7;['XM懶t3ht+/$ʼnv1y!]:cpbMt@#уoT>Ӻ1 =퀓/䴧Ǝ4׷$u(ZSՍWFIM;9K$]QK? ?vS>Dþ.;@o4r+atdP4!⼒PCU`]>3 K -I6ҵ$>#y1SzmMt-F3y+`=Qm_49W+Zۧ :7[ V59\уOeS͋ڄ6d+F!yѓlځrJ葵s[eıE1np@ *mqy DanF|6e)~jlo UZTٳA봬@_<ߩp,[(-] wl w\>$aQ Թ9ݕ^U?K3ȗ3J.i]mT],$4&>\tKO?(%.ao׾? KB`OÿoCpReDl *'8`]pl3kyuNAfz07?(GZx[gyw[{9ut͜#^{j9矋0gcIf \wVͰ SX2W +!9"yݻDoxڡ0b % ?fj# E-$!#bqTեc@CϰIJUj8r<`V?\e6yOt4у@J?jt5G)ۏDsLG8/ K-.42 #@¢G"?k;2|w:c 'y=(p2gmZdx4ԓFZ[PPXd!\U2(gួ6G^,/#*i8WGԨlLAIU=.v(TaAf(J$*-I[[l⿀$*kj.Nd#2-Qjf )*`pp{aQHN+OlsJ9Ou85YxMhxf1'5/'x")[rNU16pW{E#OtDKp_<;6W#flΔTyAĘx9Gk%%\(N?s|M(6wle.9?3C`U΄2?D\S*8R7'ї\vdphYv|DLWIsf8 wJp8T!Ŧ(xߤ CNP["9F" beA9;ȄIІyS"jҁG˦4t&RbGgB3˼lw{Q$8_)>=#T9Lhx54LtЇȤ*+872QؓhiR+Jr=AMde  40o+Đ(-k(_:nxg [ v4bU΀ AJK$J] ѨtL.74NPIccA-nik6H  dPNaw<̚j]gsm'lRsvU`;mnŠ0ml9eB6EX9[LS2 5$+&G /8o 0d9HA/B+^X" S x.jۖ.Z2r#n#okuKpĂ#jП'b@|Z<\*N(.`GA%sq@,cє܎f<tr>7@iy!:BiFt;S V nW9U[&IO|.`ޖ$CW[E2!~Ù%OX0F Sqʦ7,͏>E STKDg9dϩRLb)ZxjέJQV9d0SrX+|!yACżxiNqAA%y2o'_)m*BJ${6H][ $8uhӣgpuzxxɾ͛C-MZȈUK-cޏ,[!}v9NG[M)--˒}+h[T%O{y3%lxYhwõ^~5]R\Lι[BLn9ZEShO"_e_A&7h] D!T3J$ZeXoRP$hEl_"I7Lh5ʎMU,pSDKrXzFpcq֒cv l? >·N$Xn[ ZVovdtK0Q$0]$,"[$rͩFS9 0ca7l(礲QK4k}߃ r~[`k:qc|Xk}Z#$=Mw\Pr!ӲTvљBŒbn9(Tl?bO\d:CNl,/K+EkպQ^0k92|Te[wh)<{R $RʟU:FbŪ=j6fR+YuZ 6 sϋ2)ï~щfgIoK67Mhfi`qɔzS m ^W;.uIu8cD5xn !S}V{5|e3:V43:ƻH^̟@V=ҾۨVŔrM`)!@@>͋R’1W`bU+>҆T')]rT>eC73Ɩ8φqr2˫(2K #ʙ` +|V9SiCuK n|HtSS&I_Q$:uNIx|vT/oJ+G,67uqU/r\&L-u2„Q rd㥠 f/֤pWK{deZԋOؔރ}6] ;9NTYSThlC>3,@IE _wGYWDv\x_:Jtؤn>2}[r@>93щMy2%[™-EX9:Riv,N.6D;lZ9F(CIs9^)Fej|'0mK93.r73 V5 \N\;x?}!u9uksoL.a [ 5:UIU"r)_=W.,TV S˚CSQ_\`߲7nڛ ɗxZ8*<wHYUK]+2VUS~þ֕OOD^q#Tܾj4gzre"NOɉHOǛD?4$v2' ːhu4LoF1]D ,U:b? JbњŶ.6F}ZKd]#T#{:RR}랏 |ŒSw(h?{ ؍ؚ%p, ` N f$SnmDk*!VN{Fα}-wƾ*JHN*Ț glv⻧Ǩz熴LReKTs&oۼޠJZYg&Xغ3XG'ėb`WmC1<)D:5[f:QZх" #6U刪bCTOwF,=#h- |+=fOrIYORtb@=@ Q `;;(<}.ǃc%cT[gǻ$RGr:Od>k%]+cB*8ߏx?:Yڙ) +ع=4?8+2R/9?" @F0H[Ll]@&zOku`#տ96H{}Pc`I͓c:-` GJ·~-fK"‘ⷒ-[wl N}KxrY߿|OPrFg>KߍXa\D O qL+`NN+W-^Ό%sU@\klv}Oݩ^IkWY"7HPm}KL`|dD!m #xJ{VY-T[En桄r`޽beɤb#’09+-zv54}d T<%ݑ?d-G';uCZi=d? rYeI.G#;+KZؗ,~%x#07v;멼Q*!dnd{\_Pe4;X}6B=O*f#~C)^`BN\)/9tjkP2S oz> v($WQTa)maKR56.3ekYsaZR*lAI3SBgF.u4$̔B 9%kze].|-K]2#-lה4׼e-; m-vb"Vs ]UJ#+j4O ϙN!|]ߎ~0] nDO2mWJ @^/>4uMm { C/r<O7վC0@Zcs*߬LuUy 0DynsyɮԂ5WARZ!֤?C+fr4,'`-Wd֤{<?IekZ}2`fɂuӼ;>ZY@o&3J4~μIx9wi 3^ËVOʭ4NikCD6͒إp{7> ֎%QL LLw5zi& d"%^j<{͒ȭm೰V5mK -W$!WXlVI͕of0;v+$_UD0IENDB`perfbook_html/node317.html0000644000175000017500000001457511672746163015662 0ustar paulmckpaulmck C.7.3 ARMv7-A/R

C.7.3 ARMv7-A/R

The ARM family of CPUs is extremely popular in embedded applications, particularly for power-constrained applications such as cellphones. There have nevertheless been multiprocessor implementations of ARM for more than five years. Its memory model is similar to that of Power (see Section [*], but ARM uses a different set of memory-barrier instructions [ARM10]:

  1. DMB (data memory barrier) causes the specified type of operations to appear to have completed before any subsequent operations of the same type. The ``type'' of operations can be all operations or can be restricted to only writes (similar to the Alpha wmb and the POWER eieio instructions). In addition, ARM allows cache coherence to have one of three scopes: single processor, a subset of the processors (``inner'') and global (``outer'').
  2. DSB (data synchronization barrier) causes the specified type of operations to actually complete before any subsequent operations (of any type) are executed. The ``type'' of operations is the same as that of DMB. The DSB instruction was called DWB (drain write buffer or data write barrier, your choice) in early versions of the ARM architecture.
  3. ISB (instruction synchronization barrier) flushes the CPU pipeline, so that all instructions following the ISB are fetched only after the ISB completes. For example, if you are writing a self-modifying program (such as a JIT), you should execute an ISB after between generating the code and executing it.

None of these instructions exactly match the semantics of Linux's rmb() primitive, which must therefore be implemented as a full DMB. The DMB and DSB instructions have a recursive definition of accesses ordered before and after the barrier, which has an effect similar to that of POWER's cumulativity.

ARM also implements control dependencies, so that if a conditional branch depends on a load, then any store executed after that conditional branch will be ordered after the load. However, loads following the conditional branch will not be guaranteed to be ordered unless there is an ISB instruction between the branch and the load. Consider the following example:



  1 r1 = x;
  2 if (r1 == 0)
  3   nop();
  4 y = 1;
  5 r2 = z;
  6 ISB();
  7 r3 = z;


In this example, load-store control dependency ordering causes the load from x on line 1 to be ordered before the store to y on line 4. However, ARM does not respect load-load control dependencies, so that the load on line 1 might well happen after the load on line 5. On the other hand, the combination of the conditional branch on line 2 and the ISB instruction on line 6 ensures that the load on line 7 happens after the load on line 1. Note that inserting an additional ISB instruction somewhere between lines 3 and 4 would enforce ordering between lines 1 and 5.

Paul E. McKenney 2011-12-16
perfbook_html/img28.png0000644000175000017500000001412111672745751015235 0ustar paulmckpaulmckPNG  IHDRO8ց}h} nrp 3#Z}qhȃрZjֵ%@!06>uqrhfweiqqʣk1N3k׺7UdGcokiodz wKE_9k!mxey7tdtnvi43ӱ8X:nlYmú⋠dڬ^2}zƩvKQ#V}!f;wmf7G -ZZĬk/8].L^53x[u4n*:ˣ}S<yv}v+8M#@Ӵ%sFZr]wº2]٣! HpZ}M?o7pp_xƛg|>n,Q=khs Zf55zrK4=u]!j^@\W`~ZzGqL|{Fp )|rHnz3zڨoj=d=4Jiht3i&qS+@M65 ,M'ﮧFzzO=%z7;FQB3^n/uJ:i th:0 J2.1B^YUՉ5UTCbo{Sʆ!%W|ӱ8٨-;&q|= Ńnk[?Q83ՐrvBcoG+l*V+`ءp#17L5)94&ZZuN ~H_ܴ5n*ZޜFec5 ?]>R黐g4X9Ndk|E"!{÷:jlͻhMieK J2*7gXî"ʚ" 61x֢i%@x +`P>U45(nѧ$ހ:ZPosn~1OK^x 1­Ɔ^іsɗ ƝNӐWQvNJ+ɍW]/h|;Ⱥ K/ ǀoGmg"Џ}Tu e[ErȩZfтt'Lٚ,O$I3%WM~ bS(1zAf;(1Bʢ*t^T2xS<2ms`W~t(/xTӁEYV.3 q;'Ȋi&W`Pgs^)d:cuGۦݥw%3t-D5y|\]h$ %eN-vwCtNρ`2d@ӝQb0lZ;H ~* Q"r98E07\)^a GUiXvp/ladÑr!Qce»H=lrQH܆6 + UY5 3ƌfh fd$3s3(Yю ||-YpG{Zzj\^ѓ" Z%fxeeN LycN7"՝ DUh=y~.mG B*_늮 w[0w \cl٥=pгOq/3x$'OX%uJzKHNVr!'n쑴"ꁅk7lÑV+Hh^{9EMWQ>2"_2iQ n(qT EcQEB6މ}L?;1wBnAQ"N n  F.OIxV;m$qyq"EX3 I5U1b:N'v,61ڛ4Dt.yگiDkcR bs=FNvxTG /%dlzd;HNr"7- G> q<;[ b[7E5?UXXјu,"T\mK )ba~6vhE控w'QG#Ƕl l?Ԑ`LgO]:˃W3gK90~Q⟧a]l.gn=m;/c\ݷ{LD&;)PwsLu*zst{xխ9|J솄IN }r40j4wlY?J|,FPLڬ)/6S3`X ;`9y}zp"u>"ԴRt:ɳTXvÊgv(jA-#d]NW")7hu8 <)*u[JO3TP%!12]80Kx;;$+'w;Xt8\p7ܭZ 0SLd…P7_O]DalX"@49KWKsO [5&!2~+1gR FXos RxƸlnPl ziY"AY>I K~31D;nr2c몳8ph.q~PQN5`Z`LvL|P7g]J1ІpH矇#|_Æ3]>@Y wH{2c&!dP4>2ױ-256@3}Y;c Wu,uOhsaسR53%~}. Y+;^_q\E0:T>艇Y ^PzŏװLT…B@'o^HA'!*rz(ݹ!t!38~_|'DWk!^ʘ)9+.{AXw^-> 0%?idJex<r?Ǩ.w9ݨxٴ\`c[L\".x9Y&?q%$y?E\}x):܋ݖc XDRE-F,];,P%~V. -Pu:ն򥰶b]-\™.T,]MEX 9 5S+Y<նuר:v׶j|ZʟOw}/kGN+pڸ3S6%fG?/p?/\Вy!GLϋ hI0<=$2`dHPc{Ч1f8AORO?c:-Ɍ811 ~7=j4b&,N  F$3\ fx6Gn,"(13I@'Xĸ?c:DɌ\g)ďƢ{ 4{ K)$5Dʅl OQcԳ>޿LQsHgƼ @Eʯamyj=+AT,Q*dV1Ngzhjaﮈ"$~,y.8 zO@wWĎtd`hDP >p09SĜP sA-e:xwEDmk[84rc[2 9IZ +;U:ͫW%WB6oF|N+Jr n,3WqV6|~UM1:0SǢ|9)H D6gdW2WE3 Кp}X/ճ2ְJ~9}[!3qh.㪥w<n;.Qj2(;.rQ_1zO֥s],G3NQR>'׻rDH'׻R(^U"CT{GW,^2p{zA DDzU…WWDYJW.r?Y IENDB`perfbook_html/node224.html0000644000175000017500000002036411672746162015647 0ustar paulmckpaulmck 14.2.10.4 Data Dependency Barriers


14.2.10.4 Data Dependency Barriers

The usage requirements of data dependency barriers are a little subtle, and it's not always obvious that they're needed. To illustrate, consider the following sequence of events, with initial values {A = 1, B = 2, C = 3, P = &A, Q = &C}:



CPU 1 CPU 2
B = 4;
<write barrier>
P = &B;
Q = P;
D = *Q;


There's a clear data dependency here, and it would seem intuitively obvious that by the end of the sequence, Q must be either &A or &B, and that:



(Q == &A) implies (D == 1)
(Q == &B) implies (D == 4)


Counter-intuitive though it might be, it is quite possible that CPU 2's perception of P might be updated before its perception of B, thus leading to the following situation:



(Q == &B) and (D == 2) ????


Whilst this may seem like a failure of coherency or causality maintenance, it isn't, and this behaviour can be observed on certain real CPUs (such as the DEC Alpha).

To deal with this, a data dependency barrier must be inserted between the address load and the data load (again with initial values of {A = 1, B = 2, C = 3, P = &A, Q = &C}):



CPU 1 CPU 2
B = 4;
<write barrier>
P = &B;
Q = P;
<data dependency barrier>
D = *Q;


This enforces the occurrence of one of the two implications, and prevents the third possibility from arising.

Note that this extremely counterintuitive situation arises most easily on machines with split caches, so that, for example, one cache bank processes even-numbered cache lines and the other bank processes odd-numbered cache lines. The pointer P might be stored in an odd-numbered cache line, and the variable B might be stored in an even-numbered cache line. Then, if the even-numbered bank of the reading CPU's cache is extremely busy while the odd-numbered bank is idle, one can see the new value of the pointer P (which is &B), but the old value of the variable B (which is 1).

Another example of where data dependency barriers might by required is where a number is read from memory and then used to calculate the index for an array access with initial values {M[0] = 1, M[1] = 2, M[3] = 3, P = 0, Q = 3}:



CPU 1 CPU 2
M[1] = 4;
<write barrier>
P = 1;
Q = P;
<data dependency barrier>
D = M[Q];


The data dependency barrier is very important to the Linux kernel's RCU system, for example, see rcu_dereference() in include/linux/rcupdate.h. This permits the current target of an RCU'd pointer to be replaced with a new modified target, without the replacement target appearing to be incompletely initialised.

See also the subsection on @@@"Cache Coherency" for a more thorough example.

Paul E. McKenney 2011-12-16
perfbook_html/node130.html0000644000175000017500000002070411672746162015641 0ustar paulmckpaulmck 10.3.1.3.2 Example 2: Maintaining Multiple Versions During Replacement


10.3.1.3.2 Example 2: Maintaining Multiple Versions During Replacement

To start the replacement example, here are the last few lines of the example shown in Figure [*]:



  1 q = kmalloc(sizeof(*p), GFP_KERNEL);
  2 *q = *p;
  3 q->b = 2;
  4 q->c = 3;
  5 list_replace_rcu(&p->list, &q->list);
  6 synchronize_rcu();
  7 kfree(p);


Figure: RCU Replacement in Linked List
\resizebox{2.7in}{!}{\includegraphics{defer/RCUReplacement}}

The initial state of the list, including the pointer p, is the same as for the deletion example, as shown on the first row of Figure [*].

As before, the triples in each element represent the values of fields a, b, and c, respectively. The red-shaded elements might be referenced by readers, and because readers do not synchronize directly with updaters, readers might run concurrently with this entire replacement process. Please note that we again omit the backwards pointers and the link from the tail of the list to the head for clarity.

The following text describes how to replace the 5,6,7 element with 5,2,3 in such a way that any given reader sees one of these two values.

Line 1 kmalloc()s a replacement element, as follows, resulting in the state as shown in the second row of Figure [*]. At this point, no reader can hold a reference to the newly allocated element (as indicated by its green shading), and it is uninitialized (as indicated by the question marks).

Line 2 copies the old element to the new one, resulting in the state as shown in the third row of Figure [*]. The newly allocated element still cannot be referenced by readers, but it is now initialized.

Line 3 updates q->b to the value ``2'', and line 4 updates q->c to the value ``3'', as shown on the fourth row of Figure [*].

Now, line 5 does the replacement, so that the new element is finally visible to readers, and hence is shaded red, as shown on the fifth row of Figure [*]. At this point, as shown below, we have two versions of the list. Pre-existing readers might see the 5,6,7 element (which is therefore now shaded yellow), but new readers will instead see the 5,2,3 element. But any given reader is guaranteed to see some well-defined list.

After the synchronize_rcu() on line 6 returns, a grace period will have elapsed, and so all reads that started before the list_replace_rcu() will have completed. In particular, any readers that might have been holding references to the 5,6,7 element are guaranteed to have exited their RCU read-side critical sections, and are thus prohibited from continuing to hold a reference. Therefore, there can no longer be any readers holding references to the old element, as indicated its green shading in the sixth row of Figure [*]. As far as the readers are concerned, we are back to having a single version of the list, but with the new element in place of the old.

After the kfree() on line 7 completes, the list will appear as shown on the final row of Figure [*].

Despite the fact that RCU was named after the replacement case, the vast majority of RCU usage within the Linux kernel relies on the simple deletion case shown in Section [*].

Paul E. McKenney 2011-12-16
perfbook_html/node102.html0000644000175000017500000001704411672746162015643 0ustar paulmckpaulmck 8. Locking


8. Locking

The role of villain in much of the past few decades' concurrency research literature is played by locking, which stands accused of promoting deadlocks, convoying, starvation, unfairness, data races, and all manner of other concurrency sins. Interestingly enough, the role of workhorse in shared-memory parallel software is played by, you guessed it, locking.

There are a number of reasons behind this dichotomy:

  1. Many of locking's sins have pragmatic design solutions that work well in most cases, for example:
    1. Lock hierarchies to avoid deadlock.
    2. Deadlock-detection tools, for example, the Linux kernel's lockdep facility [Cor06].
    3. Locking-friendly data structures, such as arrays, hash tables, and radix trees, which will be covered in Chapter [*].
  2. Some of locking's sins are problems only at high levels of contention, levels reached only by poorly designed programs.
  3. Some of locking's sins are avoided by using other synchronization mechanisms in concert with locking. These other mechanisms include reference counters, statistical counters, simple non-blocking data structures, and RCU.
  4. Until quite recently, almost all large shared-memory parallel programs were developed in secret, so that it was difficult for most researchers to learn of these pragmatic solutions.
  5. All good stories need a villain, and locking has a long and honorable history serving as a research-paper whipping boy.

This chapter will give an overview of a number of ways to avoid locking's more serious sins.

Figure: Locking: Villain or Slob?
\resizebox{3in}{!}{\includegraphics{locking/LockingTheSlob}}

Figure: Locking: Workhorse or Hero?
\resizebox{3in}{!}{\includegraphics{locking/LockingTheHero}}



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img154.png0000644000175000017500000000062411672746132015312 0ustar paulmckpaulmckPNG  IHDR)"Gݐ0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(1N1E_FBZhS !K{4l-(B-@t\)k%Q*Fߙcq@X7 0V{ib1Y~A/`wՄ/-v#LfFJp)īd6|xޡs5duF0ZVBА%짾g6N2,%8l2Ӵ6{s Uz; zՁkU$[֍ؑ^`ܙ,/#Iw^*vTׄ:8a*IENDB`perfbook_html/node119.html0000644000175000017500000002027111672746162015647 0ustar paulmckpaulmck 10.2.1.2 Atomic Counting


10.2.1.2 Atomic Counting

Simple atomic counting may be used in cases where any CPU acquiring a reference must already hold a reference. This style is used when a single CPU creates an object for its own private use, but must allow other CPU, tasks, timer handlers, or I/O completion handlers that it later spawns to also access this object. Any CPU that hands the object off must first acquire a new reference on behalf of the recipient object. In the Linux kernel, the kref primitives are used to implement this style of reference counting, as shown in Figure [*].

Atomic counting is required because locking is not used to protect all reference-count operations, which means that it is possible for two different CPUs to concurrently manipulate the reference count. If normal increment and decrement were used, a pair of CPUs might both fetch the reference count concurrently, perhaps both obtaining the value ``3''. If both of them increment their value, they will both obtain ``4'', and both will store this value back into the counter. Since the new value of the counter should instead be ``5'', one of the two increments has been lost. Therefore, atomic operations must be used both for counter increments and for counter decrements.

If releases are guarded by locking or RCU, memory barriers are not required, but for different reasons. In the case of locking, the locks provide any needed memory barriers (and disabling of compiler optimizations), and the locks also prevent a pair of releases from running concurrently. In the case of RCU, cleanup must be deferred until all currently executing RCU read-side critical sections have completed, and any needed memory barriers or disabling of compiler optimizations will be provided by the RCU infrastructure. Therefore, if two CPUs release the final two references concurrently, the actual cleanup will be deferred until both CPUs exit their RCU read-side critical sections.

Quick Quiz 10.2: Why isn't it necessary to guard against cases where one CPU acquires a reference just after another CPU releases the last reference? End Quick Quiz

Figure: Linux Kernel kref API
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct kref {
2 atomic_t refco...
...ase(kref);
25 return 1;
26 }
27 return 0;
28 }\end{verbatim}
}\end{figure}

The kref structure itself, consisting of a single atomic data item, is shown in lines 1-3 of Figure [*]. The kref_init() function on lines 5-8 initializes the counter to the value ``1''. Note that the atomic_set() primitive is a simple assignment, the name stems from the data type of atomic_t rather than from the operation. The kref_init() function must be invoked during object creation, before the object has been made available to any other CPU.

The kref_get() function on lines 10-14 unconditionally atomically increments the counter. The atomic_inc() primitive does not necessarily explicitly disable compiler optimizations on all platforms, but the fact that the kref primitives are in a separate module and that the Linux kernel build process does no cross-module optimizations has the same effect.

The kref_put() function on lines 16-28 checks for the counter having the value ``1'' on line 22 (in which case no concurrent kref_get() is permitted), or if atomically decrementing the counter results in zero on line 23. In either of these two cases, kref_put() invokes the specified release function and returns ``1'', telling the caller that cleanup was performed. Otherwise, kref_put() returns ``0''.

Quick Quiz 10.3: If the check on line 22 of Figure [*] fails, how could the check on line 23 possibly succeed? End Quick Quiz

Quick Quiz 10.4: How can it possibly be safe to non-atomically check for equality with ``1'' on line 22 of Figure [*]? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node458.html0000644000175000017500000000615411672746163015662 0ustar paulmckpaulmck E.8.6 Discussion


E.8.6 Discussion

A slight shift in viewpoint resulted in a substantial simplification of the dynticks interface for RCU. The key change leading to this simplification was minimizing of sharing between irq and NMI contexts. The only sharing in this simplified interface is references from NMI context to irq variables (the dynticks variable). This type of sharing is benign, because the NMI functions never update this variable, so that its value remains constant through the lifetime of the NMI handler. This limitation of sharing allows the individual functions to be understood one at a time, in happy contrast to the situation described in Section [*], where an NMI might change shared state at any point during execution of the irq functions.

Verification can be a good thing, but simplicity is even better.



Paul E. McKenney 2011-12-16
perfbook_html/img48.png0000644000175000017500000000767011672746144015247 0ustar paulmckpaulmckPNG  IHDR a6)Y9PLTEMJKZWW# b``mkkXUV856iffC@@wuv.*+rppˆtRNS@f-IDATx Eyb}͜9;9]"byJ!@zQ[(j c9:c♵J{oRT)*#Csxb6J;/;w {N| O^+1 xA%ݤ>1pj.GjxOR)8e4 Ɲw3'>^w=S+7u"uW$LQ5ɢ"0 S?3oH[9:X+L߃bTN)#<΍! 8{((> $U}C)$hObLJlGfl(sr< _a?%LV#7 da2+ 'HmNgl[p#/#вLBLҢ.FL?PŢJ Bh~&O_9c،n y?jtHY3cqˬAak7`Ceb8`X%E@}I*@LEEX(g~!>RFfzPT=Hmq"}O bk@u/+m5IS8%5%A T O2=H$vR~`rvy7IGP!qvtZV!oRj_@i\fa $ G[(۹`d39PUziA%(#z2=`~##x7EcRo9a)) dNeeZ|Ɔ/qSR)'X>'e ѷAp#M.k7Msljr2+rd>k\Eʰ h'_v}KDWf5>y(6p,f\5g59)#!$lrbB&I!YWo7/{qշgv,5y+XwlPZ\岲&@) &+ƈ[)' >=PW@Q7 #D55F޵EJ P 5M4Rf"":S+s @mtRUA[#K.,(td%3JIGׅC5k_}* C5}jThwG2ƕ:(:칺0U[EMSؠ6!vH{-<:HI-hBf-y:GOo9 ֬}nyk silh I{"&Ie_U s[у:&% F2R$ԛxJYmqDO _'~i2 R>f2 *nHb1Ɉ=N2tMƏ5Wv}wtQ]CC-TJ`_@@ViV a|8+22òН]{ݬ:@?̊2:{鸯0k?ъ]Gگ0|C|~ɱ\h =wso{.j40W+snoPKM/[{&KT U)q(_PiKvT>jVB)ZH큽>M\)mX1Smр,#SwghkFG׭yj>j݇eL+'A jm~F8[&qytrQλ.dΡy^PX Mtf'l۹wޣ/f~w%ֽ)X+8L?z RX+Vڅ ƗBش#Чw#лvvQ.[QKn?M~[`[Mކp0w@{US m`z,K3Fj)Ї5+iMS=r.f +,ޡK>{)E>fbzq{ G  ~~'p9-VGbcC)av @ viGO)MЦi@n2n4< 8$9.45j|Ί0L!$UdUefƱ٠7[IZJdФlOMnvv7klMB|9%U7k)L~J Q`u#P*$|s&`. xO  dڔ?h*$UgUej˜T' cüh 8Jq|RP":L2i&S.-)ϙأ`7`/<1`ޗۢA0^ yRL^%>8wB/;Ve kΣJRIhMf8= ё=vP~TF3ZacMԾfnC铭g-=AmkίK[&,-k*3C$s"#pmbZ: S% ;'Pʵg iϤ_ _=?)&M%YULt&Rh8 ]:8PbM/%<z7B)Ǘc,5rԎk^`Ҍm ׀bZ0(J6k pK)rʔǘ#v Jba0Ro n`"OL;k p q a-jZrYJ Y`UABE:͍x)`PC59Xh> }ʵIENDB`perfbook_html/img322.png0000644000175000017500000002157411672746121015314 0ustar paulmckpaulmckPNG  IHDRܺNPLTEb``^\\MJKPMM# hffvstmkkXUV856C@@A>>wuv.*+rppmjk.tRNS@f IDATx]*aCq_t5=_nAEXU1? q{p3HgkE!U D ߔ0FN h4jEQ:x9+||;n}|]rwVVtҝpWm=B8~%ִ4f^m 1t5G2& o?WW6R% a{s2ŷ*u1_ 3k㏮ FXߦO6KB6RuJ6Ek*,w VN8;8QoeXy8w'ӱk+c[7P#'+S)NLDZ}]yC>0“,P\։##Bm;2kĵ2ye\F :h 46^l;" 7&nUX3g;Wx^rƋO^@XZt.tZ8yg.ALXlδ]m,ancpifW5,\D9MxHQ4f*C{?+]/y+gCw@OYxj-ƹ%6ӸcwM mE,esS\K Mȋid%H5mkjAN%>}u=$^r YTq0g߰bf ZHg,;@|| ԥWg M`M|c=o,м2]V1jMy'PcLW cЛ=.5*\8B*E~mI.URڟLnw Kc)oԬ |Gu5Q {A_kϗ"#mZ0h s9jMftVy pEB 梔i;/&W! .޺4JV`>+xOcmSa ă%0(j ~x_YրJ|poN)׮_UKMljcJ`)nkA޻yNvǛGCr` :YՊR oAES[ƌ0wd:HժDW+P/쑚/?CPImI7!fb99g Q4ޑCk~\ Ƃ2a,4,l[;ZYJΚP4E9xgwu,`&p2_~V8Ztm (e>XKSq{ k=` PU"̀'yT"/w{(b) ڡo!j%޸0.p(K%,j48=.{ 7RRkz;?EclSZ*6rJM_e5VwF*hl;xߥvr?8@,~L[(;@c eOacU) y)[%k5rBWjU7TJN7Qgd l\KeHX+F3ޝ033;>)S~Nt>LJsSew?C=e&;잩7ujҽmZȼUXT ވ})+j U-VɐiܼnGZ;i0]cfr⼉GSڴgC *4JAȄpj)c&wFvOYMbN΃b~Hx! >Zh߈[D(ٴ`UGNደǯ`Xb6tAEKmFWZoYgE>JQBΡ51ǃT)Wzn^шp|sG-"H z7+DטXGY_1k c b.$Ra|A/B:\8Th;[@!iMmj(zʧbC(4st$5JLL^T&oU]0 AoV .hQ%@"^أw=)[wQ$ TwykRV1ԕ1#IGVA;ԡ+Ӈ/7uy3a0hg:.]Tqg-'NʲmO80g&ipͧsi.qAg6a5ط;(g ؄g~Nƒd> `3F ”}r%kP@vtށk*03DaIVUh(>1YuQ-qRKsm8$o8\ÉPk&VH^Cybx*`囎h&F52_rB R7G!*dD Yp۠k=jTj_AohH5xڒm"> x: \rؑaDP6f?jK2.^]X=PXt-uŌz8bZOB"Z<]i'ٵC#_c7#r|\8^>[U@́,|(`#zC~ΰ H[mŸ|pT| e-<?U-[ w05!t!Tf׳:.q@D"hSJ)BDɜnFxf?h#5f)ck(C"Z6D&q%_WNa- oƓфD\ hu0B.qACcL.˰`Tb8.py ;l6#_wةž0׮W9ؼf=ꁮ6ؼRsϖh= g*cd.o_|Mo}r{Pg])*bAF0O ѫMgoR^53g6z=ܒr2!1;AͤҝbdJAPѠZe&GYUԝ@ 2@W:&grdJfȩò+5m$3 pNFH< l;m!49 O2i(y$3qxXc]DEbH 1f?Ǣ4a tiB2W9S} sqP md5WZXKi-awd9bٳ5Օ^~(=Pnyhso~; PǏ.%PB;|$oTA23JAvfr5TM߽RA@כ )4gEdFs]|%`R!<@(]Iɫ V`F;íZ(ja7ܓ/Ģn9&+2O燑m8&i}Pу%tFpO\QmCdYwk}goq]NUp,t|ώG&4|.?(`Z.|~,ؤ'W;`FZ*(C;Q11GweCy Wqq$Ӓϐcm~-[̞ jrnLũqB+,z5H~YKxjQWokiZqR.D^.N4)GG X823`6io6U4}R $N2@h?|"&$Iq80:ОEA. m^F1)*MPϼLcehiͱ[Gǂ=vaxF*>R,F:>R,F_Z"F_ byv8Gt uqq\+tg ~Vn`P!.(;̀|ri:$G5J߂c浊k p:n =QJ$ΕNOF䃐xOk?dRfXfOJZj~6V+?ЮyD,AXiz''@R>9peWB0 YKK@QÈ=o.Lq搜4"zМ=c?űͻD-px.81dB>4f|!Jn&Sb tY{Yhdk  )'㡠q*'> _&TpѴ (o*ֳ ׳.E~{: V2V p n~=#yۘ(Q7RҚE1 ed=,Qތ O'-O{5eT>'Nd~Ah,g[dV$sfZr7eoL+PaXh ]6+r%M4&Z" ]%n¿1%Gux |;(W.Oʴ6"/0WR-ʀa/~%u6LmPU{dEyn߁&B<څI߶uu. &?5` $d&3mT|$nM@ <݄#Jj$`3ij J%("dmj.l\æԡQ݉PV@#O'Kh hS(oR3ij%㺓H)U aXiqME iެи;'W)m1k#|DkJ߇mYs: /w_]pa=LaE0n򌸇=ɦ3=b@>p2/)0}cJ5`^>ו|VE%Ehߚ?, j_BA g&˰@],)}cN@5`^>Y:HsT-wQ7b-/_mګ@i-mQ8ǢUO~s/\0k$̙I۴\·К< $FguNc6l+L3V4p][$1:[ī󰯑~qvvi ̌#& PfH5p–\fs :<RGk'>H-o" Y<$Lj4\j,SBj}`MGBƌ81MaOr J0zG Å|7g",w`VS(ͤaU|Z'T Tpeb; I[OeJ^3 6Ad$yJR7Y6v 7fD_{όwh&/1سE3r!ޯ"8;2)wNeJ_݀pk@#EtR3,,`s( rPbG xH [&0ND~O""/&P&HgF&" p%:ELh]ygW\{$}^Nb8Lq/`+)٘?C b[N4ͥFӡƳ&xlj-q7U#C쥠ˡvxX%uod@fasxF5D{I?RW>|Nzk.3:>ss>˵d o̤)_r4/gPLYpu|v?m RQ*4o'Y<sM.cEw7LY8Tv6\ ͤIΖT;ݬNv?yG0XJ$D!8Ub`?S/(c6<0XM.z.3L<ٽ@!9 3L!9s ~a \ b#?/W&Gֺѹk.?dB獃4u ƹ5HM/'uNb/ dm'oi)jSng$?ǩGo{(H3L9I&.2#`stŚAA {@i:$'ozxF ٤ 2x @se^;$V8M]< LS6n>:E2Ǒ&$x)!W .kgЌPڿn?s?f$]… 83sj{s"㬝 oǜSgimNmǜglvv\;\khcmm@y^+29s‹2~%)Kc0dzAn)|:>9y>E(g DH6o2=5+v`&'g,>~ Z)ۡ};M';__hKigJdPio)J8MMB*٧)2@Ie$ Ќ`|AfbO韇3B =dl/Q$f*ӉC=I$b= qE 2Ќ1Xc4[ }gQEo[N6M,ߕ9M3 N".>16og9G+fO8~Uq6&Nl_g zY |gr-i.6_;TGdrQ%Va:M(߿rtud@ޭXKIENDB`perfbook_html/node28.html0000644000175000017500000001164611672746161015573 0ustar paulmckpaulmck 4.1.3 Atomic Operations


4.1.3 Atomic Operations

One such obstacle is atomic operations. The whole idea of an atomic operation in some sense conflicts with the piece-at-a-time assembly-line operation of a CPU pipeline. To hardware designers' credit, modern CPUs use a number of extremely clever tricks to make such operations look atomic even though they are in fact being executed piece-at-a-time, but even so, there are cases where the pipeline must be delayed or even flushed in order to permit a given atomic operation to complete correctly.

Figure: CPU Meets an Atomic Operation
\resizebox{3in}{!}{\includegraphics{cartoons/atomic}}

The resulting effect on performance is depicted in Figure [*].

Unfortunately, atomic operations usually apply only to single elements of data. Because many parallel algorithms require that ordering constraints be maintained between updates of multiple data elements, most CPUs provide memory barriers. These memory barriers also serve as performance-sapping obstacles, as described in the next section.

Quick Quiz 4.2: What types of machines would allow atomic operations on multiple data elements? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img213.png0000644000175000017500000001623511672746116015315 0ustar paulmckpaulmckPNG  IHDRG*ʊNPLTEb``\ZZTRRMJKZWW# hffvstmkkXUV856C@@@<=wuv.*+rpp(tRNS@fIDATx]*nn\11&&9v"W!4.[OpʭT*U+K7{F UAW ZeMo 2uq&;`ʗ~lp܏FASWD 3r<jUߥ{ EZnW@tUjY[Sc?WF0=}Ō?&Ym̹GZ67u֯7 XDɎ=p4g^њiQ0KJhJv@PC=i+6<@ŲwȭY,ݦc{C}P]m;ǣѭdlƓy'gvQꌩmf[~7!DSWN4, t8ζNZ{PӞ&>t%9Iw2:g9Tuda?st;GwDkp4-^#z6s{d+N5/"kڐFOz5k)=G֦ynVz–]Ǹ*y ܃f( ︉ɀ ρ̈4!d+S^Y]*n?*aMn?}"m3gkܗ. yk3_ڨjHUBAf㳽)TiQeɓ ǂCpWnb;\>|,+/c8Y<2ܮ? y-TUxE.:"`'ɗ5U*]+ѳv|2,4h֭NLzB(EҲi혪FZ92u_ct,ܑ;-A’csgG)#RtWR.{V, _( QM9PuAG{G(Ҙ@Xr!M_õ=Rl{ɰl~?!=> 6> /[0p~MĖh^ݏ9*ppqNn2|EN|_ 6ù*ci7d4s^:=tx7[I~|\͡#^)x4Fd9Ns}sr3}<]wƝXs6$nzǃ?9u$m|D;bBF{$XRxNcSx [ߔdjZG@'C52cf?H#?ڇ(V\jxW|oJ8?@ݠM [ 2q"4| faΚ̞!N5=x`G:-xi:dy ڬpNhQr,q@ nW2'?s2xUegA6ãe/O[,)[rNU16pW{E#ODKp_<;6W#flΔTyAĘx9G Ҷ-,N 9e>4ec~}vu&_b9GpfʙP?D\S*8R7'ї\vdphYv|DLWIsf8 wJp8T!Ŧ(xߤ CNP["9F" beA9;ȄIІyS"jҁG˦4t&RbGgB3˼lw{Q$8_)>=#T9Lhx54LtЇȤ*+,UӪŸm6yVjtSr@I:)l $"FrրYmq KM05Lak|FJ0 HIa UDKQ$%Ɨ J>ilu"-my͆u J8ΒYS`y턭4UznA?Xl] k̖3\6 >@>.dc)X48 3+~=x,ry]SN<`p2sȠ R"_Tx)b27L-LZrN&n[jndjK*|+n#oku^%8b5OZ\: >G?-. R'SRd.>ŗIM짌f<B9b_ʹ 4q#B:)S?v_7WΉy*;Edazߥ)w%.?ETOG>0oKgك"a̒@Ӄ',NLr8 eSGtϢrpa%S"c})& ?z|pB5eV(]2)9V[hj b^4ZȸР<7įД6tS!\M=s䭅kq:4`3[pn~ɺ =h<\(~~ߠuM*P(I_hayAJC~,WKQ~$-0U(;6V\RiO-%a9Ņ[K%VW,8:`m/hZID56z3,zErKŒur_䋀SoRInD7fq6N2CE݈q*X[~IGR=k]CN؊ᓲޥx*ISAϩc/Ő̔[<>Ϳoɔj.'"p/%t(gZS-Z=Ω23*mn]Bin 3 bES';7 •kڛm}#XW`;ׄ eK]s0at_kÄ'/W0|&]ڣ]%+ת^|d4/K )Ȕl!^$7 g BC`J;HFK۱D_;i 8'EixiAÄ':ri/̸,!܌ 7 7K[%&'ܲr)7Zt:ArRlB}[M2m\-lU*pV%uWd}0\6\\PY~*PN-k-NG}q ~Rc8Hio$_V\jH~{S d$kM"#fU-UwXUNqpb=x"/v\߰hfW%F9ӓ+qz~"HNDz<$'zl!9YTмna͠\t.زlhJ`TQ G(dvf+1Ekۺ1b kwf/1uLR82T|JKr.b{>0K;O}x`7bk­,خ}+PF:1b#NP޳slj];s=WETIo2)5[Yጭ_pÎ7b[|UܐVIljnTE76o7GFi֙ fx%a+ ?عUu O NM"NLVtxMi99O}Q쯂ޣ s?IU趐>d2&/Id hZ*&zUAAN=w-.+\Qt#ъD2shaett-`wa[*_ohܽ>‚k>?l9y6Of Ski~c NYۋ 2M>6ybEmaJ~1v,!v!,9B pعx8w?j p0*snӕXrx/UM^sEÏ'k9MC-[N;gƘ 8V-[ͦܟ(6; z-6gZc-'h*>wF,=#h- |+=fOrIYORtb@=@ Q `;;+QxDw \Kƨ)zώwqI FXu >}>~Kǻ8SW>DŽaUqvqt7/`#3SV Ws)!{h~.qVdY_r!#D`غMx**3FplVb5,֕'y#IlfIMt lӴ>^_xo55|4f+}[34uz /|1[ooZ̖Db#o%[[?7 `3ʿ1j }BoV}宸!JRc_3?p2vZRo 6-=vf,;שּׂ bZc3&5~NUJNZ[eRmAn#7/[bæ@%# nUX{Tjq*r4%TwW+K&Ud1Yha׳%%[u:dC rtROY7Ѻ8SKV~-gUrT;￳}ʒWY7|k|BvlHU6 OÏg#/S*;pn6Q>; &!)x)e I %S8?6`7MrAh;F.$U_ac2S5!BoF0䞴03-tVmR7LsIR_{L)x 3)PRPp8qPvx܅rԥi.>vM~฀ݎ~rl'_FXNyY5_H[dvƈ+ftP~i?x&3|‘4K oÿ7`iLD SGzOgAj4ri8Η {/Imέܕ2{eR[^ 9);B6;u(‰O~$'eWX㉛&Z%JQQ>K]Kv 0uV*Q Y)OIّxf'Z8Ӵu]gO%N~<$,ŹB;{ a;y*7/z:1`/.%y{+U SX>`/-h~Iǝ(ʘ7F a_[kC+0:E*pa->@Zcs*߬LuUy 0DynsyɮԂ5WARZ!֤?C+frPX+HekR}=rɿ$xƲ5>O~NdËi, 7|HM Qg$Dfsՙ /XrVc!rL xWKE5l|Mki;!nR5{VS0߳|%%^j<{ #ˮ)m೰V5mK -W$!WXlVI͕of0;v+$_QrzIENDB`perfbook_html/node339.html0000644000175000017500000001553111672746163015657 0ustar paulmckpaulmck D.1.3.3 Read-Side Implementation


D.1.3.3 Read-Side Implementation

The code implementing srcu_read_lock() is shown in Figure [*]. This function has been carefully constructed to avoid the need for memory barriers and atomic instructions.

Lines 5 and 11 disable and re-enable preemption, in order to force the sequence of code to execute unpreempted on a single CPU. Line 6 picks up the bottom bit of the grace-period counter, which will be used to select which rank of per-CPU counters is to be used for this SRCU read-side critical section. The barrier() call on line 7 is a directive to the compiler that ensures that the index is fetched but once,D.2so that the index used on line 9 is the same one returned on line 12. Lines 8-9 increment the selected counter for the current CPU.D.3Line 10 forces subsequent execution to occur after lines 8-9, in order to prevent to misordering of any code in a non-CONFIG_PREEMPT build, but only from the perspective of an intervening interrupt handler. However, in a CONFIG_PREEMPT kernel, the required barrier() call is embedded in the preempt_enable() on line 11, so the srcu_barrier() is a no-op in that case. Finally, line 12 returns the index so that it may be passed in to the corresponding srcu_read_unlock().

Figure: SRCU Read-Side Acquisition
\begin{figure}{ \scriptsize
\begin{verbatim}1 int srcu_read_lock(struct srcu_...
...ier();
11 preempt_enable();
12 return idx;
13 }\end{verbatim}
}\end{figure}

The code for srcu_read_unlock() is shown in Figure [*]. Again, lines 3 and 7 disable and re-enable preemption so that the whole code sequence executes unpreempted on a single CPU. In CONFIG_PREEMPT kernels, the preempt_disable() on line 3 contains a barrier() primitive, otherwise, the barrier() is supplied by line 4. Again, this directive forces the subsequent code to execute after the critical section from the perspective of intervening interrupt handlers. Lines 5 and 6 decrement the counter for this CPU, but with the same index as was used by the corresponding srcu_read_lock().

Figure: SRCU Read-Side Release
\begin{figure}{ \scriptsize
\begin{verbatim}1 void srcu_read_unlock(struct sr...
...ocessor_id())->c[idx]--;
7 preempt_enable();
8 }\end{verbatim}
}\end{figure}

The key point is that a given CPU's counters can be observed by other CPUs only in cooperation with that CPU's interrupt handlers. These interrupt handlers are responsible for ensuring that any needed memory barriers are executed prior to observing the counters.

Paul E. McKenney 2011-12-16
perfbook_html/node298.html0000644000175000017500000001770311672746163015666 0ustar paulmckpaulmck C.2.3 MESI State Diagram


C.2.3 MESI State Diagram

A given cache line's state changes as protocol messages are sent and received, as shown in Figure [*].

Figure: MESI Cache-Coherency State Diagram
\includegraphics{appendix/whymb/MESI}

The transition arcs in this figure are as follows:

  • Transition (a): A cache line is written back to memory, but the CPU retains it in its cache and further retains the right to modify it. This transition requires a ``writeback'' message.
  • Transition (b): The CPU writes to the cache line that it already had exclusive access to. This transition does not require any messages to be sent or received.
  • Transition (c): The CPU receives a ``read invalidate'' message for a cache line that it has modified. The CPU must invalidate its local copy, then respond with both a ``read response'' and an ``invalidate acknowledge'' message, both sending the data to the requesting CPU and indicating that it no longer has a local copy.
  • Transition (d): The CPU does an atomic read-modify-write operation on a data item that was not present in its cache. It transmits a ``read invalidate'', receiving the data via a ``read response''. The CPU can complete the transition once it has also received a full set of ``invalidate acknowledge'' responses.
  • Transition (e): The CPU does an atomic read-modify-write operation on a data item that was previously read-only in its cache. It must transmit ``invalidate'' messages, and must wait for a full set of ``invalidate acknowledge'' responses before completing the transition.
  • Transition (f): Some other CPU reads the cache line, and it is supplied from this CPU's cache, which retains a read-only copy, possibly also writing it back to memory. This transition is initiated by the reception of a ``read'' message, and this CPU responds with a ``read response'' message containing the requested data.
  • Transition (g): Some other CPU reads a data item in this cache line, and it is supplied either from this CPU's cache or from memory. In either case, this CPU retains a read-only copy. This transition is initiated by the reception of a ``read'' message, and this CPU responds with a ``read response'' message containing the requested data.
  • Transition (h): This CPU realizes that it will soon need to write to some data item in this cache line, and thus transmits an ``invalidate'' message. The CPU cannot complete the transition until it receives a full set of ``invalidate acknowledge'' responses. Alternatively, all other CPUs eject this cache line from their caches via ``writeback'' messages (presumably to make room for other cache lines), so that this CPU is the last CPU caching it.
  • Transition (i): Some other CPU does an atomic read-modify-write operation on a data item in a cache line held only in this CPU's cache, so this CPU invalidates it from its cache. This transition is initiated by the reception of a ``read invalidate'' message, and this CPU responds with both a ``read response'' and an ``invalidate acknowledge'' message.
  • Transition (j): This CPU does a store to a data item in a cache line that was not in its cache, and thus transmits a ``read invalidate'' message. The CPU cannot complete the transition until it receives the ``read response'' and a full set of ``invalidate acknowledge'' messages. The cache line will presumably transition to ``modified'' state via transition (b) as soon as the actual store completes.
  • Transition (k): This CPU loads a data item in a cache line that was not in its cache. The CPU transmits a ``read'' message, and completes the transition upon receiving the corresponding ``read response''.
  • Transition (l): Some other CPU does a store to a data item in this cache line, but holds this cache line in read-only state due to its being held in other CPUs' caches (such as the current CPU's cache). This transition is initiated by the reception of an ``invalidate'' message, and this CPU responds with an ``invalidate acknowledge'' message.

Quick Quiz C.4: How does the hardware handle the delayed transitions described above? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img109.png0000644000175000017500000000365611672746070015323 0ustar paulmckpaulmckPNG  IHDRj30PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@f,IDATxOh\E$MŜ Ez A0$zH{l_6 "BP/9yȡ$v6zK@HKЃ3?gIyþ73ߛ73of,ޑB-R(#|yV_9(^ P.r#E q1lKsӴ(rC^ԨszAQȌMFU/jAnxP UY|7m-zr"ip=wF_\XC-5M`C: fPBBk[C/g.P^/L[7A`q/͐;tN0S9(YH^:> [wjR9;™o#B1E+^0zi> $PiaپlzjDiA>tÒHzJ>z ;> & dwޫp`WF iEtK?o/b߄wϤ>yFqUc?ƌ-jz_b.X~yJb%vFMX{+otD}<98rSҽ:1$][ ))ɽQN&ߞ~lx-_XTw"3PB"l 1K {p9dzlvn2"(}[X0bg#&rvGfAU644=d[Rnb>Jy2@!O,?Չ%##TZʼcnL :^8B,BԮwaXW3WaJF(![h2_*FC O>RU4*˿jC_񮀧s z`&ɵa^a'MQy%zH9& `)وO!NNlSst^ !o?UB![=K(𮌔OIAV3#'~Rk9Exn`Jځʴ.-\Ə :?q/HzbTp܃תwt9&|m1Wfy3SU :?aIW h-))rCa천a<\.7׾+QCMPzp(|oCLҎ3W[Y 2n 8̈<ǖ3]lÞǿ&hac]JxxO 7o5 /I!IENDB`perfbook_html/img40.png0000644000175000017500000000745711672746104015236 0ustar paulmckpaulmckPNG  IHDR/EPLTEMJKPMM# b``vstmkkXUV856C@@A>>wuv.*+-**rpptRNS@fIDATx](a\Xþn@V˲=F !ss3 5!)<Q#EWCy־5:&7mT48i-i-NQX Bl"5uI+kZGѯ<6.|`#J(i& +fv3b ?{NF`_`:$ًR5Rv8gaa1({Vp7-J|\[v 8fP-I6|>U _UŸm|򭋽,b5{VǪZER 2i, :1DF863)cm08~E&Ǥ}Ցƴ&Ƶ'U~wbhzC ԫBK3Z´M:mc2HEjf"ǘ>5qFr&R>{)@J6G OI/;2z2+S]lZd=(DVVdCfbCHFJW >j;^*P鬟ӑSXYO{" XAZba'kx"$ HGɳ7 _&\[NpfFryZp !T~o$'Hſ&p`UO^k-gpV`adYf򊐀$"Q5 %½Da&EV١GN6L|)# ;7/U) (dn!P1yßus3ĭ4&ن3]8_ʗq ߡ= zeC[Ye-D 2Bf ;it FjRݘga xq(Aj!G,Urh^Ѫ1CgTԨúN$K: PME02+z jzAsw§P8suۋ"_p>vE(yGëD Y4b*AD0jq5g~Gv 1=Ļ5H& -,[AuQqS淨GQu /;p= I&ҵ"eFO,{2̦} m6+A>'ޑ[)#Sʽ*l]W eȑ6ŞxȔَ#"~>fӠwg*AXaWAq%tu"RZ]s ֤ʌ51]]E򗕚r h߮8*a2kQђB:J\dlU^廉 ϴ8 ݴd=H?kYK?{jam!=yޤG L4*8Qgw'I^*8ȴѺ ivg%8)N; P LpPKunX;>vh₾g?M_aurՔ5)amҗsߵ1!UTu DRHOJ9rszY` 4`0 &[pa["z/O{3YnMmv+hcUE8[p 6ebN,doBt V͒p 4;q!.F!ٛ`~ =v6GQ8, = ٛPdp&?o Զ%9wt]G dye̳5=<}\sƝ)cCӐfڑ3}L?#hY  x ex,QڅXjJ:0׬zCP\DR$6L}S ^bvH#'(nD=.o t}M50Y|m,U)|,BGN QQ\*pcE5)ӵ'v,h4Nf8~b\3 - T|Tzh22?\~yZJ|ٗ@IK`qfw SM".[ZcAA,NLgD40R}VVF.th Z~g{spIn|H7cCPA &D 0yoIu:# XpysKK2Fəwp7aض6 FY_i3:3%-Gq?mp'-wnf+V S*w蔬d$*3!Ƥ11RFO/S Rޝi]*w#!tq]G\G^2]*CGy?%m4_̵B˟)?%+c<^SȭȘAoL/}^Q`NKۍ$OT Sf 8'y\IJx-y8:~|ݻ( lɘ3DN-ľb*A(tAoQt;П!=}MYb#[stwOn03#GT^Mf_>7:g 8}2<:aSE~x1WE_@*nϩ\F=>HCަ|@p(V+ gLO9"!i" }k1XgmF-gh2['Ahqv$@l_v+" p. "ftrs4d>DXTTOdaשw}#b0! vdhu/53T?*hC bH=(Bb-3Kg)IEtU=i7J Xba#b͇^Qy:#+W>uNV~ylq~U++op2 >Vb؄XЫX^_]{du9.zN?AX?c+7 Z%*ԡIENDB`perfbook_html/img318.png0000644000175000017500000002326711672746071015326 0ustar paulmckpaulmckPNG  IHDR7u_yiPLTEb``^\\URSMJKZWWrpq# hffvstmkkiggcaaXUV856iffKHHC@@A>>wuv.*+-**|zzrppmjk?tRNS@f IDATx},%DYHP#r$tl6͙oeYF Pbz}sjapB5eLG!}DDz MFo.W^@&8{ſ;xp*Lgy~yU/n|n&3Po0U뮩K`'uF%\{Q; 㜱NZ<$Nt~sg=wBgc#%U ^yBR/9;p.^3ۓj YI[e ݉@b\z2Vo j *pp:yg΁EȒY^fD>AC?E_AoՏ Cwwv.V4aR cԾ5*]QÅWe_bxӡߚB=t -žT3yFjW_f9swkhZy9nYV]-~Wfr^wHԇLWc^tېpEԽ$sؐSgJ/9_7dsVTЉﭨRGv4TׁŒ˵:Ɲ@_5׮2FE:QTeI+yG*-|76]vhΡޑKx3͂n;mY:T/囥-UZ}Jkyʧ/FAa+_ \z'>w0`tl_ 1 '*bZGm<+xI@cnW2*`*-ҫx 4+ ͞Y%i-Gd#j R+aĤoi }/ҝ|P{zʖlfilO y퍆@Co$ZH9,5Og$*L>9к๪GOO;Q ZT[$­3ö(ӛD/Yw9Jnupjt {Gik^Q:?5vµ5]N0Lp2^XԵt@\UG(wn|rgD߷g-ŬWN,$(ƒh/)sU6?La"7iOEa5Y|>lp4?l}ėzQZ-y\9Pv9-9{1YJyZTwvy`{%hGRgQuhRxG-RQD%jo%:Ivi;fIWٍyRQM ..zX;['"<3Fxg3EbsH/yk\$G N*醖N1i9\Z*' pgZ/B ZӬyX Qi]\n`Cߙ&x! R\_.`R[zupQ?BNJ$A'XhGRDoޣ`\%Yp6@ڤD'P5-:f pv_k-K1(&lvH^oVT5֛̀CK W> Wm sKp> Ɓv VH'v xAs?V;tx$ӂ88c@ r*:EGH]$Gn#Nc̟K= aAXF f8UPwadwU5ۦtP?pse=y8U}냓Ude*8s7w݊Sbc5 &KQʮ @;8L1(!˶q>S%Q?76Eڸc?w:\M$q_ nCA2^Ɨm\5U[\>W|N6lF _:-d_by}a;vTDm?C{ә&?tdG:yi`{i=t Ɏu~A v9a FO[v5i5Ѩkk6sθqIoy|>qɠJDf;b+\If(!kHǀUb?c!6 )ۗ/8oߘ es0aQ#2efF5b|o*J @.c]͢#6^`v0_D{UE(~羞R6Ǟ;u۫*pCL;w=X+g]˩ROjKZK˿r2zrR0B) gf.V7W-[*x̉GJ`h]}Ӛ;ZMzP7~CzKG/z7<A7x,3\E8^cg b5_*Q`Q\ q5n 1Dݎ7f1]KWFlvuN 3#%$=tXl@kq\@ȌZMmN2CgIGP/- U4[ouq5sbRRK 11WDW1SYԢǬt՛X|l@7ttjX17g{_QS?nx=u¢MiR3=(6sgTs+z|Xd;r:33 a@ѣ`SoZbB !8(@=sf~Iaz#>~6CId\gsO) v8nQGiif)%jI58CMZF+Gf7=`݇h^Rip IQMYcbJ'U:$Ͻsu7_ SIbEbw"*c=f( 3C_[`N XHyRӓ6JZa)W+-trSg<:B:O;T(yьSU;EOm0mӫE#<]xu`:ߊ7𾑶igϔ> 4H7Gz{}4.fܦ_I":ųyW JB| I}oa\ӆ6%Gm];䰳qTJ5yuK1(&=j2HnT:r% \( |S("[F~%ߌY(H0=uN~ rp9om͓N ;׌Z,K_TD6xV&ycP?}EepTeWnrn[ožn9/&^iR xޢCMz_\<5l놐;Ci303VVF̣Ur-SQiڣDpq &:ܕ Kj]pq;0W YŤqMmcmYF %\Z2r\D^0X6-;|} c gDs*borW,.Dxy*CaQpÜzo ĦRͼ0) i}@E=lۼRͼS9>^kg_F`>z33o( "o\3f荍3hH߰C \ݎm[J +lL֐d=-# u1Lm,|nIylR|rb TT.NyK^ K/a :Ӷ籜WmmՒJ,6ARث,3$>We0f4tNm{[ƘjJ׀79pEطƉt ™n3Ǐk tr$),մ+Iρ5[n6UYoW>\V-V!=!/0S.yW{&zqfjy+8Ӕ27(,ޮ %M#u9T:׶k`T)VS6䩂7AdYt?S; 2N|Dl[6b'/9PD|9 U43lzU }(cRAAmE`T<6Ӓcc\/sVŶ*= "Hld;/ nwVo Y^)D?\А)x%ϽU7PJny:@Xˀ55&S[@$5txNϮݨfXY&wC}vC`ȳ"2e~Y\Ο} -;9r4ng26ra뱞p5 53+nIRn,Ypw1Ԭ4>6Ӣy9X˜m5Kl~?'Rb _j:c¥qftIr\cM`x ;pc=Rr 5t^.لc/\GpiHQ/YR~/oo~,lgGpI~| $M(d|{5vڽ wUQOi9`c iz%)v˕ɥnM~՘OUrup!"j TN]_cmbXć>r!C0L3AB S:h,߬fth:t!(eXp`}qv'^+{)j euQz$.j 5F Bq,&Gh2΂0J؎7hЪ8CԳ% x5u]U]C[ C>v]<RG%>75y?״Z?Jh!l]2* sB;s7yXp.cM]h58t x8 ^ 5npצ{9-RSTL7Ƴr!\Wf6cf`7x~bh~0F&]trTukk;ɘ(y_v?h Ymqp괤EaN|C5Tw^=K=M ByQ-o MBƙi>^Z'1vo s\ ]͐o9r췀cdžv7s h?Sw ".%J E:T[|܃F]a^N Z</Ɇ% /D5XJm\-E$MvýmoL|-3/K&|ig쁙A9+_?H eJsԸeR?=I5DwulmLm`8^NSViхtyW BS`#>=M6ӤIyyCAsS!M[$5~Xeץ/OzF@%f7ajcx iN):SO7nڧ.˩<}A|}{P {v\u7~ϊ`rW ʹq&&cD'_ruEs`U'яJFkG'F g6-9X{7$XzZ#=^ ަ@\q )fVgDT[I[3) ӷVʶS m3)n%G߸O%%!uӠ}>0SP:[t&p<_b=t2tYH O'U`(!g[AָdJQEsZ;X*Y og`QrqS Dĥ6кΎ\[X:+~ö 2XdFYls.7-^DbQ,3"73T"m+gCsn``YoˎdFbq#థmΐ[]MQ]^O?'wOl-(r=<-JU'+ shIXNKv&+T #{/ +܌OΎo >09Nip2,U2BN_,k@77#㛱ty;r{C`'9e+џU,7 朲{H"Rx{'9eyCYsdmY;ǔ51-J蘲h ۱kǔ51myOp ]!`ʊ)/s}?3XS!`2d$CD}A)IAAAo0 "W3JvW|Θ[࿋ooo Aį Xp8+"}o<ăߤ4a:7" n0J=D῝+.+~[+xVPHvXxˮNң P'>nөG\r|mg$KhS(O >^fczgICN6p3G ![Ocj& xka8nHגϼ ^W =fLǀm/SPPPK_Hoj>Vrn?~E&0#Az~I5I-$I~׉]ڽzy_nuuTgY?;,7O} lBՋ~B?}AP<̤fi8Sf|7n>0:9[7R'Ŀ 򓫫òSSّ-ՎV [ATqy={R|q?[LC6XUsad^QWI3Ɏ1c%´;D?<.APArann6cw0'jE*o伥`e vCdm獘gL\ ^;)Nl7>. T?y{Vp%)p,oWAzS=+|!d\aVy#+ٺsEȸRHt/'=]0F6W:pq%23[+dף-XOY2]%ߔOU5N_ázǕaͧZPN|'v,[[cOȮx{%jAAn}m-X#Xi"N-Y}D>ViAAn`yjM٥mIDAT!S9Ty&`,O[yW F}NY}ohkmycfL;VZ}QE>]Xm $g9 ڂ.ױKo|1< c q>D~NNS[EAc|']ߝ&=Rlܐ[@Mm1ѵz w՗=<u ooy+~S`[ D?yO\AAn|oRt/oyxؑ<wRξ#—-'xL&oi/cvM9XBiJܲ|:uɜ{ooA䩕rkwRPI?}^rŒ!&CF"$K-9T ]9+[`< ]y'7#e=w ?TT~z7.xoB'~7qAAA8½z {.m]Kp;s_xdq7>d=DžK. \P2t݂ex]!*#tI+ebW_%I.\r-J&-]ZPT&71l½L{RKɻr,OQ2萷]9 OCVUBoϡ])( 'c,5T#>HY.?~kb]yV{7.SXpjTfɎXiH>O IDb]/!Md*x4l)c51[0~D y:fՉxUf11:Q9YYe?y/1HiiցGL9s)kxUfSu3b͘O,b1+ӈT嶏&pv+L鳟C/%_!@zoRqHgr2ms;ЭN=fY2c&w9[ 䩪zqA)h8;oo9.։\S!zfʙq7W?0=|"j >~KQGDG67&&a'"BSzWNq93;GT¢#ge**)!9K8?ֲLNH;𣖙ƫ_uj/UzP(^dv6E`?y 37fz%m -R1eyhdib73:~nH#Y -ܟ'b91e1@rӅ$v^GF;}'ӳ|w٭Vnu$dl#خOv,[6~~'4[y>jIENDB`perfbook_html/node280.html0000644000175000017500000000446111672746162015651 0ustar paulmckpaulmck B.3.1 spin_lock_init()

B.3.1 spin_lock_init()

The spin_lock_init() primitive initializes the specified spinlock_t variable, and must be invoked before this variable is passed to any other spinlock primitive.



Paul E. McKenney 2011-12-16
perfbook_html/node79.html0000644000175000017500000002642711672746162015605 0ustar paulmckpaulmck 7.1.2.3 Hashed Double-Ended Queue


7.1.2.3 Hashed Double-Ended Queue

One of the simplest and most effective ways to deterministically partition a data structure is to hash it. It is possible to trivially hash a double-ended queue by assigning each element a sequence number based on its position in the list, so that the first element left-enqueued into an empty queue is numbered zero and the first element right-enqueued into an empty queue is numbered one. A series of elements left-enqueued into an otherwise-idle queue would be assigned decreasing numbers (-1, -2, -3, ...), while a series of elements right-enqueued into an otherwise-idle queue would be assigned increasing numbers (2, 3, 4, ...). A key point is that it is not necessary to actually represent a given element's number, as this number will be implied by its position in the queue.

Figure: Hashed Double-Ended Queue
\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash}}

Given this approach, we assign one lock to guard the left-hand index, one to guard the right-hand index, and one lock for each hash chain. Figure [*] shows the resulting data structure given four hash chains. Note that the lock domains do not overlap, and that deadlock is avoided by acquiring the index locks before the chain locks, and by never acquiring more than one lock of each type (index or chain) at a time.

Figure: Hashed Double-Ended Queue After Insertions
\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash1R}}

Each hash chain is itself a double-ended queue, and in this example, each holds every fourth element. The uppermost portion of Figure [*] shows the state after a single element (``R1'') has been right-enqueued, with the right-hand index having been incremented to reference hash chain 2. The middle portion of this same figure shows the state after three more elements have been right-enqueued. As you can see, the indexes are back to their initial states, however, each hash chain is now non-empty. The lower portion of this figure shows the state after three additional elements have been left-enqueued and an additional element has been right-enqueued.

From the last state shown in Figure [*], a left-dequeue operation would return element ``L-2'' and left the left-hand index referencing hash chain 2, which would then contain only a single element (``R2''). In this state, a left-enqueue running concurrently with a right-enqueue would result in lock contention, but the probability of such contention can be arbitrarily reduced by using a larger hash table.

Figure: Hashed Double-Ended Queue With 12 Elements
\resizebox{1.5in}{!}{\includegraphics{SMPdesign/lockdeqhashlots}}

Figure [*] shows how 12 elements would be organized in a four-hash-bucket parallel double-ended queue. Each underlying single-lock double-ended queue holds a one-quarter slice of the full parallel double-ended queue.

Figure: Lock-Based Parallel Double-Ended Queue Data Structure
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct pdeq {
2 spinlock_t llo...
...
5 int ridx;
6 struct deq bkt[DEQ_N_BKTS];
7 };\end{verbatim}
}\end{figure}

Figure [*] shows the corresponding C-language data structure, assuming an existing struct deq that provides a trivially locked double-ended-queue implementation. This data structure contains the left-hand lock on line 2, the left-hand index on line 3, the right-hand lock on line 4, the right-hand index on line 5, and, finally, the hashed array of simple lock-based double-ended queues on line 6. A high-performance implementation would of course use padding or special alignment directives to avoid false sharing.

Figure: Lock-Based Parallel Double-Ended Queue Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct element *pdeq_dequeue_l(...
...eright(d->lidx);
48 spin_unlock(&d->rlock);
49 }\end{verbatim}
}\end{figure}

Figure [*] shows the implementation of the enqueue and dequeue functions.7.1Discussion will focus on the left-hand operations, as the right-hand operations are trivially derived from them.

Lines 1-13 show pdeq_dequeue_l(), which left-dequeues and returns an element if possible, returning NULL otherwise. Line 6 acquires the left-hand spinlock, and line 7 computes the index to be dequeued from. Line 8 dequeues the element, and, if line 9 finds the result to be non-NULL, line 10 records the new left-hand index. Either way, line 11 releases the lock, and, finally, line 12 returns the element if there was one, or NULL otherwise.

Lines 15-24 shows pdeq_enqueue_l(), which left-enqueues the specified element. Line 19 acquires the left-hand lock, and line 20 picks up the left-hand index. Line 21 left-enqueues the specified element onto the double-ended queue indexed by the left-hand index. Line 22 updates the left-hand index, and finally line 23 releases the lock.

As noted earlier, the right-hand operations are completely analogous to their left-handed counterparts.

Quick Quiz 7.4: Is the hashed double-ended queue a good solution? Why or why not? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node370.html0000644000175000017500000001003711672746163015646 0ustar paulmckpaulmck D.3.2.1 Read-Side Critical Sections


D.3.2.1 Read-Side Critical Sections

Figure: RCU Read-Side Critical Sections
\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_lock(void)
2 {...
...25 __release(RCU_BH);
26 local_bh_enable();
27 }\end{verbatim}
}\end{figure}

Figure [*] shows the functions that demark RCU read-side critical sections. Lines 1-6 show __rcu_read_lock(), which begins an ``rcu'' read-side critical section. line 3 disables preemption, line 4 is a sparse marker noting the beginning of an RCU read-side critical section, and line 5 updates lockdep state. Lines 8-13 show __rcu_read_unlock(), which is the inverse of __rcu_read_lock(). Lines 15-20 show __rcu_read_lock_bh() and lines 22-27 show __rcu_read_unlock_bh(), which are analogous to the previous two functions, but disable and enable bottom-half processing rather than preemption.

Quick Quiz D.27: I thought that RCU read-side processing was supposed to be fast! The functions shown in Figure [*] have so much junk in them that they just have to be slow! What gives here? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/img217.png0000644000175000017500000001342711672745765015332 0ustar paulmckpaulmckPNG  IHDR!𒶅HPLTEb``^\\MJK956# hffvstmkkXUV856KHHC@@wuv.*+tRNS@f}IDATx]*a3^jR$(x;BRTQꕆ& Nƿϥ27i)t/OXc~;u;Z$Q#a xYQaIK[-JC s[Z59LR0ʹOْ.)N&śHwa;ߤdE0Ҳ^CO>UZ=/TRVy#\&\ʏ8-Jzg,* XN[%|MoMFƤ*>$X,ղ z#q3 dRHH7$H j`5QMt P!FU 4ٍt])1_?\=3PqX:3QHgߖ!x^I?X|6ËPz*E#PL -q t:캾jvX QmY6¼;PHM\oՇ~0+P%.7xe+لCc-quͻMJ&DYGC]ٶBq01hRŲ8Ĭnt^-Pxq?Nᮋr1tZH jAVL'Hop7td h{{g_ ah=nbam7"P?$}ky -mP,?iNzb8^GU-)c)c,.BK z| +]h\Nm@jp!uX%.F` mS.z|4|U2P4C'Zt<ڳHNMcUlxp1ʗt8[JD`,:q~w(1@۾vBޖHS&!] )2_N@ټQo_B6KٞY| `\p8Fr5`ଡ>zoa"A88[9?#njWh#Y 1KA%eKPofQDA)#[MQvMGcNx܆ [a|~9 ',SY9_ iNo~O .?dvaE Lg;Wtu)[?X-dU?|CF:BPk̓. vN5(QܿgMxs6#0bvR5D%mq9G%{߻'`?qqH5i.< E yz@ p6&utoO6W >8"faIF8ݮWӍ1|[qa*F$Ʀ<ƇQ +X1ʄpajU9A&qmbDHa~armo3D½`$K8vv4yM!j wQt Xg`/4Jᆁ!l=g-!wh3IwP(|^}v kȺqjZM_IF9,;L()JhixQ՚T,H X3/#+]i,N.b^Ī `n:-] zesX?raB]̅Ya_ؖ0]ElTMUi;Tm lZz 6v*G -]9MM%vٲb n4\ T*RQ\m6|b$KAWO)U ᷊'wfWمok20C~'W0.)%3+*r2/{tޡ\W./ot!lɘ,nToٯq>Ͽ+t&﷪z g08l]/:_rv 7]*xG]&k~|IϺKhҬ/SM.psP2 YcC4IPL{]9x+%쁱`"b[1/88?)>|Z`ze((>+Ѧ#&S_ q/>E/]NWvM>>FQ ~k+. uf?T3hȲ!w \w |_mL7#w+s#Lv4d#;_tK'NfeGqYUj7X_uu\b$@2|Q_uQ .enrs]8nҝCmJ4B!T5!u-PÏ"7?7\~<=s z0.\xz8--4"Pb1GoN}S`UhbM#-0>T*!??&@C 1e~ԁ-oe* YWG%%~I|Ypa V>5dn 4&nYovf#(L0äWN&B%&Y~#0d)j\srL,fǘbĈ5^cő./ `meu΅9|,73[_؂X}Y' f>'`Ă8L AnwTă?P&pZGtZ`RQ=/?#\bʀUMqL.UwG6zbvD4 KlI* V) 9Ij2w6٢xs~SSo[;;Ťb藲 YS{j<39d 3",[0dckgSL(@OĽg=}U0JmGdXōlz|iN 1ې*E~5湆5/۲`ifrG_d!L\=MYO.ɭ_D)-Y0rJ HnmD%2t fł]}&?Paj7cDW4BNtح3.}b%* ?ʙb^ZIb"ő/  ™lK>p{xQ"$ltD 0崽q)d+A\ՕE.r!FxWv^w9CĕRWȯIHF1i']8bWf0u@s]K7kO~q2;8y‰Av 6TinS7}.:,qj?%3].rTWa, bl$,w=¦"eB]fRÑcseB/䖩l}m|OϡIo]Je(ȓ[|9[UD _y +YrTu#gClWB̈Kvt찅gL|qYf4/̙3HϦ|mYY4e|ZϞZ·頁 1ΗR?i$:IN7k.Z#w K~+Ard4*}ak_G?>oZHƂR[_k.tQʾ0A}hm3?%?733?[(2/IENDB`perfbook_html/node430.html0000644000175000017500000001424011672746163015643 0ustar paulmckpaulmck E.4.2 Promela Coding Tricks


E.4.2 Promela Coding Tricks

Promela was designed to analyze protocols, so using it on parallel programs is a bit abusive. The following tricks can help you to abuse Promela safely:

  1. Memory reordering. Suppose you have a pair of statements copying globals x and y to locals r1 and r2, where ordering matters (e.g., unprotected by locks), but where you have no memory barriers. This can be modeled in Promela as follows:



      1 if
      2 :: 1 -> r1 = x;
      3   r2 = y
      4 :: 1 -> r2 = y;
      5   r1 = x
      6 fi
    


    The two branches of the if statement will be selected nondeterministically, since they both are available. Because the full state space is searched, both choices will eventually be made in all cases.

    Of course, this trick will cause your state space to explode if used too heavily. In addition, it requires you to anticipate possible reorderings.

    Figure: Complex Promela Assertion
    \begin{figure}{ % \scriptsize
\begin{verbatim}1 i = 0;
2 sum = 0;
3 do
4 :...
...U_READERS ->
9 assert(sum == 0);
10 break
11 od\end{verbatim}
}\end{figure}

    Figure: Atomic Block for Complex Promela Assertion
    \begin{figure}{ % \scriptsize
\begin{verbatim}1 atomic {
2 i = 0;
3 sum = 0...
...RS ->
10 assert(sum == 0);
11 break
12 od
13 }\end{verbatim}
}\end{figure}

  2. State reduction. If you have complex assertions, evaluate them under atomic. After all, they are not part of the algorithm. One example of a complex assertion (to be discussed in more detail later) is as shown in Figure [*].

    There is no reason to evaluate this assertion non-atomically, since it is not actually part of the algorithm. Because each statement contributes to state, we can reduce the number of useless states by enclosing it in an atomic block as shown in Figure [*]

  3. Promela does not provide functions. You must instead use C preprocessor macros. However, you must use them carefully in order to avoid combinatorial explosion.

Now we are ready for more complex examples.

Paul E. McKenney 2011-12-16
perfbook_html/node478.html0000644000175000017500000014451611672746164015672 0ustar paulmckpaulmck Bibliography

Bibliography

aCB08
University at California Berkeley.
SETI@HOME.
Available: http://setiathome.berkeley.edu/ [Viewed January 31, 2008], December 2008.

ACMS03
Andrea Arcangeli, Mingming Cao, Paul E. McKenney, and Dipankar Sarma.
Using read-copy update techniques for System V IPC in the Linux 2.5 kernel.
In Proceedings of the 2003 USENIX Annual Technical Conference (FREENIX Track), pages 297-310. USENIX Association, June 2003.
Available: http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf [Viewed November 21, 2007].

Adv02
Advanced Micro Devices.
AMD x86-64 Architecture Programmer's Manual Volumes 1-5, 2002.

Adv07
Advanced Micro Devices.
AMD x86-64 Architecture Programmer's Manual Volume 2: System Programming, 2007.

Ale79
Christopher Alexander.
The Timeless Way of Building.
Oxford University Press, New York, 1979.

Amd67
Gene Amdahl.
Validity of the single processor approach to achieving large-scale computing capabilities.
In AFIPS Conference Proceedings, pages 483-485, Washington, DC, USA, 1967. IEEE Computer Society.

ARM10
ARM Limited.
ARM Architecture Reference Manual: ARMv7-A and ARMv7-R Edition, 2010.

ATS09
Ali-Reza Adl-Tabatabai and Tatiana Shpeisman.
Draft specification of transactional language constructs for c++.
http://research.sun.com/scalable/pubs/C++-transactional-constructs-1.0.pdf, August 2009.

BA01
Jeff Bonwick and Jonathan Adams.
Magazines and vmem: Extending the slab allocator to many CPUs and arbitrary resources.
In USENIX Annual Technical Conference, General Track 2001, pages 15-33, 2001.

BC05
Daniel Bovet and Marco Cesati.
Understanding the Linux Kernel.
O'Reilly Media, Inc., third edition, 2005.

BHS07
Frank Buschmann, Kevlin Henney, and Douglas C. Schmidt.
Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing.
Wiley, Chichester, West Sussex, England, 2007.

BK85
Bob Beck and Bob Kasten.
VLSI assist in building a multiprocessor UNIX system.
In USENIX Conference Proceedings, pages 255-275, Portland, OR, June 1985. USENIX Association.

BLM05
C. Blundell, E. C. Lewis, and M. Martin.
Deconstructing transactional semantics: The subtleties of atomicity.
In Annual Workshop on Duplicating, Deconstructing, and Debunking (WDDD), June 2005.
Available: http://www.cis.upenn.edu/acg/papers/wddd05_atomic_semantics.pdf [Viewed June 4, 2009].

BLM06
C. Blundell, E. C. Lewis, and M. Martin.
Subtleties of transactional memory and atomicity semantics.
Computer Architecture Letters, 5(2), 2006.
Available: http://www.cis.upenn.edu/acg/papers/cal06_atomic_semantics.pdf [Viewed June 4, 2009].

Boe09
Hans-J. Boehm.
Transactional memory should be an implementation technique, not a programming interface.
In HOTPAR 2009, page 6, Berkeley, CA, USA, March 2009.
Available: http://www.usenix.org/event/hotpar09/tech/full_papers/boehm/boehm.pdf [Viewed May 24, 2009].

But97
David Butenhof.
Programming with POSIX Threads.
Addison-Wesley, Boston, MA, USA, 1997.

Cor06
Jonathan Corbet.
The kernel lock validator.
Available: http://lwn.net/Articles/185666/ [Viewed: March 26, 2010], May 2006.

Cor08
Jonathan Corbet.
Linux weekly news.
Available: http://lwn.net/ [Viewed November 26, 2008], November 2008.

CRKH05
Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman.
Linux Device Drivers.
O'Reilly Media, Inc., third edition, 2005.

CSG99
David E. Culler, Jaswinder Pal Singh, and Anoop Gupta.
Parallel Computer Architecture: a Hardware/Software Approach.
Morgan Kaufman, 1999.

DCW+11
Luke Dalessandro, Francois Carouge, Sean White, Yossi Lev, Mark Moir, Michael L. Scott, and Michael F. Spear.
Hybrid norec: A case study in the effectiveness of best effort hardware transactional memory.
In Proceedings of the 16th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS), ASPLOS '11, pages ???-???, New York, NY, USA, 2011. ACM.

Des09
Mathieu Desnoyers.
[RFC git tree] userspace RCU (urcu) for Linux.
Available: http://lkml.org/lkml/2009/2/5/572 http://lttng.org/urcu [Viewed February 20, 2009], February 2009.

Dij71
Edsger W. Dijkstra.
Hierarchical ordering of sequential processes.
Acta Informatica, 1(2):115-138, 1971.
Available: http://www.cs.utexas.edu/users/EWD/ewd03xx/EWD310.PDF [Viewed January 13, 2008].

DLM+10
Dave Dice, Yossi Lev, Virendra J. Marathe, Mark Moir, Dan Nussbaum, and Marek Oleszewski.
Simplifying concurrent algorithms by exploiting hardware transactional memory.
In Proceedings of the 22nd ACM symposium on Parallelism in algorithms and architectures, SPAA '10, pages 325-334, New York, NY, USA, 2010. ACM.

DLMN09
Dave Dice, Yossi Lev, Mark Moir, and Dan Nussbaum.
Early experience with a commericial hardware transactional memory implementation.
In Fourteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '09), pages 157-168, Washington, DC, USA, March 2009.
Available: http://research.sun.com/scalable/pubs/ASPLOS2009-RockHTM.pdf [Viewed February 4, 2009].

Dov90
Ken F. Dove.
A high capacity TCP/IP in parallel STREAMS.
In UKUUG Conference Proceedings, London, June 1990.

DSS06
Dave Dice, Ori Shalev, and Nir Shavit.
Transactional locking II.
In Proc. International Symposium on Distributed Computing. Springer Verlag, 2006.
Available: http://www.springerlink.com/content/5688h5q0w72r54x0/ [Viewed March 10, 2008].

EGCD03
T. A. El-Ghazawi, W. W. Carlson, and J. M. Draper.
UPC language specifications v1.1.
Available: http://upc.gwu.edu [Viewed September 19, 2008], May 2003.

Eng68
Douglas Engelbart.
The demo.
Available: http://video.google.com/videoplay?docid=-8734787622017763097 [Viewed November 28, 2008], December 1968.

ENS05
Ryan Eccles, Blair Nonneck, and Deborah A. Stacey.
Exploring parallel programming knowledge in the novice.
In HPCS '05: Proceedings of the 19th International Symposium on High Performance Computing Systems and Applications, pages 97-102, Washington, DC, USA, 2005. IEEE Computer Society.

ES05
Ryan Eccles and Deborah A. Stacey.
Understanding the parallel programmer.
In HPCS '05: Proceedings of the 19th International Symposium on High Performance Computing Systems and Applications, pages 156-160, Washington, DC, USA, 2005. IEEE Computer Society.

Gar90
Arun Garg.
Parallel STREAMS: a multi-processor implementation.
In USENIX Conference Proceedings, pages 163-176, Berkeley CA, February 1990. USENIX Association.

Gar07
Bryan Gardiner.
Idf: Gordon moore predicts end of moore's law (again).
Available: http://blog.wired.com/business/2007/09/idf-gordon-mo-1.html [Viewed: November 28, 2008], September 2007.

GC96
Michael Greenwald and David R. Cheriton.
The synergy between non-blocking synchronization and operating system structure.
In Proceedings of the Second Symposium on Operating Systems Design and Implementation, pages 123-136, Seattle, WA, October 1996. USENIX Association.

Gha95
Kourosh Gharachorloo.
Memory consistency models for shared-memory multiprocessors.
Technical Report CSL-TR-95-685, Computer Systems Laboratory, Departments of Electrical Engineering and Computer Science, Stanford University, Stanford, CA, December 1995.
Available: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-9.pdf [Viewed: October 11, 2004].

GHJV95
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley, 1995.

GKAS99
Ben Gamsa, Orran Krieger, Jonathan Appavoo, and Michael Stumm.
Tornado: Maximizing locality and concurrency in a shared memory multiprocessor operating system.
In Proceedings of the 3rd Symposium on Operating System Design and Implementation, pages 87-100, New Orleans, LA, February 1999.
Available: http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf [Viewed August 30, 2006].

GMTW08
D. Guniguntala, P. E. McKenney, J. Triplett, and J. Walpole.
The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with Linux.
IBM Systems Journal, 47(2):221-236, May 2008.
Available: http://www.research.ibm.com/journal/sj/472/guniguntala.pdf [Viewed April 24, 2008].

GPB+07
Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea.
Java: Concurrency in Practice.
Addison Wesley, Upper Saddle River, NJ, USA, 2007.

Gra02
Jim Gray.
Super-servers: Commodity computer clusters pose a software challenge.
Available: http://research.microsoft.com/en-us/um/people/gray/papers/superservers(4t_computers).doc [Viewed: June 23, 2004], April 2002.

Gri00
Scott Griffen.
Internet pioneers: Doug englebart.
Available: http://www.ibiblio.org/pioneers/englebart.html [Viewed November 28, 2008], May 2000.

Gro01
The Open Group.
Single UNIX specification.
http://www.opengroup.org/onlinepubs/007908799/index.html, July 2001.

Gro07
Dan Grossman.
The transactional memory / garbage collection analogy.
In OOPSLA '07: Proceedings of the 22nd annual ACM SIGPLAN conference on Object oriented programming systems and applications, pages 695-706, New York, NY, USA, October 2007. ACM.
Available: http://www.cs.washington.edu/homes/djg/papers/analogy_oopsla07.pdf [Viewed December 19, 2008].

HCS+05
Lorin Hochstein, Jeff Carver, Forrest Shull, Sima Asgari, and Victor Basili.
Parallel programmer productivity: A case study of novice parallel programmers.
In SC '05: Proceedings of the 2005 ACM/IEEE conference on Supercomputing, page 35, Washington, DC, USA, 2005. IEEE Computer Society.

Her90
Maurice P. Herlihy.
A methodology for implementing highly concurrent data structures.
In Proceedings of the 2nd ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming, pages 197-206, March 1990.

Her05
Maurice Herlihy.
The transactional manifesto: software engineering and non-blocking synchronization.
In PLDI '05: Proceedings of the 2005 ACM SIGPLAN conference on Programming language design and implementation, pages 280-280, New York, NY, USA, 2005. ACM Press.

HM93
Maurice Herlihy and J. Eliot B. Moss.
Transactional memory: Architectural support for lock-free data structures.
The 20th Annual International Symposium on Computer Architecture, pages 289-300, May 1993.

HMB06
Thomas E. Hart, Paul E. McKenney, and Angela Demke Brown.
Making lockless synchronization fast: Performance implications of memory reclamation.
In 20th IEEE International Parallel and Distributed Processing Symposium, Rhodes, Greece, April 2006.
Available: http://www.rdrop.com/users/paulmck/RCU/hart_ipdps06.pdf [Viewed April 28, 2008].

Hol03
Gerard J. Holzmann.
The Spin Model Checker: Primer and Reference Manual.
Addison-Wesley, 2003.

HP95
John L. Hennessy and David A. Patterson.
Computer Architecture: A Quantitative Approach.
Morgan Kaufman, 1995.

HS08
Maurice Herlihy and Nir Shavit.
The Art of Multiprocessor Programming.
Morgan Kaufmann, Burlington, MA, USA, 2008.

HW92
Wilson C. Hsieh and William E. Weihl.
Scalable reader-writer locks for parallel systems.
In Proceedings of the 6th International Parallel Processing Symposium, pages 216-230, Beverly Hills, CA, USA, March 1992.

IBM94
IBM Microelectronics and Motorola.
PowerPC Microprocessor Family: The Programming Environments, 1994.

Inm85
Jack Inman.
Implementing loosely coupled functions on tightly coupled engines.
In USENIX Conference Proceedings, pages 277-298, Portland, OR, June 1985. USENIX Association.

Int92
International Standards Organization.
Information Technology - Database Language SQL.
ISO, 1992.
Available: http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt [Viewed September 19, 2008].

Int02a
Intel Corporation.
Intel Itanium Architecture Software Developer's Manual Volume 3: Instruction Set Reference, 2002.

Int02b
Intel Corporation.
Intel Itanium Architecture Software Developer's Manual Volume 3: System Architecture, 2002.

Int04a
Intel Corporation.
IA-32 Intel Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z, 2004.
Available: ftp://download.intel.com/design/Pentium4/manuals/25366714.pdf [Viewed: February 16, 2005].

Int04b
Intel Corporation.
IA-32 Intel Architecture Software Developer's Manual Volume 3: System Programming Guide, 2004.
Available: ftp://download.intel.com/design/Pentium4/manuals/25366814.pdf [Viewed: February 16, 2005].

Int04c
International Business Machines Corporation.
z/Architecture principles of operation.
Available: http://publibz.boulder.ibm.com/epubs/pdf/dz9zr003.pdf [Viewed: February 16, 2005], May 2004.

Int07
Intel Corporation.
Intel 64 Architecture Memory Ordering White Paper, 2007.
Available: http://developer.intel.com/products/processor/manuals/318147.pdf [Viewed: September 7, 2007].

Int09
Intel Corporation.
Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide, Part 1, 2009.
Available: http://download.intel.com/design/processor/manuals/253668.pdf [Viewed: November 8, 2009].

Jia08
Lai Jiangshan.
[RFC][PATCH] rcu classic: new algorithm for callbacks-processing.
Available: http://lkml.org/lkml/2008/6/2/539 [Viewed December 10, 2008], June 2008.

Kan96
Gerry Kane.
PA-RISC 2.0 Architecture.
Hewlett-Packard Professional Books, 1996.

KL80
H. T. Kung and Q. Lehman.
Concurrent maintenance of binary search trees.
ACM Transactions on Database Systems, 5(3):354-382, September 1980.
Available: http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE, [Viewed December 3, 2007].

Kni08
John U. Knickerbocker.
3D chip technology.
IBM Journal of Research and Development, 52(6), November 2008.
Available: http://www.research.ibm.com/journal/rd52-6.html [Viewed: January 1, 2009].

Knu73
Donald Knuth.
The Art of Computer Programming.
Addison-Wesley, 1973.

Lea97
Doug Lea.
Concurrent Programming in Java: Design Principles and Patterns.
Addison Wesley Longman, Reading, MA, USA, 1997.

LLO09
Yossi Lev, Victor Luchangco, and Marek Olszewski.
Scalable reader-writer locks.
In SPAA '09: Proceedings of the twenty-first annual symposium on Parallelism in algorithms and architectures, pages 101-110, New York, NY, USA, 2009. ACM.

Lom77
D. B. Lomet.
Process structuring, synchronization, and recovery using atomic actions.
SIGSOFT Softw. Eng. Notes, 2(2):128-137, 1977.
Available: http://portal.acm.org/citation.cfm?id=808319# [Viewed June 27, 2008].

Lov05
Robert Love.
Linux Kernel Development.
Novell Press, second edition, 2005.

LS86
Vladimir Lanin and Dennis Shasha.
A symmetric concurrent b-tree algorithm.
In ACM '86: Proceedings of 1986 ACM Fall joint computer conference, pages 380-389, Los Alamitos, CA, USA, 1986. IEEE Computer Society Press.

LSH02
Michael Lyons, Ed Silha, and Bill Hay.
PowerPC storage model and AIX programming.
Available: http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html [Viewed: January 31, 2005], August 2002.

Mas92
H. Massalin.
Synthesis: An Efficient Implementation of Fundamental Operating System Services.
PhD thesis, Columbia University, New York, NY, 1992.

McK96
Paul E. McKenney.
Pattern Languages of Program Design, volume 2, chapter 31: Selecting Locking Designs for Parallel Programs, pages 501-531.
Addison-Wesley, June 1996.
Available: http://www.rdrop.com/users/paulmck/scalability/paper/mutexdesignpat.pdf [Viewed February 17, 2005].

McK03
Paul E. McKenney.
Using RCU in the Linux 2.5 kernel.
Linux Journal, 1(114):18-26, October 2003.
Available: http://www.linuxjournal.com/article/6993 [Viewed November 14, 2007].

McK04
Paul E. McKenney.
Exploiting Deferred Destruction: An Analysis of Read-Copy-Update Techniques in Operating System Kernels.
PhD thesis, OGI School of Science and Engineering at Oregon Health and Sciences University, 2004.
Available: http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf [Viewed October 15, 2004].

McK05a
Paul E. McKenney.
Memory ordering in modern microprocessors, part I.
Linux Journal, 1(136):52-57, August 2005.
Available: http://www.linuxjournal.com/article/8211 http://www.rdrop.com/users/paulmck/scalability/paper/ordering.2007.09.19a.pdf [Viewed November 30, 2007].

McK05b
Paul E. McKenney.
Memory ordering in modern microprocessors, part II.
Linux Journal, 1(137):78-82, September 2005.
Available: http://www.linuxjournal.com/article/8212 http://www.rdrop.com/users/paulmck/scalability/paper/ordering.2007.09.19a.pdf [Viewed November 30, 2007].

McK05c
Paul E. McKenney.
Re: [fwd: Re: [patch] real-time preemption, -rt-2.6.13-rc4-v0.7.52-01].
Available: http://lkml.org/lkml/2005/8/8/108 [Viewed March 14, 2006], August 2005.

McK06
Paul E. McKenney.
Sleepable RCU.
Available: http://lwn.net/Articles/202847/ Revised: http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf [Viewed August 21, 2006], October 2006.

McK07a
Paul E. McKenney.
The design of preemptible read-copy-update.
Available: http://lwn.net/Articles/253651/ [Viewed October 25, 2007], October 2007.

McK07b
Paul E. McKenney.
[PATCH] QRCU with lockless fastpath.
Available: http://lkml.org/lkml/2007/2/25/18 [Viewed March 27, 2008], February 2007.

McK07c
Paul E. McKenney.
[patch rfc 0/9] RCU: Preemptible RCU.
Available: http://lkml.org/lkml/2007/9/10/213 [Viewed October 25, 2007], September 2007.

McK07d
Paul E. McKenney.
Priority-boosting RCU read-side critical sections.
Available: http://lwn.net/Articles/220677/ Revised: http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf [Viewed September 7, 2007], February 2007.

McK07e
Paul E. McKenney.
RCU and unloadable modules.
Available: http://lwn.net/Articles/217484/ [Viewed November 22, 2007], January 2007.

McK07f
Paul E. McKenney.
Using Promela and Spin to verify parallel algorithms.
Available: http://lwn.net/Articles/243851/ [Viewed September 8, 2007], August 2007.

McK07g
Paul E. McKenney.
What is RCU?
Available: http://www.rdrop.com/users/paulmck/RCU/whatisRCU.html [Viewed July 6, 2007], 07 2007.

McK08a
Paul E. McKenney.
Hierarchical RCU.
Available: http://lwn.net/Articles/305782/ [Viewed November 6, 2008], November 2008.

McK08b
Paul E. McKenney.
RCU part 3: the RCU API.
Available: http://lwn.net/Articles/264090/ [Viewed January 10, 2008], January 2008.

McK08c
Paul E. McKenney.
What is RCU? part 2: Usage.
Available: http://lwn.net/Articles/263130/ [Viewed January 4, 2008], January 2008.

McK09a
Paul E. McKenney.
Re: [patch fyi] rcu: the bloatwatch edition.
Available: http://lkml.org/lkml/2009/1/14/449 [Viewed January 15, 2009], January 2009.

McK09b
Paul E. McKenney.
Transactional memory everywhere?
http://paulmck.livejournal.com/tag/transactionalSeptember 2009.

MD92
Paul E. McKenney and Ken F. Dove.
Efficient demultiplexing of incoming tcp packets.
In SIGCOMM '92, Proceedings of the Conference on Communications Architecture & Protocols, pages 269-279, Baltimore, MD, August 1992. Association for Computing Machinery.

Mel06
Melbourne School of Engineering.
CSIRAC.
Available: http://www.csse.unimelb.edu.au/dept/about/csirac/ [Viewed: December 7, 2008], 2006.

Met99
Panagiotis Takis Metaxas.
Fast dithering on a data-parallel computer.
In Proceedings of the IASTED International Conference on Parallel and Distributed Computing and Systems, pages 570-576, Cambridge, MA, USA, 1999. IASTED.

MG92
Paul E. McKenney and Gary Graunke.
Efficient buffer allocation on shared-memory multiprocessors.
In IEEE Workshop on the Architecture and Implementation of High Performance Communication Subsystems, pages 194-199, Tucson, AZ, February 1992. The Institute of Electrical and Electronics Engineers, Inc.

MGM+09
Paul E. McKenney, Manish Gupta, Maged M. Michael, Phil Howard, Joshua Triplett, and Jonathan Walpole.
Is parallel programming hard, and if so, why?
Technical Report TR-09-02, Portland State University, Portland, OR, USA, February 2009.
Available: http://www.cs.pdx.edu/pdfs/tr0902.pdf [Viewed February 19, 2009].

Mic04
Maged M. Michael.
Hazard pointers: Safe memory reclamation for lock-free objects.
IEEE Transactions on Parallel and Distributed Systems, 15(6):491-504, June 2004.

MK88
Marshall Kirk McKusick and Michael J. Karels.
Design of a general purpose memory allocator for the 4.3BSD UNIX kernel.
In USENIX Conference Proceedings, Berkeley CA, June 1988.

MM00
Ingo Molnar and David S. Miller.
brlock.
Available: http://www.tm.kernel.org/pub/linux/kernel/v2.3/patch-html/patch-2.3.49/linux_include_linux_brlock.h.html [Viewed September 3, 2004], March 2000.

MMW07
Paul E. McKenney, Maged Michael, and Jonathan Walpole.
Why the grass may not be greener on the other side: A comparison of locking vs. transactional memory.
In Programming Languages and Operating Systems, pages 1-5, New York, NY, USA, October 2007. ACM SIGOPS.

Mol05
Ingo Molnar.
Index of /pub/linux/kernel/projects/rt.
Available: http://www.kernel.org/pub/linux/kernel/projects/rt/ [Viewed February 15, 2005], February 2005.

Moo03
Gordon Moore.
No exponential is forever-but we can delay forever.
In IBM Academy of Technology 2003 Annual Meeting, San Francisco, CA, October 2003.

MPA+06
Paul E. McKenney, Chris Purcell, Algae, Ben Schumin, Gaius Cornelius, Qwertyus, Neil Conway, Sbw, Blainster, Canis Rufus, Zoicon5, Anome, and Hal Eisen.
Read-copy update.
Available: http://en.wikipedia.org/wiki/Read-copy-update [Viewed August 21, 2006], July 2006.

MPI08
MPI Forum.
Message passing interface forum.
Available: http://www.mpi-forum.org/ [Viewed September 9, 2008], September 2008.

MR08
Paul E. McKenney and Steven Rostedt.
Integrating and validating dynticks and preemptable rcu.
Available: http://lwn.net/Articles/279077/ [Viewed April 24, 2008], April 2008.

MS93
Paul E. McKenney and Jack Slingwine.
Efficient kernel memory allocation on shared-memory multiprocessors.
In USENIX Conference Proceedings, pages 295-306, Berkeley CA, February 1993. USENIX Association.
Available: http://www.rdrop.com/users/paulmck/scalability/paper/mpalloc.pdf [Viewed January 30, 2005].

MS98
Paul E. McKenney and John D. Slingwine.
Read-copy update: Using execution history to solve concurrency problems.
In Parallel and Distributed Computing and Systems, pages 509-518, Las Vegas, NV, October 1998.
Available: http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf [Viewed December 3, 2007].

MS05
Paul E. McKenney and Dipankar Sarma.
Towards hard realtime response from the Linux kernel on SMP hardware.
In linux.conf.au 2005, Canberra, Australia, April 2005.
Available: http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf [Viewed May 13, 2005].

MS08
MySQL AB and Sun Microsystems.
MySQL Downloads.
Available: http://dev.mysql.com/downloads/ [Viewed November 26, 2008], November 2008.

MS09
Paul E. McKenney and Raul Silvera.
Example power implementation for c/c++ memory model.
Available: http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2009.02.27a.html [Viewed: April 5, 2009], February 2009.

MSK01
Paul E. McKenney, Jack Slingwine, and Phil Krueger.
Experience with an efficient parallel kernel memory allocator.
Software - Practice and Experience, 31(3):235-257, March 2001.

MSM05
Timothy G. Mattson, Beverly A. Sanders, and Berna L. Massingill.
Patterns for Parallel Programming.
Addison Wesley, Boston, MA, USA, 2005.

MSMB06
Paul E. McKenney, Dipankar Sarma, Ingo Molnar, and Suparna Bhattacharya.
Extending RCU for realtime and embedded workloads.
In Ottawa Linux Symposium, pages v2 123-138, July 2006.
Available: http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184 http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf [Viewed January 1, 2007].

MSS04
Paul E. McKenney, Dipankar Sarma, and Maneesh Soni.
Scaling dcache with RCU.
Linux Journal, 1(118):38-46, January 2004.
Available: http://www.linuxjournal.com/node/7124 [Viewed December 26, 2010].

MT01
Jose F. Martinez and Josep Torrellas.
Speculative locks for concurrent execution of critical sections in shared-memory multiprocessors.
In Workshop on Memory Performance Issues, International Symposium on Computer Architecture, Gothenburg, Sweden, June 2001.
Available: http://iacoma.cs.uiuc.edu/iacoma-papers/wmpi_locks.pdf [Viewed June 23, 2004].

Mus04
Museum Victoria Australia.
CSIRAC: Australia's first computer.
Available: http://museumvictoria.com.au/CSIRAC/ [Viewed: December 7, 2008], 2004.

MW07
Paul E. McKenney and Jonathan Walpole.
What is RCU, fundamentally?
Available: http://lwn.net/Articles/262464/ [Viewed December 27, 2007], December 2007.

Nes06a
Oleg Nesterov.
Re: [patch] cpufreq: mark cpufreq_tsc() as core_initcall_sync.
Available: http://lkml.org/lkml/2006/11/19/69 [Viewed May 28, 2007], November 2006.

Nes06b
Oleg Nesterov.
Re: [rfc, patch 1/2] qrcu: "quick" srcu implementation.
Available: http://lkml.org/lkml/2006/11/29/330 [Viewed November 26, 2008], November 2006.

ONH+96
Kunle Olukotun, Basem A. Nayfeh, Lance Hammond, Ken Wilson, and Kunyung Chang.
The case for a single-chip multiprocessor.
In ASPLOS VII, October 1996.

Ope97
Open Group.
The single UNIX specification, version 2: Threads.
Available: http://www.opengroup.org/onlinepubs/007908799/xsh/threads.html [Viewed September 19, 2008], 1997.

Pos08
PostgreSQL Global Development Group.
PostgreSQL.
Available: http://www.postgresql.org/ [Viewed November 26, 2008], November 2008.

PW07
Donald E. Porter and Emmett Witchel.
Lessons from large transactional systems.
Personal communication <20071214220521.GA5721@olive-green.cs.utexas.edu>, December 2007.

Rei07
James Reinders.
Intel Threading Building Blocks.
O'Reilly, Sebastopol, CA, USA, 2007.

RG01
Ravi Rajwar and James R. Goodman.
Speculative lock elision: Enabling highly concurrent multithreaded execution.
In Proceedings of the 34th Annual ACM/IEEE International Symposium on Microarchitecture, pages 294-305, Austin, TX, December 2001. The Institute of Electrical and Electronics Engineers, Inc.

RHP+07
Chistopher J. Rossbach, Owen S. Hofmann, Donald E. Porter, Hany E. Ramadan, Aditya Bhandari, and Emmett Witchel.
TxLinux: Using and managing hardware transactional memory in an operating system.
In SOSP'07: Twenty-First ACM Symposium on Operating Systems Principles. ACM SIGOPS, October 2007.
Available: http://www.sosp2007.org/papers/sosp056-rossbach.pdf [Viewed October 21, 2007].

SATG+09
Tatiana Shpeisman, Ali-Reza Adl-Tabatabai, Robert Geva, Yang Ni, and Adam Welc.
Towards transactional memory semantics for c++.
In SPAA '09: Proceedings of the twenty-first annual symposium on Parallelism in algorithms and architectures, pages 49-58, New York, NY, USA, 2009. ACM.

Sco06
Michael Scott.
Programming Language Pragmatics.
Morgan Kaufmann, Burlington, MA, USA, 2006.

Sew
Peter Sewell.
The semantics of multiprocessor programs.
Available: http://www.cl.cam.ac.uk/~pes20/weakmemory/ [Viewed: June 7, 2010].

SMS08
Michael Spear, Maged Michael, and Michael Scott.
Inevitability mechanisms for software transactional memory.
In 3rd ACM SIGPLAN Workshop on Transactional Computing, New York, NY, USA, February 2008. ACM.
Available: http://www.cs.rochester.edu/u/scott/papers/2008_TRANSACT_inevitability.pdf [Viewed January 10, 2009].

SPA94
SPARC International.
The SPARC Architecture Manual, 1994.

Spr01
Manfred Spraul.
Re: RFC: patch to allow lock-free traversal of lists with insertion.
Available: http://marc.theaimsgroup.com/?l=linux-kernel&m=100264675012867&w=2 [Viewed June 23, 2004], October 2001.

Spr08a
Manfred Spraul.
Re: [RFC, PATCH] v4 scalable classic RCU implementation.
Available: http://lkml.org/lkml/2008/9/6/86 [Viewed December 8, 2008], September 2008.

Spr08b
Manfred Spraul.
[RFC, PATCH] state machine based rcu.
Available: http://lkml.org/lkml/2008/8/21/336 [Viewed December 8, 2008], August 2008.

SS94
Duane Szafron and Jonathan Schaeffer.
Experimentally assessing the usability of parallel programming systems.
In IFIP WG10.3 Programming Environments for Massively Parallel Distributed Systems, pages 19.1-19.7, 1994.

SSHT93
Janice S. Stone, Harold S. Stone, Philip Heidelberger, and John Turek.
Multiple reservations and the Oklahoma update.
IEEE Parallel and Distributed Technology Systems and Applications, 1(4):58-71, November 1993.

SSRB00
Douglas C. Schmidt, Michael Stal, Hans Rohnert, and Frank Buschmann.
Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects.
Wiley, Chichester, West Sussex, England, 2000.

ST87
William E. Snaman and David W. Thiel.
The VAX/VMS distributed lock manager.
Digital Technical Journal, 5:29-44, September 1987.

ST95
Nir Shavit and Dan Touitou.
Software transactional memory.
In Proceedings of the 14th Annual ACM Symposium on Principles of Distributed Computing, pages 204-213, Ottawa, Ontario, Canada, August 1995.

Ste92
W. Richard Stevens.
Advanced Programming in the UNIX Environment.
Addison Wesley, 1992.

Sut08
Herb Sutter.
Effective concurrency.
Series in Dr. Dobbs Journal, 2008.

SW95
Richard L. Sites and Richard T. Witek.
Alpha AXP Architecture.
Digital Press, second edition, 1995.

The08
The Open MPI Project.
MySQL Downloads.
Available: http://www.open-mpi.org/software/ [Viewed November 26, 2008], November 2008.

Tor01
Linus Torvalds.
Re: [Lse-tech] Re: RFC: patch to allow lock-free traversal of lists with insertion.
Available: http://lkml.org/lkml/2001/10/13/105 [Viewed August 21, 2004], October 2001.

Tor03
Linus Torvalds.
Linux 2.6.
Available: ftp://kernel.org/pub/linux/kernel/v2.6 [Viewed June 23, 2004], August 2003.

Tra01
Transaction Processing Performance Council.
TPC.
Available: http://www.tpc.org/ [Viewed December 7, 2008], 2001.

UoC08
Berkeley University of California.
BOINC: compute for science.
Available: http://boinc.berkeley.edu/ [Viewed January 31, 2008], October 2008.

VGS08
Haris Volos, Neelam Goyal, and Michael M. Swift.
Pathological interaction of locks with transactional memory.
In 3rd ACM SIGPLAN Workshop on Transactional Computing, New York, NY, USA, February 2008. ACM.
Available: http://www.cs.wisc.edu/multifacet/papers/transact08_txlock.pdf [Viewed September 7, 2009].

Vog09
Werner Vogels.
Eventually consistent.
Commun. ACM, 52:40-44, January 2009.

Wik08
Wikipedia.
Zilog Z80.
Available: http://en.wikipedia.org/wiki/Z80 [Viewed: December 7, 2008], 2008.


Paul E. McKenney 2011-12-16
perfbook_html/img135.png0000644000175000017500000001650511672746071015320 0ustar paulmckpaulmckPNG  IHDRwHPLTEb``TRRMJKPMMFCCwvv# hffmkkXUV856C@@wuv.*+igh:GtRNS@fIDATx],FqCPPZj]Yuj[JrIB둱eJƚVg'88F |(%ƕ/nU X2PymVWy+umjg6ssU&x"TA;UzQG1}z07mT S"y^VG6 9P=ڼ5Z.>,ۆyJLo0ٴ"Uv#6,*ld_x8 3v+s߻%4|oLR*+>6*`a`(JTjXEbde/_cn[,-ft+9p-LA|<3_j]|F*+8u+*9^ 菺f(p48pG,ه N0:Kp4X;VS;p[(PjbS| qN* V6rӟGpmZ Lmm˃=^/dN`>(ܣUgdxx+iGo0:B[V74J:纆:f(5Z&4庇s~܊VJxyq),6rJ֡NUԪ/oVn^ l:u"BVt=f/2de8M|jo- Eo*tP9̙0ՠrè"' ls6䤑S_b 9#- GLQӎu+LH9lܯYlW?03Km@߲`h#*/ ȭxPQ5:ֳ{o%@&ss!ȁ83KʥQUՌ8㓥ke(*" DO9?H+B7g6V}NSI0чdݭQs jQB1n&hՓT17nbTՠlC$UpTM=y U@0\}F ]49)~Y[Wesg1%|xkHG) Z.K{|P$7@vuZe:E 8yʒY+Rm|D9ݢoe_oGyK/ {`ץxxٔDu(+ qv} aEJ܈%ˍZA\޴5/a XQ9M 6 ]\7p뭷*(JJ*n5ˁX- p[VA3[4YHOu)Ygf ٩3DA6698NTᘘ 3z gft'+ .%F̼3=1ֺ1=މ6{?'dϽ) ̷!h4{=4f o|j>S׉1LHJokHj_8?TE@wF5P9nPoXTrP0ь9D?n"b Kf`=_MALiyUiI֌Ώ4yFd^$'P!+nrDR6W[x f]63r]F!_K}[TxOnnUd'#+ lW_t؟/boI]D@JEVLW%fpUT!\M1i&;سUakxȜ 6<2/p^OpUl6>f3}Q1J8 Czp/:1}>X\:@RE@@PʀiyT>=2ta\k41{O⸔Y/%{\;>.e?uRsPU}XC7B喂Z "Ap4Kd9ɫ5Fy뙕%7uUS$s ~Fy[e6knl1v!=8 f'c6XX.+t"i!2G~W]ˉ'bj.U?qg;Xl_Nxl׫s]fF(@ W^@:eΫB߁-F?AHT\`S6/_fv+="P`+y}p#C7{1o_bV 뤾S=K(4nO1TM"E.VsS@M2Vؖ~%! /kkbj֦ Ǭ( ocܜM̂;<2+[gxkj1M,9t LF_M>`Y<_b=,׷O1vO,_bVaQj^^bsU"7⧘} 6v+ޛU~ux2>ٻeG= =b"l9k&)SISQI8->NgG;5g\ 91R\12rܺX/3w}ٔوTef_"ĨDZ _\M}w}pTT;G7d*>(J$J yfN m]ף.9-W΄X`┆C/T020l&s>xg2iNyltӘ]~{{[Ȫ˨,}Kpg:ʝNxl;]!a~ņ* uHFdB[z٥<3Ǜs*z姘}Xi]Xke#{uR2\M%W1 n6B6lxN0s)Avo|k 0kٹ]4-zmpB#BJӘ1: 2\J`tvS]G63;+c-Y6F̘e`ב;my#a)vٟj&hr.m4%5‡%>~eW&0asl"Pذ`I߼-uciV.d8-ˎ1͵E%ϸyDѨ4Y xװ9 j-!Ẋ4d. fpU(\q%vowD2#yFf6|)m3Tdj5Y'yq](Jdgq47?t &*< J32*')UuΨ^nndֆlweas_R\>xv%,Y.97JQf o쓍SQ%HAObt]oGIŢ vf7q",8P/VOObrY t=򃨾tSRaEXtpR1*IL$?R[OW7V&=tG}p+v!+mE[+\=Ԕ )#jac:Q즼*h9_A8ftƩ7e!W-=)f}(xΣ %uGe͐Ꮱ+ . p`y}ًiS_мC9ke᮷ǩ,=U6p8qѠ G#Itu/d7Yt4Z#2WEᎯ׸ep3E]S[ľ|6΢Fô :ƥc:I pB{^D-J[ikuIkS;YL kX2yP9MG& 8 gahF8阙*Nf8YMHIE?kEۑ1o[l3R& 4q{j왴=3 Rm);-iOVTll(ABH-_ҝTk+:⁡UjA=R&k܈V M+2():*؏lǨP(l`N*[ =mrWO+p9x>FԆI١snl52i!;! PTxX; W%f*9~J:&Y-l6ZG /0=+hk>o' PX@<*#SƩEPP8/hb *0%S)M&_3 6a| IKIc$fQ]GEŴP_O)`cStn&|0/,M4:eм+m37Xclqq{5LO+-ih2ZNUR._5[O5L0PJ8$iE ƻ\x`Q`|KCKp]$"4耺:TՂ5,`[2WYVkZ)+|ަ2TרP[9[Y[]X @ y{c"1nK_{6ƞ$X`J0'k*)F?q=[!V(SMMcDs$:JPp-sIHˤ)Pm4 3Ys4k ~Ѩ&{Gjbi{] W[XwK |H (zxuj;qmQeqxTEGHj+9VHP˹v &DC.,|Q+ Њ4rN{QKvR~s 9!-]֙=|r{&dBo@8$ ?xan5ۻx=:79Փ5P @E\()GB8+R0W4Q֨cOq 譴 &v,$A@ Df 3yoEZ3UyK_ϬdbBS~f߲KṼzUInE̵mE*m@WԮLos亠ݢ.7l%h)\Y*0rsLo%̚dm~&u/CE8( Im_|mBl[E8}yy{)τ4sҳM KkPRK"ʺv4E]wКL>80cްdA5#6alFbE'Ҭ-'}oѣbAItktU>9 &cΛ-aId#=TDž GtΩN|O.FT%:yʴ麲+.جlh\(8('U;?bN?Nޥ FALMxdRRg_z#U,24*P1|]vQPiȦ3p| DɎXޙ1m L1%wo%>=Wr)'x&C [!_ `*a2X -(bST%TGm+] aiȦv ۙ퐡Fz#h_ .O&PRf?7kswܕ]QcP2ڑQ4/܆JW۾sfB">zӐDۊt J=U$RrV<svHj? 5^GP +% b?!C v nzo{*-9vG~#R=.#} j嫄Ȼbގzb>!;qJbX6Rj<'Ey;L6~3 X딻^#◿Ǝ=v$%fl H5' M/j3F 4JpCdjLJcX2hOea|irM7D;ͭr{//A5w_+%:y+.*5FS5fx$Ϣī# $b<U3_X'fݶdJ݆(,2aFPʔv,2%JKNF"ӆ&J;8s0zb%?D̈́)4cT0=q'Y X΂K:!P6tS~)%,0agJ7tz,I:mm+~^;tYI >&*K΃jƄl&X)i^fI _nr1|̪Ă,lWj|V7^ɉE -c+Co ).qb P6”lSj ȡy?\o1dtVUyGl00wSӗc%XcCLybt❞ $q >TހSE| GTdCG i5Ǐg!D _ύQG[%#Po0e.댄?7t5n_aٴޅ*|$L2Tc*yHrH9 |c%%SoDz %NFZ Շ\1y2C٠̽+f;SQrR"†BD6C{MMUKxt2@XɅyk L"ƦE(MAo)~;"+fm/Gm}kA6VK.^PW}c#52>M΁c e*݋ OگFjΣ"k&LjYhl8h=RȒ‰G „3a/PGXH5 ΛFE6hbJ8HYxx,f'2ټp)÷[LIaR눘 dY޸YȬL{ wMā (0d* VKJփ}'~aqU9^AaDlƯ~HCS> bNwZIö́e{xxL_JN~9cW& t%}0*A͞ѐ&Nvo/>c=U*#j~ uTnPWsV(aLXP4^|=dpfո t=٤~Ȧ#v74F*^zm`~㹒_I\ e{KQ3hDLw$׏/gì5joh@(ʤC[ c9jL%B35>v$ۏ { _q{PQ*,3aJ60ZT:\OvUJcJSk:LH$Na#9v|z;x$=gC0zMC[U=I.) bIQZױScz:hGr)r<|xҪ@c!$&\¦Pj>?fHfڜqa  ;v "C2`v`ĚAxEA%UrM/׮` d: ]CH`&1) Cy=AUƆ#Zkl;VM6) 6,.Hҗt Caxm56ףw6,5Uw޴ԬW>vAR@}ϸH=3_(0oP<3< Z[ J'X2݌twtR.[ʛ7 lPK+]iYoorb>l;16.4\B׽/&(ȸb<C|v:S Bؓվk nۢ%H[5CĠwWp$6fwEՋد{YR$`oZvjÐ%68F ks*ou7r gHru:$U/beI`u)AMKowAQ,nT2k3*3I:- o羶|X4yZKyBKtVi״uPPٜK |;pǫ9^#]ۆ$7Yޫ3.nW><ϸK~\$2gsPn%4Ɇ:=?֩.,q-D$Y;C6=Rmk2-e+\H8JE<#DO/Yu._U'Hq3O/;JN~}ƒ1 Kp(&+xc@Cn\'<\ oIENDB`perfbook_html/img77.png0000644000175000017500000012303511672746053015242 0ustar paulmckpaulmckPNG  IHDRYs/PLTEHRW4,)4*)4<@BLQ7991#2!.1lZ&6'$4%"҄dߍjݞZ6=>$J39;Ԇi୙/576߾/>DEOS{U=IKp[223ݪ2-)0;>vY3$ חtZ~ݦ~דg]#@289/"w5123109@CMENR;;;ƞ5.+l_a?JO578B;/125..+6BFc(y`i[e]ݶ8-*8?ADMPWZ\5448HN;CG9AE7?C~[߹4=@4$ò߅fRX]Ո]ܔ{/246CH169 B1233;FI͘;DItb`)ЌuDPU^\^1:?178yǁh101YGQWFқrRQVZ9EIۢ6(%ۜ6:<$268167147h2/.3AF"֏l1(#ⱒixdtRNS@f IDATxw#u'Svb 6!" %sF4Zcn3pXa9P4:bJ|LrP-nb9#:PRnqSجƻQn9NI͏«_w~р6^m7i2kYCHqbsi P$GaTIm؊؊?p#IxPL5ˤMoa=G_5ZgIU5x`\7oUP-M|R, >߱l`xlsi)VfsI$O*w&:!V$ o~!e{~Am>٢0$Uߪ+*%܉$Iℒf-{iy/Ҝҽ!(mՔi[›wU$L7Ål e2}RpȬ9rmtb:8W+FTDRzL*ǡf,f]&r91Y.guBȔ;lh@g޶Sxg*Iqjudk6ja,9kiMgж]͍j^^_o#)?zCm."0lOm 0Bs*Fap%=}oK[RTBb $I<,seoss˧Gr.'kռy?1$ٱ`)ڵ}m/M5o-A[btW^›W`rU$xˋ{W&ȎхbWdsSS[23zD/˸)S^HnksRq޻ ^4뀫Զ&Se"]Av YfH*#pYգBe6[2ÜLjS#kPw`EcXٴZT#`[Uk.VHjU\rxsR"3.zF#\"0dL0*>_ҨY--H5xP8n+QU ?۔qe)xT҄W:Ռ;ʧ27xBUla$VJMqͣN;(?`d>LXLP@hD 7) &,&}U A+*R[aT1Ph,ukG`x-ItujRȽdz?$e)!La$óga("VeBT(1.I{$P~P|F1t)XJyN !;d;֖ yi&;!LY@5)ͷqYxs B cTg?3{Vݵ)|+SlAXNZ]7%\Ԁ9E9V",A"1#,y_nynܘc| Lf:$37@~3? f]ԎdPr 7^l݂1(d௬6BU:"XY[.HM ㄂\C-rSr3R Lr2U-,TngXJAyу;4s0u˻*Au:ptܙc}Ϲ^dAl=7bAnҹ\Þ]^^VmB a8g 3ss_Ν[}۶V0i]PqS lc%0VԇC ͊TB-%&(0%S j%nA땥Yi.,\nfs$-ӛ@txC6҈w`ef{`#SXhM}XK\R\ g?f-A2LpZ8|ސҍbjҵ䪼楴^(dj^Ii 69Vբ2*r]ԛGE 8Gj+XHyKmRnXK6Īg?6kRe` ^sؐj@*]?bācY綫 i6LpZe {ݘ<:sD7.QP ʽQRJLWO 3=9fs wjXQI%rJ $cv$+?l3ʆY荔0 7F4O-7({9JdQ_qoAC.zWۍL@ mo LW6S_ %IPǦR^U"CQAMǝGEiW% ~#nSyb,r$a6[osK-@nc!cx RL'")zFfβ* fD@yg,p&:+(WLV-X7VXTAbĥ=|$s):H^QS䋻2(ryqx?e-km jӱ, tezd"?n5X.7v ]8oew[#L)CkېG~a'ƍ|/*P 5ŏ8}) KR`ˀMO 2\fT*q)K}0i֛aG!#Sm+k&)w;beTAI [7~__rFTa ㄳc `6*6`2mݻ_P"! 2]J Jf!MŠ▫VL "n?(կ265B"gY8,,19 Kh]lzLH B0a`b_#a$dq쪵 %_ lx6X)_XfХf'1"U3eP nөV-&)M04Ly7;u.}:?׵,8dfX>KWe 緫Y +`ό3=k-Ȳ N>Lp.,U4b[/u[ձnPߚ1гyF!N*l{L,'ٲ an sef.qGڪ!m5|QN>mlHꈻ%ͱqov[=w;yC/zFЁBv\wE~g;1ǩGGG [SS[;yw|}ެNRTC@ VJ:lj)"]mB-ONMޞkdkyj}wm4R`Зj3 !pW 0W>NBFn}-PL$iG sC-OSF3Vf8!M B X /ecAzmo+0$t=LϤ_O$Bl\]TG%IzH7̭.Խ[cywF%n¸rpޭ$mb"5a=#Ɖ <8S 1&4ux˜67,(퇍n#ͮLRY.y;-#̈́fJ!YhT$_qF ,MBC}1f޴33.q <) " K َ55`(l\e/5|L6˦6`R`D>_.bqF$$ \@QI3)" c6TqG { qc=FXJL I,Pq/PYv X ē8vXO`h2w0m8OV6,V_*K/"_/1%Rt:>w@ЃOA X*Q`Tsb$ IȘ:> -;(XwZҦ4|Р"Tl/l4?H ST_HQMQk6pNL=:0ae (SW*0gqe0v#?Fea[`QVˆU/׳b_^a?cu֊C,GZ"D6鮏^: }9N\CtF@'>p{lrikS'ztwm<}HX 8&1+PKseþcS۷_Y[5\ ݚgR)+1Y%56WiT}'V_b9;0p5LG\Kxt1s;FDu fl:-Ԃ>ⷦ՗1؝{2bWΟNUTzĈV 72g5 Vmiq2j:tD ]hZ-?b]0W A=Hd+OC EbR͸`n?pW1űn[[Sۻ8R{ָ龒/G4+ځVsLRvolSH1FW]PrY #uOyϤzZbL.oC k w)7zrejT |OY2ʏ3-$jj%>1a,4{6RgE#MlX)Q'6[kT rWveͷ|;/XD2S^ɇ]@t*rƫݨbvpP#K^s\IkQVr`°6k]@Om{|6WaUlif5uidr}okފ7$X'AmVG#5qWzy$TƃU1SY\I%%lGvd[&Mct0Ì +aakg+aEK$^"vW*-PբV+0p jpՃhI^!'o>J&0"/K Bpg1ΊLvx wq ̘)sa6m0%5S{1o>)< -O<tھ= ;QkOx&఼A ;%=!}*UKLƋ6'- 9 2?kLR3bIxNm9vj-/^B<.(Bwmt+-Ux5!pMo.}C쯤 :XMeqݚ'͉Y{$XA+mn(07x2*%zq)l3,]yi&eln<"x5$ m_0hq-AQ68"Yּ Y4dEBbF2Y77״6a)|w+eiN?uҚBKD~G3|(=՚,ZDB!rK1_a6H)_/ԎOQEb Nү_Q*/@E<hذ ?K?kzi\ K/x9]Xf~Y(ZoMy7WGe6H=)F5A qw(C>`Oŕdr,ZTľ&YJ?z!hUę,&\(:ULC+s9s IBk@99꧑Nz33E>ѐ6W I{ALɱ:|A7ͩX@vŏ(-:7NXd<ڦ&dC(էam2U5zO(N6'6". s^6hfhcK+F=d;@@wg҂> /1Wl*F>ZQ2OgXRl͐I&"GCL(.y@7ï{p0琐.) *PA |1~JM (6#i7_)xuaeҪ.|v+aW@ (3:yK=$ALZq+vC.P+M[ïp:4.4DPŪZyNgQ.k IDAT f(8lj #K=9݆`Z@fU221an56M?D0yFulA2@lgl![_vϢNc,ܚÃ&iӖ٣7o^q͌X+[dݴ' нhhw>|X2-^^_g{9.Bj)gi-|rHӟFxMFXC&rAaPZp6}M6\:r?},17I 5z/0vfk|珬m~e_4BCc@ =r bY_t !{U*c_vcϟ~\nMOOoKkQ M]!0OX?Ѯ_>^킛eUEbs<-\yLUU` Bhb|*$i\1/|O.>1 n1I-}TOƸ$*ˆ_m$t $6^41>,JxhCIV+)tШ`2M+\ydXs/L;-N@q׊ ^5%X˧+~.綶>z]HEˮFH;~J8CC(ZkvhI71"Mׇ6C m<Dk'%ue4Ӓ:חd}SEWud}rTwO lz'<;1IQO'.&5FJf$_ˀw*7~=K6rlZ^ rToxۡ~DE۱BicyR2˫>Id9!Aߦ3ĚkwϠ[^<)thĔPi`:lqX3TXn0s`A# tȉw WD Q`؜{?$V Re-"Qn-mOvfqbu~@bE(~Fk-Hj4GB+Cd~A74UiOʛ 0-Im?mh)WBV46sXQQu bbv{+)t`~H%B2kfֻ{q Y7]roVq#oж{e Cr*p- L v H# (s;BPʇd(9Da_ټ8&}n3yqpTErBF^eX԰˽̫y<`}p] Py53aa1&0^ G4࢝GYe|fC,F4 h_rJ={hH+^;~[eDTjȤ ǔ'0ͤf" WX\٘.DUÅ- ό}p*w63d,b[j5SHS&&vRddnYɎew˴M3G_Xnpox|uzo|K̻4PYoX}W4٢|` Ab2$ҕSϺwrol5M]~tEZnuutn!cl?_^=#<%e$S@r!G+[(mXu-Veg2m꫗sO~҇W/4M6_e(p Ay/"K`|^Xp-58ZH+{U-Į>UbȌ8B˪w^/(婩̖Ǖ&ov҇J1sw9^VgbZIr'AՏ!-KѾ[_~|69A4SW-mpygϔJv!9~߀ O'Kvʠ[7_-B|Aߚʭ6G]{6eF75F\WZGm)D(z;txiDchQrh2h&U1r˫9ᅧ/kuZ|;߼-MweI%dV󼧌睙em__6N[%ȏTp)ت n%!ֲXOWfknVOOMnw_sbSQF5'ο^+%](R ;0<8~\UC䃢ANы\)ڔiy_ܼʶDN-o0%`$6.W~fV\}hѺ"+TY{> \/z=uӄ/׮oh(p<A}u^R]y_h⿯IzE_zT4k'oroqbkJZ5[Ou >J(]SSyFF2Z*nTOIK*Q?YJ %yÛWq){z9 .7'8TG~;~P@? vtTL' X[SVzfՉ_/I+8(>jUj#GT\F3myQ@n+0+ݔahl`כM *CvGk. oyY;j+iilƪOUmvTƸjzJCwFa0KpJ c߰ K&qeu̙?処@@_,Gv,CvfE'm3z$k¾3)5C cFR3l!k=[}p1QaG]OjAT"){JjpR3lsmykmhi0w,[8;/T2Zz*%j4Opnh\a na{@CWWJZq#>"fKHXW90|Pe}cp須m\Š&5jxq?b 9f+'Tea%Ndn:m֭12<0xsTҼGkfnhhlN{RG—FO1R ]ҙ5@`Wu7S2c⣬:1b pieÁ h=#U*~ F"P;"j1J exe65lzKO HLX}pmxWNn*L ZН}nO_!84fPK0Rbjm9lahVpCE=0$TI0H`CTij4>b T0@d!{ +; ]!F\p&UI¹꾚 HM;zsXaW?F-(;^8QX5JQ`yC/asNPĎH&i)O}|5f= ~cɨhG&<$YqӈYzMfSK掩.ռQB0B,N%z]/nd#OU6&^rX Z"5"2m٘<̷`!)B%7A,y5ߎ/hmIgL%*xϽ¡A-Q߉>ІͦZ&m&g]I SR8!ZlFSA^/OhƊO$Zt y c%dO rC2!R<6z ů2@ 6!b| 6#GHD;>ŕbrw@IVO_[>wRaF2!o#tav߷S-nKaSc*b:=I }k/Ɏ2wlȱR[t`}uw2ػ\|rҡ@-X~|ݘ1Q̚C+{da #֡&CkpM*l?RO vXwk۴SpY XZJГc@b 1Q!"qw =+&#r 9[A <ܱ?.1wIx\oIhDu%oBn` 9ac%mо8)`wNe:"~=Px{z[@H {)|0Z=oW? BfH=n`CާzضG#][5bNp2p <:+hc`msP@h N+/" 0~ό!`mѺ~7alx C`*#ܖDQDJ4t$?bmx oJN]%CʏQi/ +D~cy3 $%$/A ;PjOUZit Ȣe[Dy8{k@/N:ZE cv/fK!?ˉM$p _֞.'d`ɯ唥ugg$ӥiǒycЪ(gi2|8Zӝn x9n UI{V!mg ס٘AyPu,}VrYP˟~3^Clɺ(`emVEBQp,XZeJˬwi# awV졑nlSy U)}ȶ탥;`d<Oodw(UE"6'mx6X'rbF;` <9RRo2CUHxg쩮֝;'V鯟su5HG5Rm@%Y hL5YzWGR|_> >w VX4"!>å˽IAΉH[mX>z/Y#E9g嘻.mlQxu6O'oks30A`+V=,"vXgv򎕟_Yҗ<Cڂ۲#s%:+1L+[_re"˖ӋWy|u gBw`Ô`s˗E"bk2ݛ/V[eUX]$tѷu'UÔ-VI~ae`ᓕXeAՎî?4X;ea4]Y.a]`Z;Km`E+jgl|{,!svROb|HF.y]@A Qe`E9 G XC1B{<4&]Z8 z,:(Ѐ04u`˿+Ô`}xL6DSmmc V!+T)tAN6 -LH=H@SF4_֝c'u$q722- 8cyk#Q .uC28 iŞȓ1+ʨwk 9\d*ʁ:rͳ&؊YZ7Qؽxލe,L$y%;ɑ7Y{V2r)δ*uew '=tu  ^Bc>%Q+B.L {qgVx 7۩BT`Ep=ll=Ϳ–V/*=weR6wmq( kbDf͡VD{"`Vo`Jv/FBipBທŮдuH;mD GdN&мq}6H)ew<}LxGh[;qEآAr.wX!֒ 6f[~s7<ݦ&TVU2yIv*#|cxe|u:?q`9vnƦ'l uۮdw;9xpZ{hial?ess2קVq];LEA0$`II}eߖ-E6[bd}~iѧ?|~.CHÌGo\ѿvONMpjFoe " !ea|ԩ7wX.'G,kΌ3_-ߒO'W^D3߭{w.IB^οz#v1-#@XBscx;kWbꯜkna~d_m}aUreMfh#\|g52[٩0,J9@17ɢ5gE[;w##ڦ@n~?ɗX]g U֟Wލ'V4|6v@dP<5xwpC3E0[/VaE/}Bt浩)qܙj.7XYQڬz׶C#V|mfECXFq3o.OsS[o>Zd6qFo:z. 6ICMzN!͢wùkv} ק*/2o?qͭ<{o\2 ֜B^{Ԧ;%_}lH2:]th2r.֓A;w0?G[-kgغ׶(X|9wZ y03jjT(p}TAcAVYjH=NÓI;ַy>he✰2O8o@;V.֋g[?ĝr , 1D,6Oa k2a:=i xw_}ijjjJǞss'Ĵ6hԁg`瞪J%0ka!K,fQ*L#i)X,rk3k=w}6OvƜ~rȱo^חwޒv^O<\Kݟ|1h/JV(n;i*3~b^Kn3r XGFMb.hYcuh7(&.%^ӽތqG;+H2CƲRYZ;rA 1ӟn2mpTˍO3 ͸+CRH=J\#ZJE_\t m<փpex@(9Y^0X}ϲΟ?grᚂ F3 ^F/ KdY,Y,1RO\B9dǚV.|s5ԯxuk6oZyYݲ~izUsyHZM׍D\Kp<Z`֞l* Mir2m#__]vmtڨoN"aA#y篧;Zf#S=:j%&5t:SZJҎ ـ2)Zq}hן:,^eTXҬgsm4/vt=s{O!č̘j=cVgKD(6Ce~! kL7@zI y~s_YÊGL!'ǩǗ>;PG p֧~. #copGA*5O`_R8cqfpčc>WL44 |/j)+7t_c`/H;+=gy܂(is/T[0Woʳ̙1DJ#Z+ҌJP#ꥩC?,xVJ CK?MJ|t1,ӻ{4^钋BStx^+< |?_5|s <}zp:s&>+ VD3~{b6W!s;eCZlϷ +e|~UEuKJ-cf㠸VLll(NGJ[S>衊I3ÑI 'C^=UL{ZM  O/o‚A3Ԇ-!F# !V,cOS_ͱ}^襟hmV:3Q㳯rp |P~}J>XY͂ iBRFjM?F []~vd,'ą-zQbX 65ZK3Al`C fH5IjTZ[4j-vUo%jI_C\mo <պ2oߪZV8JԊ6ݭT:}*}i1W=o)IxMӘmU> |YcS[mmL*..tbsv;(h 'jNRKL+Ɔ?3́PfyohԩSbW-0ul}o|&3UtQ0CSw( Q` k=&jsy x_lR"WK&`\mrxyHX.nkIY ,ue\:WV6ܤA׸[6I(X-y7I6[Kǎ1n>> :dР$РFa>x{ۏmnҴF5DMvZISzk3cIʸD׷]{x0QM:2a48fX2_SrJ]:eTi[Tb0m5L Ry?a c X[ѣGPs3P4"85o}KxE~נ5J% 49S(^S!$J2UW҄jqݼy'S*s)"3wGK (>Sm^}QW5)t4.RYAݕ;x O쫏*;HpfʏG<\p_0~Ǵ4>k,1-,!![\'HX}؄੃]r";9QDznҀ &[O`yEeV l.=bZDOũU̍1Ӥ)CSQDVT!Z(FW(H9? $m^M6in⵵.:bFJWXk; vpMRReĎ5۪h= T1uhP`E>k.mշSBfڻn;ı`Aj5Asi3Kav AfMk1` lޘq(< V,2hflǟr(>Ac *g% KKFT_ 73ks_ngB/N`Xd@˧O/qr`c9'Okg7֐ Ȧ3?lHD˺wF?CmG>8f x^'hݢ~]_0elp/WmaQټ 3G'&R5SىM8J.pR;ayFK|`<*4㥚WJT "m&0mar ݉z퓇 -5?])R-Pz C8N0[Abދp \ʅpQM$37;Q=q̄ aOG6XR*%+34zw]Q[ anEOc*l1^j`jav:TMc!K~C"mۻ+5=L5h~҃Hm*؈` i9Vx &9 *mv~Mb5,G)PI1`ޤ]cAJ;{fKޝ6#j+Fw#z lVJi:=:pź*CdF+%@4j5s!0Ӄ l QBj kSxTD'3?C6s:._?q 4˲C'*C3c1hO;d"1#NqfQفu6{2/3slaaL98Ky"v\ʣmT@PD`SεH< MAٰֆ YQ[3yprÌ-]Zy3*bHupSŧa UmƌqѹF+M,HIey$UYK8Uy1AK)Qė@:ً5A`%B;gI=Pv]˞X]\kɨ PYS٘cSZY˴T'ǔ@,SƸLkYYh9y;"CxZ! {#@kVfrBfk@CZO2NZY͝4Fk!{E.'oYЕ쨲l/kH4YxcDVSK\׃(@ڭV:;Z1rܪlV˟UlT8L$|%.UG';>4ж2bਬft[ n2EB鞬o> Yw ?0rKY@`Jm]ypphN d=K8(Vg:ɋ,KE&9YI\vV*Cm8׭UuGaK!ɼ|s 9:@_0X'Bz:V7EuͶ1Y4&,lzyEww]?7Fb |!?H+oCcv."Jݖ@AK?B"\upBhWS))N$Ix ROx,tpF kwchڳ[` #iĒ1#U#cY S_Hs\32T1|כlOgF$P״gꖦF |~Sdo0TDK[Jש;bz P oOgp9Tvk>:?1=tΪTA4T ߺ,D:"k]պ蹴b8]Ů~HWsյzJt7b"krerI?NZ,ɬjk~[K;mzhE;p29!(&^ ݵ@ۍn5#a*=\̛asl0a8a[ ԏ,j!,jڟEM<^n! nfSFN Vv7jqFuٗ}ɲh;];^E|*Uvŋ6n m ??I"y*]ӏ! UTAthV5L~t=L%l*J$ f\ .~ݑ \ANɺ,n'kI)cO1MA55QU8jFyd\ڭ'Dt1 `Z#w,N/+Yr,]9o,QlР"k /8eX y+ۉdI̖&g,>@:VxӺ29TfehZTE\XfyDJf==QO൤܆W,d t5j?ãqʦuF:{ $5n\>ǀ5O]Zj.J6[zگ)8lf'w.=+o G#doeU SmjYU]Y4uGZa ea+XPdxedd.Đ%ҩE5C ^-7Rg{bbH8;SOt KwBo,/?t1'u!+Fx`7OL\.F}@KMoy#'~5cndQ4d9 p)?j=롽i~v3OOO= Ld=ː8(q#)8 zY\ ]6Rĉg]~,E>2?{{K4t̸win{'+ Uk6|;7ǀ4 Wa hu3 . }(BpFF,o?fܺ#Kk,t,Yg{{ާEg 4\k/,?|0%`=Tn,F։-#l,YBu>/ݐ47R+zDhE h槱b5F/~*ҷʓ=' o/Yc z9$M o~$]e6-j}d> xů|oOT.ʟ,=ɧ( +Z=)7dKN*˯bɒij,|ر_gOdVgss: ]O6 {5Fon4`^W?O(J/Ԑ_+qʄDsw` ZBd񜈤Qe{:.R$=&`|JÉqQB!7Ci>''Wel]Vr9H^kfԼw:q<7Wp*vU,cPV#Iʼn86;4m4"ƅ @ ZC[O-1HɲptteO^|{OA2 JVV=JH$\#jY[$`>"JE I^OD +^30<X@qwg6p|$vܾ<ێlGM-)Fz7N?{CnfL+01ɂgFW C*״l6ziizfu?[HY4ޑ~ k&-W&6RQ+b@2@fժ(&8]1JX#8h{ ];1ukO|X &fT`퐚%I\+([^LFy&ڈD ډ.|HzS<:=6(Nc >jz'01 mwt* VdI]Ɖ f7P+MewD'!X!HKa_zٴ ؕ+)&s'Y#[PA9Kٔkj@UpAJ}'fAz EÐ-' Z# [w•vM3 m]h݅em郡d:YQ(YPk\:˅Xuc)8'j/9EDǂ?ZPO sj44h=yLT`;ˍx(DwO# 2+yJwp8фQg'>-w4M( T۲[hFMjfSjDӬX=Ɏ5bx>qr٠er5NFyF`B E50E61d-RяSZ=ğY\!̩,(mɺMY,잫|ҭ~%±@ ׂ}cH=@Z X`˶)y4fg4&E (NcD#DP͘V@#a:|w]pjֳV#ɀ]!LYh3ڍZuvu+Bjnv0f"V694VH"R7L I6K(Ez<'4 yկo4"ղY澁JM$ugǶ8%" û"DHEab%εƗ"V.6O {ٯl0C,,1;۠y \ ,: \bWlEf [֫eɓ6ܻY2l(LPYLSȒLn0%f;|c+C4Zz#c9\fLo҇8@kל"dafdr8fRߋړ';<22< R=\G]m%կFM0:&dX%ɕb Y)v$6S(iRR`;4[N3?C6]%Ldu3rz"UNGR7ӕW{g.XaO{ï?$1s)h7 S0Ho_1kI:2h\duk =>es.*jC[VPh_G4zCఏ?l[]3ٙ3boͿP{ՑIX:F89Dյ۲nz8Pw܅f/?x:;#˾v.Q{Gdi+qbϩFݘ yR3l[k~ee7=1##ϛ`X ,gd't KeD|[7>`?ԑ[k=~_z: <$mc@Vxl#K\[<1; ez7̰b$ۆֆT5X~]zA弲#u2k?=>\@ YIڪ_:Njш{~7{G{8KdDAhʉ@ehT&l_Q'%%s2=0oFڮD+kle,*ZMδ~{ Rgp~#h$Y$fh 0a{xݓ8|'իW>1ׯ/ k?uxEΛuVLUp 0kAKa]kmK '0`XȮV ӵX-)Db/4Vt^MmV1{O/!A/~sߦ3ޖϿ7;<7áׯÁcWm0G>{Ɯo9Bu2O)aiP(tb zKkBd8$I0 ]D`uv.J!n\-6'Y@zN+q? og0V11Z,^Ey?*~cDdEmd^+X4PҾ\.ZT5} Y^gXl+J zYB_b)&LL=y-Df{1`@; 5ǎ .}'Efr*!/'}0h.(Ol t/Ψ_7)5!YV Ŗ|[v/^dvd;itx&M$' C-:U*Ë@d_`JG|{`bȑEJ^cG_9M)9~Q&IwQTL]S\7=Yxvɚsf3K6AbpjM)6jp  o\֚oϬ8 mƍU[^"_I])IgNn[xixy gpxZXuhx{'^Pjl5bK:J =O=U4)>C:]ߒzذ} %e`| n{@iݜ;5{R>N1'q :^:ۛ Ȩ=;??8<}/-|_bj CjqTdy4z :ΚxfF@a݀d5RU5-7kw5N۽!NnB$ 2C$YFq62H=Չ~wAv8boX_`¨P+r3I" ?2oϩ|_ɘbCk$ E9j 9a[-Nʾ\|4>_HȘ|jdDң.n|/bxԗF<$rmWW-چnԲ#^BK)q*q Z?Ay! KKG_,M{ b4R*4qcJ+k ˻w ff"@?pP[0E_Gsm*06BI,W[0Y.26bpb- ^h`뤞@S&a e ԗN7-G,هYEP1;80 IDATd~VEQBP}ڼ-vl^Ev}犦^X87F^w$p||)"02(R&V(}4Z[ZNY[[~dW= 3S]YNdF} 2I@68g}ɆZCdO;bgGC*M^^T&{7";)@[wv)yxMmzvɓˑHBܵ]c@Q6B{nCPI;33SԆ85E9cۉ#"4Ô%Y 񚬃YoG"IMM/% Y{ӣ q"4_kǏB~+o,kC# ]_=YE-`$@lQV5_K@!lh=e--6l$9@x oKjj}Ȍ?1lV2GF8S'WAc5=alσ]9#eq,ї聭郉Oh/@,Y5g_ )Tpl_@s Z~b!^TBk'/SJ陙{ʅk8+=ٔ1 R=Ugw#6U&9'Ŧr i"`ޜZWM X.Zt P~_Au!Hv|Yǔ,T Y o8UURU͋I6'sdI U{0rئ",o)!` U4jrdIf _ic 5dI"Lmk9U ~Pٳd_݅r$[y[GjD#g5 @#{'f{F=_XO/R`j*&E,!_r%烞-RʶZY4uG%I|C-m[0BTM `ٱ| 2y5,5`@չ˿tUvqqї0?G_yg"idu83 y9 WO TKe͖92j[3c/D:ݰ(PPn*Eg4 P@=b"K/o:՜'aLrBٔ$,G Y7?W~ꯜq]_YR5j1{&4'Z_M*~xKZ<pqb2- $5[jHA;dRP+saRJAC"[R ] +mfy ,O/Һ W&M䚬o QL9l '^A7jyO֑c!AWlGb,7vS/Ckx߾Vs:^k?Y 5\s^D‰fdL+(DlUW>mg-(M``p6NꡥK"F l+Z.O.X4~.B!K'_̓efhLgFXO?LE,Ox,c.ω9\4_"CX¯?D Rٱ(j@6Wg]Pw &zؾT J}cvfri"L>( YEüjz *3L.'mF6NL4;˰BoQ߾j_8򏳶+]mKӪ\6ǏV\x:T/tF<|g?yftvf1ϡΑ95&?T@5܀"զafyLKmrlNQCV(`x]?~w"NZpW t7:B0g| 4p|l DIf_L&5'l@jKWm`xx6z,,-It5V|#)` bTW~ߜgd?EkY2% }3 b?li-`bwT 3c_R{R:|kx/Y +֒Q/Tb8v.7+Aۦ*"| xmՌx2ڳ_e\LK)r ޑo_E] +v뗟{/ Xu:9il2{}P ( \A>> 4" <,rxZI/ao! `GOC3%Ӽ&pW ^ۂW[>i7ZpruEݶWq~^n-,us Jb3C`?˙>|eX#oaHxqKn堁(@Mi MA B"Z:!"˨b] vа/Y AkO*"XҺӏj$71KٴFU3&>+O˸>L4+Mb4 ^1ۄxyx\N)-<˥1h>Je˪i` tаdDzj}ifR>qONʓ+*˦aZ\!v҂\ d2k 2jp곗f/ފO̦iv- \?uAPnU泫tgp5Od`[*`tႨ!{iOVη/=┨ N4';_h1YO@kQ|{!(2[M,H/%h7τZI@-e5oY{yu`)8k:Fio=2>c ͦiN^ې&&WΦ3K( 屗'cH^V˚6qyBjM* S 9(bsxJ]H́" 7_G#͈"}54Xrj #L j^Ա1VS%g<IõloW& v/3 [Ė_'Ye}p#4TqiϕB0 IQ`k;=tiEմ5U  Ic&g𬣸w|q_'70Oy'Ylf¹)Եך ïYNON!d!bY,b "fR2يH1xja5+ЪOɜ  X b] &A4L4? V 8ZMg2M@QUsZQSR-y-b˪M6'ٹ8-La"|di ͢ъ\~}fG 87.  l\k~)l{,bM$8vYp DL& N PƁ ^ji0 gYT] @&mP[CUCY)qve`|5@SzWs\P̚@aWR*FK++mi-U6P3.v{ɶ+ q&.zP HQJt5Fh(ߝh*-iF4k rl'8 D-ٛVs>?lڴ2tPd=G ;'΃X.n34~!{BXIGQBL,chTk)%0L& G=HOVrXW.( `Nj.֚a8#S!ZbLpBq0Q3wTZNՑՁ,Sd6-n@,- *.C3=gXXJKM`=k*t 莗F߅.LAuPWadd#,|ALF'Vza꓀u|K @CÒ3!JXıheqk_t@P2K=Uqm?/ +k0Sc",9(bMրDKrN$`nઞҜ)lӖUq+[!UUSL)T:dԀߐ]J(I$\sxwvɒ}IMZHDaB T'RVcry v^&{l*f.\%Zh_|VB{:b %Um3/YRwbjKVg}HY aL6׌joohA< 8kfV.YM#{,hTeŠ̱̙j:ךo+uEe^hzX%NVJg>p ?&Ks}y7<,f6ڶFKͨ"0=ieB6,k[g/\]E.fgV\,YP;V=w9Y..Li1IL&?+0-*)ĽVKan%KlEbZ%כ`Kx#uWIhϷdF~.Xj :j-a7~EI9N!h۩1v&y yy̪5n}7 蒴+(h*%@BNSϡW<.(Fu>YwgX7oasl}$CklO"T s] ɯ_7dB\;Xp G̭m`&4cr(>kԊ ѰBf;եs3_gMoDdj?")gB>`lZ{^&h/ d--(->KT<&*`6k=OMkfJl%AU%8J<.(LM͉Qۖ ˠXU7M6жAם9ҷ"fʹ|8Dy/sjQzDYQ5jf8SxR B0; }õ[CՔ̑%-G%kmbք|v1Ah%fԯT _mf0WӀd(* #fJA7րm!Eud%4ÖMlw{bFP80ֽ[օj13pnLk*7|-8R.ɶ]KvV;gDl^ae@;HyӘ,a(iS̚aA8L2/4t\Vqn$Ddm7drˑ숍 ]&c.N7qG&yBPJ+-!GI1>9T|Sh%-SAhڕwrV }RZV[B.k( Rߌ7jDž4qNhAAP3Zpg%كLWޓ,9Iܶc(XΒ۞˻rWO&V %h \ǃNf`0j9rn]ard,>N#gP:A%3wE^sT .h p Εrr 3j!- qe4_tvC4tp ɒ%F" ǚ)9$-7w/~nݣȥI2[E̺id*mȒ_(NO^z] [msc1X9˔mк2 !+1І|JC/Wuƣ80YdV:,YPvv'Y ; Y,T5jc^Gd A,ɏT G0~?x 7Cf‘EsF8/h"#_ fs_ʜaΫ2X(¹fdIcpe &P0PYP}>5.iGp=ك 2N% RokB>R=ټ  pbI{M#M$?s5%jN5~0!ыFa*ŚلBZd:, J4}p.ud؋0dD$ 0mn8ⷓW7;IYD"l4J c{}.6\ΨŁr0k` v=)6wFyiS~:;GU',6xV`صt.7@U ηcf<Y<גߘɵx{ ~dXirLu{W&G[ݢFA٤dF%7]-v"{3ukA?r퍃;{ -<3M(Ix*pxYPn0w߅.\ݛEJdrm1qg)<W~d|<ɲX,6ҿXGgt1{bNtͺ_ @#tHN[#٘ە!B+ 3!yM\Gd77dn5ipcnCI Ur[Q ꬑͮnϫ 7Ё,nzOJ";*U'lؖGoC޸W֭m_b.I `tGjL ynÒu*%@IDATrpMzF]p۾tE֙L:/~c 洩Wo /: WS;/i-~/x/S<+F1\"Hg^_yё7оV<ӶR33ۼ*p,JV| [b;;{moӰmݒy뎬w⡓, I;׵5/e\%vqr!C ^G([cņD|)UdyC/k3txciPVg>>kNᷙ%cc'eY:]Iwiv`~t]wݛa9 XdO1fo 0t [8V8)&1kd)S!mC:s?G d]˓m G֣rfoזMjuָ%Rm{o:'{Bmt";'z?d$29xUd=uԁ}:~4bhV%cr`!^sn%EISihΥ'Hr'Oc6t4:A'lj1gp& ;Z%c/ pB)Mm; dH\-e>'Vk'nL^Wtym̼ےe 7xI8 T }_ecIENDB`perfbook_html/node449.html0000644000175000017500000001567511672746163015672 0ustar paulmckpaulmck E.7.2.6 Validating Nested Interrupt Handlers


E.7.2.6 Validating Nested Interrupt Handlers

Nested interrupt handlers may be modeled by splitting the body of the loop in dyntick_irq() as follows:

  1 proctype dyntick_irq()
  2 {
  3   byte tmp;
  4   byte i = 0;
  5   byte j = 0;
  6   bit old_gp_idle;
  7   bit outermost;
  8
  9   do
 10   :: i >= MAX_DYNTICK_LOOP_IRQ &&
 11      j >= MAX_DYNTICK_LOOP_IRQ -> break;
 12   :: i < MAX_DYNTICK_LOOP_IRQ ->
 13     atomic {
 14       outermost = (in_dyntick_irq == 0);
 15       in_dyntick_irq = 1;
 16     }
 17     if
 18     :: rcu_update_flag > 0 ->
 19       tmp = rcu_update_flag;
 20       rcu_update_flag = tmp + 1;
 21     :: else -> skip;
 22     fi;
 23     if
 24     :: !in_interrupt &&
 25        (dynticks_progress_counter & 1) == 0 ->
 26       tmp = dynticks_progress_counter;
 27       dynticks_progress_counter = tmp + 1;
 28       tmp = rcu_update_flag;
 29       rcu_update_flag = tmp + 1;
 30     :: else -> skip;
 31     fi;
 32     tmp = in_interrupt;
 33     in_interrupt = tmp + 1;
 34     atomic {
 35       if
 36       :: outermost ->
 37         old_gp_idle = (grace_period_state == GP_IDLE);
 38       :: else -> skip;
 39       fi;
 40     }
 41     i++;
 42   :: j < i ->
 43     atomic {
 44       if
 45       :: j + 1 == i ->
 46         assert(!old_gp_idle ||
 47                grace_period_state != GP_DONE);
 48       :: else -> skip;
 49       fi;
 50     }
 51     tmp = in_interrupt;
 52     in_interrupt = tmp - 1;
 53     if
 54     :: rcu_update_flag != 0 ->
 55       tmp = rcu_update_flag;
 56       rcu_update_flag = tmp - 1;
 57       if
 58       :: rcu_update_flag == 0 ->
 59         tmp = dynticks_progress_counter;
 60         dynticks_progress_counter = tmp + 1;
 61       :: else -> skip;
 62       fi;
 63     :: else -> skip;
 64     fi;
 65     atomic {
 66       j++;
 67       in_dyntick_irq = (i != j);
 68     }
 69   od;
 70   dyntick_irq_done = 1;
 71 }

This is similar to the earlier dynticks_irq() process. It adds a second counter variable j on line 5, so that i counts entries to interrupt handlers and j counts exits. The outermost variable on line 7 helps determine when the grace_period_state variable needs to be sampled for the safety checks. The loop-exit check on lines 10 and 11 is updated to require that the specified number of interrupt handlers are exited as well as entered, and the increment of i is moved to line 41, which is the end of the interrupt-entry model. Lines 13-16 set the outermost variable to indicate whether this is the outermost of a set of nested interrupts and to set the in_dyntick_irq variable that is used by the dyntick_nohz() process. Lines 34-40 capture the state of the grace_period_state variable, but only when in the outermost interrupt handler.

Line 42 has the do-loop conditional for interrupt-exit modeling: as long as we have exited fewer interrupts than we have entered, it is legal to exit another interrupt. Lines 43-50 check the safety criterion, but only if we are exiting from the outermost interrupt level. Finally, lines 65-68 increment the interrupt-exit count j and, if this is the outermost interrupt level, clears in_dyntick_irq.

This model (dyntickRCU-irq-ssl.spin) results in a correct verification with a bit more than half a million states, passing without errors. However, this version of the model does not handle NMIs, which are taken up in the nest section.

Paul E. McKenney 2011-12-16
perfbook_html/node463.html0000644000175000017500000005636311672746163015665 0ustar paulmckpaulmck F.3 Chapter 

F.3 Chapter [*]

Quick Quiz [*].1: 
But this silly shell script isn't a real parallel program! Why bother with such trivia???
 
Answer:
Because you should never forget the simple stuff!

Please keep in mind that the title of this book is ``Is Parallel Programming Hard, And, If So, What Can You Do About It?''. One of the most effective things you can do about it is to avoid forgetting the simple stuff! After all, if you choose to do parallel programming the hard way, you have no one but yourself to blame for it being hard.

Quick Quiz [*].2: 
Is there a simpler way to create a parallel shell script? If so, how? If not, why not?
 
Answer:
One straightforward approach is the shell pipeline:

grep $pattern1 | sed -e 's/a/b/' | sort


For a sufficiently large input file, grep will pattern-match in parallel with sed editing and with the input processing of sort. See the file parallel.sh for a demonstration of shell-script parallelism and pipelining.

Quick Quiz [*].3: 
But if script-based parallel programming is so easy, why bother with anything else?
 
Answer:
In fact, it is quite likely that a very large fraction of parallel programs in use today are script-based. However, script-based parallelism does have its limitations:

  1. Creation of new processes is usually quite heavyweight, involving the expensive fork() and exec() system calls.
  2. Sharing of data, including pipelining, typically involves expensive file I/O.
  3. The reliable synchronization primitives available to scripts also typically involve expensive file I/O.
These limitations require that script-based parallelism use coarse-grained parallelism, with each unit of work having execution time of at least tens of milliseconds, and preferably much longer.

Those requiring finer-grained parallelism are well advised to think hard about their problem to see if it can be expressed in a coarse-grained form. If not, they should consider using other parallel-programming environments, such as those discussed in Section [*].

Quick Quiz [*].4: 
Why does this wait() primitive need to be so complicated? Why not just make it work like the shell-script wait does?
 
Answer:
Some parallel applications need to take special action when specific children exit, and therefore need to wait for each child individually. In addition, some parallel applications need to detect the reason that the child died. As we saw in Figure [*], it is not hard to build a waitall() function out of the wait() function, but it would be impossible to do the reverse. Once the information about a specific child is lost, it is lost.

Quick Quiz [*].5: 
Isn't there a lot more to fork() and wait() than discussed here?
 
Answer:
Indeed there is, and it is quite possible that this section will be expanded in future versions to include messaging features (such as UNIX pipes, TCP/IP, and shared file I/O) and memory mapping (such as mmap() and shmget()). In the meantime, there are any number of textbooks that cover these primitives in great detail, and the truly motivated can read manpages, existing parallel applications using these primitives, as well as the source code of the Linux-kernel implementations themselves.

Quick Quiz [*].6: 
If the mythread() function in Figure [*] can simply return, why bother with pthread_exit()?
 
Answer:
In this simple example, there is no reason whatsoever. However, imagine a more complex example, where mythread() invokes other functions, possibly separately compiled. In such a case, pthread_exit() allows these other functions to end the thread's execution without having to pass some sort of error return all the way back up to mythread().

Quick Quiz [*].7: 
If the C language makes no guarantees in presence of a data race, then why does the Linux kernel have so many data races? Are you trying to tell me that the Linux kernel is completely broken???
 
Answer:
Ah, but the Linux kernel is written in a carefully selected superset of the C language that includes special gcc extensions, such as asms, that permit safe execution even in presence of data races. In addition, the Linux kernel does not run on a number of platforms where data races would be especially problematic. For an example, consider embedded systems with 32-bit pointers and 16-bit busses. On such a system, a data race involving a store to and a load from a given pointer might well result in the load returning the low-order 16 bits of the old value of the pointer concatenated with the high-order 16 bits of the new value of the pointer.

Quick Quiz [*].8: 
What if I want several threads to hold the same lock at the same time?
 
Answer:
The first thing you should do is to ask yourself why you would want to do such a thing. If the answer is ``because I have a lot of data that is read by many threads, and only occasionally updated'', then POSIX reader-writer locks might be what you are looking for. These are introduced in Section [*].

Another way to get the effect of multiple threads holding the same lock is for one thread to acquire the lock, and then use pthread_create() to create the other threads. The question of why this would ever be a good idea is left to the reader.

Quick Quiz [*].9: 
Why not simply make the argument to lock_reader() on line 5 of Figure [*] be a pointer to a pthread_mutex_t?
 
Answer:
Because we will need to pass lock_reader() to pthread_create(). Although we could cast the function when passing it to pthread_create(), function casts are quite a bit uglier and harder to get right than are simple pointer casts.

Quick Quiz [*].10: 
Writing four lines of code for each acquisition and release of a pthread_mutex_t sure seems painful! Isn't there a better way?
 
Answer:
Indeed! And for that reason, the pthread_mutex_lock() and pthread_mutex_unlock() primitives are normally wrapped in functions that do this error checking. Later on, we will wrapper them with the Linux kernel spin_lock() and spin_unlock() APIs.

Quick Quiz [*].11: 
Is ``x = 0'' the only possible output from the code fragment shown in Figure [*]? If so, why? If not, what other output could appear, and why?
 
Answer:
No. The reason that ``x = 0'' was output was that lock_reader() acquired the lock first. Had lock_writer() instead acquired the lock first, then the output would have been ``x = 3''. However, because the code fragment started lock_reader() first and because this run was performed on a multiprocessor, one would normally expect lock_reader() to acquire the lock first. However, there are no guarantees, especially on a busy system.

Quick Quiz [*].12: 
Using different locks could cause quite a bit of confusion, what with threads seeing each others' intermediate states. So should well-written parallel programs restrict themselves to using a single lock in order to avoid this kind of confusion?
 
Answer:
Although it is sometimes possible to write a program using a single global lock that both performs and scales well, such programs are exceptions to the rule. You will normally need to use multiple locks to attain good performance and scalability.

One possible exception to this rule is ``transactional memory'', which is currently a research topic. Transactional-memory semantics can be thought of as those of a single global lock with optimizations permitted and with the addition of rollback [Boe09].

Quick Quiz [*].13: 
In the code shown in Figure [*], is lock_reader() guaranteed to see all the values produced by lock_writer()? Why or why not?
 
Answer:
No. On a busy system, lock_reader() might be preempted for the entire duration of lock_writer()'s execution, in which case it would not see any of lock_writer()'s intermediate states for x.

Quick Quiz [*].14: 
Wait a minute here!!! Figure [*] didn't initialize shared variable x, so why does it need to be initialized in Figure [*]?
 
Answer:
See line 3 of Figure [*]. Because the code in Figure [*] ran first, it could rely on the compile-time initialization of x. The code in Figure [*] ran next, so it had to re-initialize x.

Quick Quiz [*].15: 
Isn't comparing against single-CPU throughput a bit harsh?
 
Answer:
Not at all. In fact, this comparison was, if anything, overly lenient. A more balanced comparison would be against single-CPU throughput with the locking primitives commented out.

Quick Quiz [*].16: 
But 1,000 instructions is not a particularly small size for a critical section. What do I do if I need a much smaller critical section, for example, one containing only a few tens of instructions?
 
Answer:
If the data being read never changes, then you do not need to hold any locks while accessing it. If the data changes sufficiently infrequently, you might be able to checkpoint execution, terminate all threads, change the data, then restart at the checkpoint.

Another approach is to keep a single exclusive lock per thread, so that a thread read-acquires the larger aggregate reader-writer lock by acquiring its own lock, and write-acquires by acquiring all the per-thread locks [HW92]. This can work quite well for readers, but causes writers to incur increasingly large overheads as the number of threads increases.

Some other ways of handling very small critical sections are described in Section [*].

Quick Quiz [*].17: 
In Figure [*], all of the traces other than the 100M trace deviate gently from the ideal line. In contrast, the 100M trace breaks sharply from the ideal line at 64 CPUs. In addition, the spacing between the 100M trace and the 10M trace is much smaller than that between the 10M trace and the 1M trace. Why does the 100M trace behave so much differently than the other traces?
 
Answer:
Your first clue is that 64 CPUs is exactly half of the 128 CPUs on the machine. The difference is an artifact of hardware threading. This system has 64 cores with two hardware threads per core. As long as fewer than 64 threads are running, each can run in its own core. But as soon as there are more than 64 threads, some of the threads must share cores. Because the pair of threads in any given core share some hardware resources, the throughput of two threads sharing a core is not quite as high as that of two threads each in their own core. So the performance of the 100M trace is limited not by the reader-writer lock, but rather by the sharing of hardware resources between hardware threads in a single core.

This can also be seen in the 10M trace, which deviates gently from the ideal line up to 64 threads, then breaks sharply down, parallel to the 100M trace. Up to 64 threads, the 10M trace is limited primarily by reader-writer lock scalability, and beyond that, also by sharing of hardware resources between hardware threads in a single core.

Quick Quiz [*].18: 
Power 5 is several years old, and new hardware should be faster. So why should anyone worry about reader-writer locks being slow?
 
Answer:
In general, newer hardware is improving. However, it will need to improve more than two orders of magnitude to permit reader-writer lock to achieve idea performance on 128 CPUs. Worse yet, the greater the number of CPUs, the larger the required performance improvement. The performance problems of reader-writer locking are therefore very likely to be with us for quite some time to come.

Quick Quiz [*].19: 
Is it really necessary to have both sets of primitives?
 
Answer:
Strictly speaking, no. One could implement any member of the second set using the corresponding member of the first set. For example, one could implement __sync_nand_and_fetch() in terms of __sync_fetch_and_nand() as follows:



tmp = v;
ret = __sync_fetch_and_nand(p, tmp);
ret = ~ret & tmp;


It is similarly possible to implement __sync_fetch_and_add(), __sync_fetch_and_sub(), and __sync_fetch_and_xor() in terms of their post-value counterparts.

However, the alternative forms can be quite convenient, both for the programmer and for the compiler/library implementor.

Quick Quiz [*].20: 
Given that these atomic operations will often be able to generate single atomic instructions that are directly supported by the underlying instruction set, shouldn't they be the fastest possible way to get things done?
 
Answer:
Unfortunately, no. See Chapter [*] for some stark counterexamples.

Quick Quiz [*].21: 
What happened to the Linux-kernel equivalents to fork() and join()?
 
Answer:
They don't really exist. All tasks executing within the Linux kernel share memory, at least unless you want to do a huge amount of memory-mapping work by hand.

Paul E. McKenney 2011-12-16
perfbook_html/node64.html0000644000175000017500000000521311672746162015565 0ustar paulmckpaulmck 6.3.5 Approximate Limit Counter Discussion

6.3.5 Approximate Limit Counter Discussion

These changes greatly reduce the limit inaccuracy seen in the previous version, but present another problem: any given value of MAX_COUNTERMAX will cause a workload-dependent fraction of accesses to fall off the fastpath. As the number of threads increase, non-fastpath execution will become both a performance and a scalability problem. However, we will defer this problem and turn instead to counters with exact limits.



Paul E. McKenney 2011-12-16
perfbook_html/node33.html0000644000175000017500000001462011672746161015562 0ustar paulmckpaulmck 4.2.1 Hardware System Architecture


4.2.1 Hardware System Architecture

Figure: System Hardware Architecture
\resizebox{3in}{!}{\includegraphics{cpu/SystemArch}}

Figure [*] shows a rough schematic of an eight-core computer system. Each die has a pair of CPU cores, each with its cache, as well as an interconnect allowing the pair of CPUs to communicate with each other. The system interconnect in the middle of the diagram allows the four dies to communicate, and also connects them to main memory.

Data moves through this system in units of ``cache lines'', which are power-of-two fixed-size aligned blocks of memory, usually ranging from 32 to 256 bytes in size. When a CPU loads a variable from memory to one of its registers, it must first load the cacheline containing that variable into its cache. Similarly, when a CPU stores a value from one of its registers into memory, it must also load the cacheline containing that variable into its cache, but must also ensure that no other CPU has a copy of that cacheline.

For example, if CPU 0 were to perform a compare-and-swap (CAS) operation on a variable whose cacheline resided in CPU 7's cache, the following over-simplified sequence of events might ensue:

  1. CPU 0 checks its local cache, and does not find the cacheline.
  2. The request is forwarded to CPU 0's and 1's interconnect, which checks CPU 1's local cache, and does not find the cacheline.
  3. The request is forwarded to the system interconnect, which checks with the other three dies, learning that the cacheline is held by the die containing CPU 6 and 7.
  4. The request is forwarded to CPU 6's and 7's interconnect, which checks both CPUs' caches, finding the value in CPU 7's cache.
  5. CPU 7 forwards the cacheline to its interconnect, and also flushes the cacheline from its cache.
  6. CPU 6's and 7's interconnect forwards the cacheline to the system interconnect.
  7. The system interconnect forwards the cacheline to CPU 0's and 1's interconnect.
  8. CPU 0's and 1's interconnect forwards the cacheline to CPU 0's cache.
  9. CPU 0 can now perform the CAS operation on the value in its cache.

Quick Quiz 4.3: This is a simplified sequence of events? How could it possibly be any more complex? End Quick Quiz

Quick Quiz 4.4: Why is it necessary to flush the cacheline from CPU 7's cache? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img20.png0000644000175000017500000000375211672746046015233 0ustar paulmckpaulmckPNG  IHDRWwؼ6PLTEgggMMM''' tttZZZ@@@4442tRNS@fbIDATx] DcDzMg7>x, 4M2;L0w`&?>#tfhb_)Dr@,rXޠXXv/ak{aB w:XjvgS>u Mb)Vʶ߅5Uk kG/G/,~5 QۡўwX58о^}?Ph܋-is( !epu*18<f'=E- 2=X7e ^"sQ݃v6?G  w5n uUb4=K RzrZtpUQM޴'R/SړܿHS=8IOr|{:IuVAk!BeδD(@EƷ8'BM+LV"#_}XH,=[Y'蜨=e0lpRW"G#X< ,w7,NN\sjbhb_". 8ZM'hi:vkB9ZXNbT-کkϐXU6b!cjX{N kŮ1}3D,*V}/@b!ZXYT D ts`{֠آj!N4Nr:2JЏ/1L.3rIXC=Kv+'Q:,[^F GrtF}M+&n}Z]5jz;/JUZh?Uuh>_.׽2 ʳr 0Ɋ u\mȅg"Ɖyc>yV$4rV7Jt?4){̵^լ] h]KLMxj7HҪjoKV/F@ZJj '>ZK:ƖNZ=aHV@8Dkj$T:552Xhr耲[ 7j :yݕ |$M Y+g9<2t~S> .k>. H+7Or k  ""._)15&bJ ᔗegR2p[g ]:j2o\|oIH2ވ;kq@kWkUݦ\_UvaUYz6XZ֗>*KaFםu.BoR!1:֯5hH+KԥWē.#PU|b,k }0r5+wAƒ䫦 _8 _k]|5`D[WUWm%_W] F|%_u5.V|`D[|]@Hҿ#J``ڊˡX>wuv.*+[YZ0tRNS@f IDATx}³qhmg ePPLLbg;^5auB  +FpT_ͨ0S=A _ziHOKnhwW~690jTx#~Dz[rvBJ~iD{;XQ NJb)ͧ:]Dhh*!=;TloRZ)3Tґ"$Z1yC*ǵh՞ ~6LOoY }*8}}tZB0ytn_:6^P=;'BqRdY-':A*<;N7gK{?PZ }e.Ej ]{Yq/~{>6T? K@paTܷ{<ȅH`PVg.Հ mYW;>-sSC)qq[%Ƿ񞻆A* d(o"o b+3,>=1µn}.cwr3JRv /1,S7&NgQTKtA5ꄿW84K:.o&7^=];PQtY=@C~[^`znJ r΂/S !^6uFI%ĥ1;7, 8\螚sؘ; ~on54MpMRASn Ѫ&2.I }T ǒRzxnXG#q#Oy&M=xYʭi@(7<{D[$]k#jCVUAvne2CߪonP+vw&jZn&@ tw.Tb<&}]%Lxh$Ly$k|<\pi+po?=0߇([8wpaj"P5ӽsmHP([R @2COEԐʫ+FMOdktNm#O=3wj.4G"t`gxq\&.t1e$#^eޛ^4,K Jl[wxfwtUܳ7u:魶X`յFqBfw!ݣ%_T'՞Afu-dጄt]noL"d]hГkP^Ā}5::uU8ÄoЦ=UP oGVM;y >d0Ubq.)$~3Zuu  v0'+ ϢNA6cӂo_vJr킨jB'pK%͙3AݪA`y!Z(,FLrM |VPJx;E7͈h9&2z{cݰ+;ic+``hv."i@ &C/Bza1wc/rmA0H96Uq_[~A&ֆ2h~ro߹|WcyΥ?p e=lk=<׹5LslؐT+ˏnSDϷRx <>LtM+l`UV^Y¸{3TV>,,a~=?%Ͳ#g (a68S{ ߆zm56Q --tloRX-MpjeK;6T * o< \y.)7ge$kͳ?vE}Q|$@J,ayv>TU]mҦseSVQ1ɝ"O$N ``~'Muw894׶o +,ע ~ 4~|juo{rFŅяjK}.!FKjSݫ ܱɫdW\HΐTSW`hk@rDK%UX R /0^ʬ8,בjԞGQԋmϾ =rr{by 6dmJqN:?z"fNHU@Mոz!t(9}CAVႪ2HD%m=`"p2u;u*)Ze7̞pEeh d+. >}>õC[%4ژr,[hެC&[iAռmX9ܝeB͆7([mm哀`uh.Ii"##׿~edՅ] א;dwNS|rlfkx0UxdHUF5lIGg=^Aef&)J`b:%HЋ*SU-|8q8Ѝ |)qʽ7hRhaƐlGocn)Q~1$Y*bGbnFr*'}I#΃ o?e*b UP,bjQ*8pPKlBcGV!Mr:%HV uԟAŦD+T`dJ6NݑpULkdǩfBl}1Qx9) } gxMxۻVG$J-a #J\ً6h0=ɏ ۽+sLÚPϙ^'(,]e`wb0V tvIY\ǀpmH!~ jvdf!?ldfWK7h4_udT!+why|,iF5(!K:斲]_Ktk+G@SlD+u5 Jr{c9:uK0(JFa ^݄kUcY_MT3 ɟ2/tAj5xI&;gÛ, D+Mb^A4.)YXlSN#%b SocB Ї?\ ؃l^Լhg(,)i Ħ B~q27-߆r)F Fs iWl73_[#jc&|.]9K¿8Eq+ׁ$Q NE"{ 7cfuG!A 7"vc FyMh=FuŔ$Axi8ZYN!`?l%Ù=Z~_n{2NŤ1FBHb6S`\\eweao.vZB3$B<+RuuS&s٭/(EJ~Xp2S5<Ϋ{ l /M[ՑȧUW֜P:b: e?t ]ˎs}5>h+ΰ=.5l 'a )b ~ALAV %Csxh 6@S6N( oɥ/P' !9L&sDRJzXT.2i*w~!ٶ0>z&&Y uz;Z~ZYH¨[cGXڇ|mJ7Ocmm[9s'=d5hws92hJ96??',L= JJu4?8\-0^V"9^K#u0t`{@7xp| PH'[f6V0b֢ɯc7j7 @BhXohhv ;61fZ>%dbhfjeCDAa0!s)?wJrd!>), wo@8,B_l֜h M7pOв.-qT#,Uoi Wmd lEW]A׳uH54zӈW&;U*DiMp_F#@uSEAS=x&zkk(<_j)Pw$ڨ5=\[N@N[6VaU)l$ar2dj27l L1 8!+)>H ]dap@, ;-;01(uO,EFLaޒFabfm%\+ A&gr[-SmPx5MtAR&㳢j|SghUQNh0`˷6hG'd .PSIɶqn}Eaial| ۯblP:3Ozw>Kr?#t{-+/ \'dËZN, U6w up{zڞjH t=9KDCc&[xߛN9:T5Z%]6$*˒;EBXe.ŸaE-{SKJR1]+Us $Y__! XSU.=ԨЀ}1pCbAdpbwKi]k(yј-з ,~0s1 rXG_vCq'&m{5u9;_r+\k _cGg9wx2?I&\,N6tM@/W϶'07q*j8ކ2L릏TnT_X9eeqpDzدpZqc GA-mos/,x\;{cWv_wh8rµћc7LD6vx$e/dYT $|@lQFV;ȩ6u:~ˉqa)m$鸟qTt6rvΐG+E Ho4tL}zXYʞiYF{^|!Q! [-w%fNa:GsrADuZO$`7yܬʝ'^|@F3r{ 6ӵ166ڼk1¹pq-{%Ј̲,y]$RlKЅ'L}nJh+cD+S `#d֐ח{ &:ުϥ-=Ϥ_TsE(N%3jw( E ț4\V;WukO\o^UW4T(L4zY\ e+ҟg*bz7 Ulc3b:)1SyJ[nʊf8&,W %P$Ț,RW"mL$0Q| ELAL_/3 ٢c<Ď4(crGbgY6ʩ"/1$H-" HM~P ;ebfܛ :R͢u(7p3e+a\"$E:=d»[*aѬوr A ֊X9!tk8x .X8؄/Th(dwi-W4Wr7Q`17xR}y 2^d&kZ1b7A_Bpo Ě$*crMƯE#Kzbf|TWM'Vo/ \&#ZOөE /g(mŔBSDx-S?+m!}NUy^-9z$7 1_C&Qv]٤q`꺠) 6P>,hbQN Qloc|X)ȫ;:bn-1~K0k+k‘x-/NT.,KP|pVd-k54h/wtlx>agzϏ܇wa/ZY]]E<% =ћ`rR(/D9ƁW?,$꨺܇oE`U;YV?XW* [ZE, B b/Ey,E.瞵WV X;Aqie%mnCI/C54\7$~a¡Jf#&q0NALz:'ղEy*G\Ӈuzuͦ֡pu*wcN a(]c:ƒX% ͥd aƏ ^Gߗ?3,'MX-7X}lJei0K9.t\9fbRp$>qoYj!o_KGNbZTo+PCon[9 !JRCgf;IKz/8X*),YD+EF쨕 b;k="<-W,6 VBΗ ) %<;b>2C벻lI9wNIPՌ;'AY׎O+^÷l ))_aSѱrA4WZP3b>/w-s܃D)|m'd{,j(`g/trr簁.{ %0X'w{15XG$fscEOcfc|I%Л1M\+XQ9hO6ɝE:eLM7+gW66bm}{hHJ{ͬ@-`lRޟ3گ!Udw4r5ra ;S'i/Aķ.vw5MV09yU" QZw>wQ\:7a>d)pbˎ̬]oTn&q 5,ފ@6 ҹ>ȸ4mxND+iǭ5U_.Mb6j-TpYVt9J3Eyt1+Lٶn] 9)xƜݶ9'V1V-scp 1"(¦+H=^Hz+ӿAL bPT澤TS)+Pt&g_*k*}fŔx>!C[Q|s;rۃ,9?wq.AU/0Z SL^&B B-~ulc3h!m HGwњ-TTau&f[N=Tag%޿'`#[Lo ̼G!_C^_[ w㘘"@qYaׂ Er%^ʹOp`ovgh}:(.8!u0z@bztƘ"uC0_ZHIDAT  C;o8-WP>ػM'PR x:iwbڻa]IKdJVt1-#f wS@u4ߕj"y00’ Qԥ:$K_zl8:i'O.lZ!ɴ9m8?lT^1m<{,p5*ʩT% )ٔt˜+*k=A4U&ٜĈRl "ݕn">V7)!bO1@k[ 2f#\=yD֘J*nS]~s"@NJ>u=)7Tz:7jğJGڷ:]VW)JvFkJs鿤NjY_}V|:28prG>gcTCu􆯤k Lח t֓R.|u~|6h;tĉ'~ HR>Y.ufYl|FY{/6&cIlw4u&R 8Rqi#:&hSukb2:L펦niA%p8M|FY{xDZ8`djGAFbS9p\Q$'NV҅u(U)k͋}Nv}m[2lF7۷UU. %c@nj-W4 ʆC%o][BU5|">p»X_p&=e}q>S7Epa@g eċd/g=qğ*%,.=N'37A2/R{{} :39L7e"27S?qi`q%-Օ.vh5H+dFdFN'd9΍? S ̩|e彃]?529q͑VЀSrxK]boyYwq'N 8MY~Z rFgbήodtWh8dLL֕FJ<|FTygD'Je:Y]]8ߊXYbk1vW# gkO-`6kFhk SZj~&vI9Zۚ)-+6q3S yuJ@[m^@G9P_2kuHzF pXʕo̵q,+1jq+z,K@JJZ[uoE )V- A<5@'{ȼ lo Z@ w۽`W'N?;mݑ:WDf9b- S]լp'ի)rʱӖΉgSDs|Cx$=Oa\͘=;Տ,9] k0b }^[k8Ͱ+c, Ӷ OB QYʆ,td9,G"i>6+!1NLbw^%6-l0A)]9`>4Zqښ>󆃨t%^HΗ$`dOX[B#æ 7~PN ͱȈ ro#6V'!oŨp &БiXt?Ν6#V@]Uy_ut?q{ANY~U}eVoJ|$Oҍ3mʷ$>I'3~Tc֟2o{'~˼[P6,Cw\jYt-C5B4Oĉ# Z1꼐^--iNO )}.2u^Jm]QK&féVgRji_&*l1xK+n)y5G%qW*ʧSI)\\#Ȅ[\s&J?nʓ8fKr`B]d=t04bϮ,Z>^soz? naT^0/.XҠ[*tR vweg~-~\FZU} gpv!וּx= WkD3~P=qq$wo`=̹}͵ӷ^[#\*6Y͍YYꓸ*i3:gq}~:ixҍvɢ4h'96;qR'Nr J̓pRӡ)uZ"m.:Ρz wHIENDB`perfbook_html/node349.html0000644000175000017500000001473511672746163015665 0ustar paulmckpaulmck D.2.7 Use Cases


D.2.7 Use Cases

This section gives an overview of several ``use cases'' within the RCU implementation, listing the data structures touched and the functions invoked. The use cases are as follows:

  1. Start a New Grace Period (Section [*])
  2. Pass Through a Quiescent State (Section [*])
  3. Announce a Quiescent State to RCU (Section [*])
  4. Enter and Leave Dynticks Idle Mode (Section [*])
  5. Interrupt from Dynticks Idle Mode (Section [*])
  6. NMI from Dynticks Idle Mode (Section [*])
  7. Note That a CPU is in Dynticks Idle Mode (Section [*])
  8. Offline a CPU (Section [*])
  9. Online a CPU (Section [*])
  10. Detect a Too-Long Grace Period (Section [*])

Each of these use cases is described in the following sections.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node384.html0000644000175000017500000000657511672746163015667 0ustar paulmckpaulmck D.3.6 Grace-Period-Detection Functions


D.3.6 Grace-Period-Detection Functions

This section covers functions that are directly involved in detecting beginnings and ends of grace periods. This of course includes actually starting and ending grace periods, but also includes noting when other CPUs have started or ended grace periods.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node385.html0000644000175000017500000001560211672746163015657 0ustar paulmckpaulmck D.3.6.1 Noting New Grace Periods


D.3.6.1 Noting New Grace Periods

The main purpose of Hierarchical RCU is to detect grace periods, and the functions more directly involved in this task are described in this section. Section [*] covers functions that allow CPUs to note that a new grace period has begun, Section [*] covers functions that allow CPUs to note that an existing grace period has ended, Section [*] covers rcu_start_gp(), which starts a new grace period, and Section [*] covers functions involved in reporting CPUs' quiescent states to the RCU core.

Figure: Noting New Grace Periods
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void note_new_gpnum(stru...
...23 local_irq_restore(flags);
24 return ret;
25 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for note_new_gpnum(), which updates state to reflect a new grace period, as well as check_for_new_grace_period(), which is used by CPUs to detect when other CPUs have started a new grace period.

Line 4 of note_new_gpnum() sets the ->qs_pending flag is the current CPU's rcu_data structure to indicate that RCU needs a quiescent state from this CPU, line 5 clears the ->passed_quiesc flag to indicate that this CPU has not yet passed through such a quiescent state, line 6 copies the grace-period number from the global rcu_state structure to this CPU's rcu_data structure so that this CPU will remember that it has already noted the beginning of this new grace period. Finally, lines 7-8 record the time in jiffies at which this CPU will attempt to force holdout CPUs to pass through quiescent states (by invoking force_quiescent_state() on or after that future time), assuming that the grace period does not end beforehand.

Lines 18 and 23 of check_for_new_grace_period() disable and re-enable interrupts, respectively. Line 19 checks to see if there is a new grace period that the current CPU has not yet noted, and, if so, line 20 invokes note_new_gpnum() in order to note the new grace period, and line 21 sets the return value accordingly. Either way, line 24 returns status: non-zero if a new grace period has started, and zero otherwise.

Quick Quiz D.42: Why not just expand note_new_gpnum() inline into check_for_new_grace_period() in Figure [*]? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node189.html0000644000175000017500000003667311672746162015673 0ustar paulmckpaulmck 14.2 Memory Barriers


14.2 Memory Barriers

Author: David Howells and Paul McKenney.

Causality and sequencing are deeply intuitive, and hackers often tend to have a much stronger grasp of these concepts than does the general population. These intuitions can be extremely powerful tools when writing, analyzing, and debugging both sequential code and parallel code that makes use of standard mutual-exclusion mechanisms, such as locking and RCU.

Unfortunately, these intuitions break down completely in face of code that makes direct use of explicit memory barriers for data structures in shared memory (driver writers making use of MMIO registers can place greater trust in their intuition, but more on this @@@ later). The following sections show exactly where this intuition breaks down, and then puts forward a mental model of memory barriers that can help you avoid these pitfalls.

Section [*] gives a brief overview of memory ordering and memory barriers. Once this background is in place, the next step is to get you to admit that your intuition has a problem. This painful task is taken up by Section [*], which shows an intuitively correct code fragment that fails miserably on real hardware, and by Section [*], which presents some code demonstrating that scalar variables can take on multiple values simultaneously. Once your intuition has made it through the grieving process, Section [*] provides the basic rules that memory barriers follow, rules that we will build upon.

@@@ roadmap...



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img122.png0000644000175000017500000000710011672746043015302 0ustar paulmckpaulmckPNG  IHDR CwMM-{ѾGN\J#?=(qg24D\ڣ`n$wF<0Y#b; JF4'Gf4P<N6<[|LP߂Em-1t)ce;c-"jkULb#lg)^(HIs q-U%`KRiZb OG"w֩|# 5$eS=[L,RHR/loV+wF L u-jcfl/#l\y{ajS&X|myI;!,A8-4lE`*(ndai[˭"5sJwr7d`hkjvPHޫ-bNH%ц55L?pPO/u@YJBsdutCfKnON֡A"Drt[>ػ/bCے \:'QhP(MLm Ӻ6U B}TxdF uc-x UW+rM:@m:h#\ug,t-ړ,6IxӤB{)ج_RnƮ c{l֍te߰lFҤ5|>`{(PS6,e6+×KSugVt=Ij#S7w^$-G#{ (H_MZ(Nݘ~U/nƂ6o2!+z6`]O$=1z/w=So2)l懭.Y\cHÌNڔօ&3J*2@0|р L=V2:,:Wy\t]V{T $UMWq8CиiN댘z2bLlaJ'~氂z̏q|tlndg՜6DMUܔz xy-^Vj/0y–\9=NkDM䜐W-MAJg/0-t@3՜VB?CJoqj榛eӭ2h&t#[#ߚ.QT3-)Ldʹ#;f0M}5( ytc?H=;Ya9BҎ]]Ü_ؔ9m:L!$/gE K.`ipY;[]zL*3 &e?oWg jz6:8axkFհH=ӜS~K9O|*leAE|m/S54<7:\bR]E r,됲Y \PryH1@E=ZӪXCvB|4.Dsė,Wh >.Dob mr5$b=]ℚ4Q24 됆7:%'NZR U'O8]UM~t$hKctޫo-CYxۺ\I*gշ~Nu4/%/{Ė5y}o^"ȣ+|ÜljrBejK?>c&v C.5 Read and Write Memory Barriers


C.5 Read and Write Memory Barriers

In the previous section, memory barriers were used to mark entries in both the store buffer and the invalidate queue. But in our code fragment, foo() had no reason to do anything with the invalidate queue, and bar() similarly had no reason to do anything with the store queue.

Many CPU architectures therefore provide weaker memory-barrier instructions that do only one or the other of these two. Roughly speaking, a ``read memory barrier'' marks only the invalidate queue and a ``write memory barrier'' marks only the store buffer, while a full-fledged memory barrier does both.

The effect of this is that a read memory barrier orders only loads on the CPU that executes it, so that all loads preceding the read memory barrier will appear to have completed before any load following the read memory barrier. Similarly, a write memory barrier orders only stores, again on the CPU that executes it, and again so that all stores preceding the write memory barrier will appear to have completed before any store following the write memory barrier. A full-fledged memory barrier orders both loads and stores, but again only on the CPU executing the memory barrier.

If we update foo and bar to use read and write memory barriers, they appear as follows:



  1 void foo(void)
  2 {
  3   a = 1;
  4   smp_wmb();
  5   b = 1;
  6 }
  7
  8 void bar(void)
  9 {
 10   while (b == 0) continue;
 11   smp_rmb();
 12   assert(a == 1);
 13 }


Some computers have even more flavors of memory barriers, but understanding these three variants will provide a good introduction to memory barriers in general.

Paul E. McKenney 2011-12-16
perfbook_html/node414.html0000644000175000017500000003444011672746163015651 0ustar paulmckpaulmck D.4.2.3.2 Grace-Period State Machine Walkthrough


D.4.2.3.2 Grace-Period State Machine Walkthrough

Figure: rcu_check_callbacks() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_check_callbacks(int cp...
...2 spin_unlock_irqrestore(&rdp->lock, flags);
13 }\end{verbatim}
}\end{figure}

This section walks through the C code that implements the RCU grace-period state machine, which is invoked from the scheduling-clock interrupt, which invokes rcu_check_callbacks() with irqs (and thus also preemption) disabled. This function is implemented as shown in Figure [*]. Line 4 selects the rcu_data structure corresponding to the current CPU, and line 6 checks to see if this CPU needs to execute a memory barrier to advance the state machine out of the rcu_try_flip_waitmb_state state. Line 7 checks to see if this CPU is already aware of the current grace-period stage number, and line 8 attempts to advance the state machine if so. Lines 9 and 12 hold the rcu_data's lock, and line 11 advances callbacks if appropriate. Line 10 updates RCU tracing statistics, if enabled via CONFIG_RCU_TRACE.

Figure: rcu_check_mb() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_check_mb(int cp...
...per_cpu(rcu_mb_flag, cpu) = rcu_mb_done;
6 }
7 }\end{verbatim}
}\end{figure}

The rcu_check_mb() function executes a memory barrier as needed as shown in Figure [*]. Line 3 checks to see if this CPU needs to execute a memory barrier, and, if so, line 4 executes one and line 5 informs the state machine. Note that this memory barrier ensures that any CPU that sees the new value of rcu_mb_flag will also see the memory operations executed by this CPU in any prior RCU read-side critical section.

Figure: rcu_try_flip() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_try_flip(void)
...
...ck_irqrestore(&rcu_ctrlblk.fliplock, flags);
28 }\end{verbatim}
}\end{figure}

The rcu_try_flip() function implements the top level of the RCU grace-period state machine, as shown in Figure [*]. Line 6 attempts to acquire the global RCU state-machine lock, and returns if unsuccessful. Lines; 5 and 7 accumulate RCU-tracing statistics (again, if CONFIG_RCU_TRACE is enabled). Lines 10 through 26 execute the state machine, each invoking a function specific to that state. Each such function returns 1 if the state needs to be advanced and 0 otherwise. In principle, the next state could be executed immediately, but in practice we choose not to do so in order to reduce latency. Finally, line 27 releases the global RCU state-machine lock that was acquired by line 6.

Figure: rcu_try_flip_idle() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_idle(vo...
...flip_flag, cpu) = rcu_flipped;
15 return 1;
16 }\end{verbatim}
}\end{figure}

The rcu_try_flip_idle() function is called when the RCU grace-period state machine is idle, and is thus responsible for getting it started when needed. Its code is shown in Figure [*]. Line 6 checks to see if there is any RCU grace-period work pending for this CPU, and if not, line 8 leaves, telling the top-level state machine to remain in the idle state. If instead there is work to do, line 11 increments the grace-period stage counter, line 12 does a memory barrier to ensure that CPUs see the new counter before they see the request to acknowledge it, and lines 13 and 14 set all of the online CPUs' rcu_flip_flag. Finally, line 15 tells the top-level state machine to advance to the next state.

Figure: rcu_try_flip_waitack() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitack...
...rcupreempt_trace_try_flip_a2);
13 return 1;
14 }\end{verbatim}
}\end{figure}

The rcu_try_flip_waitack() function, shown in Figure [*], checks to see if all online CPUs have acknowledged the counter flip (AKA "increment", but called "flip" because the bottom bit, which rcu_read_lock() uses to index the rcu_flipctr array, does flip). If they have, it tells the top-level grace-period state machine to move to the next state.

Line 6 cycles through all of the online CPUs, and line 7 checks to see if the current such CPU has acknowledged the last counter flip. If not, line 9 tells the top-level grace-period state machine to remain in this state. Otherwise, if all online CPUs have acknowledged, then line 11 does a memory barrier to ensure that we don't check for zeroes before the last CPU acknowledges. This may seem dubious, but CPU designers have sometimes done strange things. Finally, line 13 tells the top-level grace-period state machine to advance to the next state.

Figure: rcu_try_flip_waitzero() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitzer...
...rcupreempt_trace_try_flip_z2);
18 return 1;
19 }\end{verbatim}
}\end{figure}

The rcu_try_flip_waitzero() function, shown in Figure [*], checks to see if all pre-existing RCU read-side critical sections have completed, telling the state machine to advance if so. Lines 8 and 9 sum the counters, and line 10 checks to see if the result is zero, and, if not, line 12 tells the state machine to stay right where it is. Otherwise, line 14 executes a memory barrier to ensure that no CPU sees the subsequent call for a memory barrier before it has exited its last RCU read-side critical section. This possibility might seem remote, but again, CPU designers have done stranger things, and besides, this is anything but a fastpath. Lines 15 and 16 set all online CPUs' rcu_mb_flag variables, and line 18 tells the state machine to advance to the next state.

Figure: rcu_try_flip_waitmb() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitmb(...
...rcupreempt_trace_try_flip_m2);
13 return 1;
14 }\end{verbatim}
}\end{figure}

The rcu_try_flip_waitmb() function, shown in Figure [*], checks to see if all online CPUs have executed the requested memory barrier, telling the state machine to advance if so. Lines 6 and 7 check each online CPU to see if it has done the needed memory barrier, and if not, line 9 tells the state machine not to advance. Otherwise, if all CPUs have executed a memory barrier, line 11 executes a memory barrier to ensure that any RCU callback invocation follows all of the memory barriers, and line 13 tells the state machine to advance.

Figure: __rcu_advance_callbacks() Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __rcu_advance_callb...
...g, cpu) = rcu_flip_seen;
42 smp_mb();
43 }
44 }\end{verbatim}
}\end{figure}

The __rcu_advance_callbacks() function, shown in Figure [*], advances callbacks and acknowledges the counter flip. Line 7 checks to see if the global rcu_ctrlblk.completed counter has advanced since the last call by the current CPU to this function. If not, callbacks need not be advanced (lines 8-37). Otherwise, lines 8 through 37 advance callbacks through the lists (while maintaining a count of the number of non-empty lists in the wlc variable). In either case, lines 38 through 43 acknowledge the counter flip if needed.

Quick Quiz D.58: How is it possible for lines 38-43 of __rcu_advance_callbacks() to be executed when lines 7-37 have not? Won't they both be executed just after a counter flip, and never at any other time? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node302.html0000644000175000017500000001536111672746163015646 0ustar paulmckpaulmck C.3.2 Store Forwarding


C.3.2 Store Forwarding

To see the first complication, a violation of self-consistency, consider the following code with variables ``a'' and ``b'' both initially zero, and with the cache line containing variable ``a'' initially owned by CPU 1 and that containing ``b'' initially owned by CPU 0:



  1   a = 1;
  2   b = a + 1;
  3   assert(b == 2);


One would not expect the assertion to fail. However, if one were foolish enough to use the very simple architecture shown in Figure [*], one would be surprised. Such a system could potentially see the following sequence of events:

  1. CPU 0 starts executing the a = 1.
  2. CPU 0 looks ``a'' up in the cache, and finds that it is missing.
  3. CPU 0 therefore sends a ``read invalidate'' message in order to get exclusive ownership of the cache line containing ``a''.
  4. CPU 0 records the store to ``a'' in its store buffer.
  5. CPU 1 receives the ``read invalidate'' message, and responds by transmitting the cache line and removing that cacheline from its cache.
  6. CPU 0 starts executing the b = a + 1.
  7. CPU 0 receives the cache line from CPU 1, which still has a value of zero for ``a''.
  8. CPU 0 loads ``a'' from its cache, finding the value zero.
  9. CPU 0 applies the entry from its store queue to the newly arrived cache line, setting the value of ``a'' in its cache to one.
  10. CPU 0 adds one to the value zero loaded for ``a'' above, and stores it into the cache line containing ``b'' (which we will assume is already owned by CPU 0).
  11. CPU 0 executes assert(b == 2), which fails.

The problem is that we have two copies of ``a'', one in the cache and the other in the store buffer.

This example breaks a very important guarantee, namely that each CPU will always see its own operations as if they happened in program order. Breaking this guarantee is violently counter-intuitive to software types, so much so that the hardware guys took pity and implemented ``store forwarding'', where each CPU refers to (or ``snoops'') its store buffer as well as its cache when performing loads, as shown in Figure [*]. In other words, a given CPU's stores are directly forwarded to its subsequent loads, without having to pass through the cache.

Figure: Caches With Store Forwarding
\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBf}}

With store forwarding in place, item [*] in the above sequence would have found the correct value of 1 for ``a'' in the store buffer, so that the final value of ``b'' would have been 2, as one would hope.

Paul E. McKenney 2011-12-16
perfbook_html/img62.png0000644000175000017500000001373111672745777015251 0ustar paulmckpaulmckPNG  IHDR*+; tRNSىHIDATx];9=L)4 h(W@f5 h? |=`, (mi]P璼'ReD0oG:kuݷޘ- ^Y =4BŌmj) MD2@M̦;z T91fUf⩽cV"5K{Įx{/(kָ*uWk 3'`9ԀqNre=2 g_K]?zCx+,%BGBOOXx)ljYu`TD`UCōfgEt$Пexﶵ鄒}gr:A}3N!o Wp*D:5%TZ]PSc)0IӕӼIR_6.J|IyŁ6tzǸO.$zxL) T=Х%PߒD7ʡbi/ Fy󓶤6~2cKR~BGfTNA(9UaL؝4˜QS_CQOpRRTm|Rte/;5aO]; FFvƪ0˃)^/@m?]Dߏ=Ql ӔhL@kͶf֫nLh S~)K[r *zfClzLe$PYM!J+q{ 6֪ןfS2jit%(jlFuy4z~bXż=uR۱Ků` M~)o_awOQ=0 8*\0w'5)o`NKxH-uMġLv$܃zOt2B3bč C٦*Mά!2\2 "CY%L.:VBdd,ed ]GR> NIZngoL38\'RqBV JɨY[V݂Q;7Uw0|(G;s'b}rp09H pH' 2J%M--Ukj6@rLl$$-1IH P֣!iʑYhtBœ$ Tk%8uT\VlLQj47~|CrKXA(3R`F6& Aλ(,V۵-Wu&jجHFi.%d4`J8dPlhbi3YH5h`ބ(+ٞ.$ 4vѿ6?_ә?-I&:ضhZ(w*Vͯ",\$WB*hQZ 5*I`)`>zr'!Oe- :IK'l"r05 #~ju !c"jN9(d"g{qο-[}=}^  4DQ2RR'#AXLgYe"ZlRuz9(? WF0pMY5Ĺlqzc؀=; HY[6+%K,6i**smP}u7a 7x=}R7aZOIZ9 s bXDVK!X#ǼXۓQ5[-#:\.AqQc:" W0;O wyDMC&IYH /%g:9^-Kzjd*Fj" Ɲ3,dF)q˚:9C'ny3R$,j~%˨SC =>5 WUB:w^udUiaG#SZQWhV@1_M*jlfsk@cՐT+86t>_擣F-Y{ Zլ'N5>'4k䵨e%}<oXCz}3kg"@O*7] اP̬Hn:, ˈkP"(JUɣ^A7u3hvjV'؃١I6z5%E+Eœ`Djd:Ɋ]dQ`ˋlnb-C۬ rZ+vjk8-@zrSWp_dL*r(bͨbVTEfOMj+LϚ9BVuѳ{N5ҚVy7XL0gR!Zt ߔ|o_yV@JTUBg5V٦ƦT]q/u>J2%lIf״J'/uF.+_8ztXɍx$jK{~wZųݪ2 Eu3*9dN+xsٰq zK9OӃĭvnd&丝3'5Y׆ͤ%/KWyT@^j-;-u~5p '&EIMNެZg8sz JlZblaiIAEM8I$[ @b˘Ri=JM  _O+yZ_-}y:#_z\ʢ~z.>O^̧NȉRj{z)/cu 23NyQ~(t Tbl=Z%;^Hڴ'[Zi[j19HoBM8V$z^EX0}/ڨk[)en43h30'",c]AUhdX)<ʇ:k hO=JOY[ȱp e:E!!n"a"Z-V!Cn_n5"ǢOY^̸spyY鬊DN%S/utKFnp-+&derx]Ef֙ŬӱsÓr\p; -8ZGJ"̷N$HhC;Usݫ$+Gj4*Kȫ y|5^OSX08W\_ݽ3>-x4i]D\wrw7}EA t)n,Hg,%J *5mZ*V,w'8ռ*?eZ1?Goufu /j_-LHu}ϯ[-~Thj\O??|J權 j. n(y[tvUڰ TzWRmJqz6'@_ukan6\Pda(Lܱ5ОDZ{pxoj(V (pN`׎f_bl݀<EvG܊  p >1| 1$ZWR`#Ir ֶTGbF_*,F+WBh*!‡bRgVwFJ=3 8#TUJWgUg2ngUrT C*C) ՅQSWHXJU-[4O)^TKfLuc%6ϷW)nF!܆Tr2zk @9+ȵYk]ptkw)dETr,߆YJea KxB#UF55)쯦\ *;`8}nǃ!ץUXο w)FAu/CBW!ׅVh*,<GGQJK.B%-X+TT"VP oUUQzC ZajI5Mv?Z-j)V[X*TL /6b&;GH9ryDYfX$E+IQ'n)TWdp:xm2:9Tǩ,VX_*FR&bN Aj5?0U!~uO־Q%\__ݕ:\xzObj݆Wj]&)ͫB_RXqo2G!|^5J[]|GC Ǒ fý7H Q;qk*TLIENDB`perfbook_html/img275.png0000644000175000017500000002172311672745774015334 0ustar paulmckpaulmckPNG  IHDRWG tRNSىH IDATx}NiW"[%4tiLۘ4WJ@ nsxh0UJmW@.ł%8aβpL\,m './>8`JZ%:Y=dY'Ku+ Eu9WZŽ l^,k'4|2tP Jb+ku܄A["E! [zKu)^(eV'{4 .^nk64 g,jGkw . XEΚ֔-mXi|ӻ#M7ٚ(-~St-Ab\/UY=ֶҤ_- _(ʂ;dN\wB+;]qF8@ZYjN^_kD^Z5rKV6I!T5@Jmj,67]aWE01"H %@דhG)JlUZ(5H{!UU&ܙ;›:g z=KWe..lX7^z@@]Vo?(MVS]ͽ-n m(ӽ`@fS/AZٍVGy{mBw/*&.}]h _3>7qV,^#MHiv "U w^}T&|1}-݊!+4F뤝E XCe"[PkWe}C,m+ *l`\8TR4ߎkEpiJ5 " a N}P OV˭jcAit3.Pڨk?vsilFC 7/`9/qVS@4@h{9-Dd jϛ\@^tfjW e%Zc@OU޴ZZ#͕mM[po肀TaK"R-V;ij S^ _s@Kz[Pjot?xfخ?4$uαӥ9-p>bˋʨdU"W|rA XŁ+/DJ7JRm5"`:p5AeDrvk4vT̵8<ȧ`4`ƖunN[f'wS:ͧOCtm\Ul[;>iK4 F y2@60['!xy:{Ynw>lՈpPmMG,G  ȿ*t*`C Z; ^XE]upPVCO Z}YV:V_[AXycHcӱUd wײ~%a<~Ad\%vIJ^@魕O@B:E)!!U/M%Р$-Poc{nJp\}{$۴1mr~CA֊Zjk/&ѵ4Ñv&,>h /x'@TX~Dbx\lV^05y gCbu NM m0]JG/UqrI[*UNQ^@.RDG'$ 2nz9ithw +mfyeVfթinXOzah Si.Ý%rT.։-ϔj1pqZξɏvVq689K9>`9mnfb)kM囖VfXv=} -0jװ_>,? 89H< JWS٥]q]ǫ}KW;\KO,6վH"bn]պHE1"Jze"s3b@6h F \3~e9^!TRS*NzU1#Av(nP8F#t"W8>WDF0۾wqS&}ev ƶ[`o3 Ko)EŶ[$e(HKH&0lG# ."zVњ7!?zX{M;,yqSAJݡy?ҳ-yTuJB@Coe@}Uw:q'ݶgׂؔWN1٧Rɞ $.MCK'@C7n: nt(g<(nuux#:XaRZG`Ԅܐ;\սu]e&}?*:}N ~$u]xA nJ!W 8͍d]( |)Z#;66鼹rr iX3 6M[0/ʳ1ކ VX\I$ә xACT^6[a+0֙@̉.$W ZvL1U߬<^4WKI[5D ˛B/ ǧ~zq@0h|o{68P@iu]Ɩ~l]-,k)Yh^ֶ ͻmmݴ,t̙kgUۀJ@DQ 7QO,럪^NUuǜ @qUN=aIQk`)".oV\n?E]oP1걛]À沟!}DH Fj׻A0B}vuY(yA!Z@3D17#.x> sGl"aS71g~Zhv*F/MW[PBRφ=I!-qQYs4KeRRqSnlP戯)R"Ek )ڇo !I 'bBz+(X %BpVWJ9='[e=J<Z;0RhM&X'+"0݃t =]#O{*nq,|{jNj>zXFU-"kbfp(IVx- KqS t^:,Ir͏**5nYPѨQF.!Q?3*~J SNkphG>xg>[_DΜsvdq>/%Gr(p gT(b ΔzܝsoEDj]wx?"id{ͪ]ϙ5L4:DqV7iz^F/Ӷ9\G{x3olaD0mnnh^.&iiϺWp}a5a^B#0`uwf5bp}4ռzYQPI[ުݟ(gW:S&g=pZ56P@3}ɊگZ¾%WbFlC1\RTOg45\ZzUyў|s˴p֪Zpͣ^7Y3?`QGķy3쳔'^95®~oVq ~Vu[Hl=_di\Pm)>:dk}tWQw}ÖSb-\Vj7r=ndYWk="wK,R:M)dn 9$nPĶ3oBϮgϝJlnbh?b7qG[[:؟]:g 2+\oѳC4:QyIn>XS)½ z,;y굖\7-M7[ 6HhŴPSt_[{t3o̶'acTv&}$<)J}yzկltޱtǗVc .͇<ͳj[5C<ɍy'\;Wg ϓoqZI*bia([7E] 7ړ\/`~-."FN 17ׇ/lxT6F>xj0uD1wE+'Y'KwKҲ^r5@l' }Xu9uHˇUNW]ԫ??0| Z~TA-lMSklu[X˯=k<#\nOCkj#rB%RWk.ԛR+ՂI,fgCR̨gts9kRG.+=xzև'ta|P5`pȜr2衯ɔile\uҚQ$aJ+Ix wQe6_4i~i6J^U;Ro$4P_gF-mT1zn{2(- j?ō25J{h}(bo->HĬ,m޳fTB, J`]74Ⱥf0//XpI?\r=Ŀ.8MըΑVK=UHR庀QؒZ[RaO}D%n1zfjd`9)_ysuvĿ΂Z,X>̹CԸ9`0qosZڱ6ַx^Iyv} v|%͸1ПVr=[6u+׌3#[,<8& :!EV ɖ;e_ ړ,Y7= " {' ,{@Vw,^}&_XWsue8l; e'R_1㻦B ?uB26"][{v|@""d m `T%Hlǫ#p=}EToǃiѹCC26#,YeP^%[,FiBze"/zŹ`"l/~ss4ZGdlF&.̧yIf}Y/v mMz܂}36k̖yl;,.n3#<)YM1n__coqU8YW6Z My&Mؿ z1W0>s=OUd'O~?,AEvq؟K\g!C)35A m.8`g_.v_3^$9'S"}yUp^d.qeDR>)N&N&R>n5.yڪfKj +Uu}+}8|:Ɉ7cًb[ɝ-|<<(aHx 6nCѵz/q3;ԡh>Pׅk핁+&/ ᮭ|<kZIxVDЯk:\t=9Sx` ,LczJ >>sUڸUMޖ,׎;XioN'C렌[dcKntKE;4w˨*ui.al ȕʋřu;6R+U{F]" 獺]?'&b/ZGqC%P5 .OP+17]_Hu:jqM9pˬ; : ]+Bx^,mՙVRuPEͿ:O 5+bYAZЎ[ﹶ e  v,]UD5]^eܒNZ; Pǭ8ٞ?iMA J[ ?,u%|C!UO,L ޔ4?vD};J{-RgDZo$铙FuA/ᚁ(m+T;:_7]JL,>|R7TN'A}dNJԊbS;[o2c{^g@ne^ͳXsl5緡3] +؞WUe*z6 !mK(bUu&" ^sC4ϒTSmÌiz} ;e囱 F;ys^35]],W X(/XiEWU_kojaܺ›c4Yj|D* g%Y]8RZ_DtފYG8eL%|":yŎ9FītkӴsb-#tBIvGub%pY \2ofܜds[?:xesk4>b\[anYl$j oxSWQ@VsƭOcxB\}2LWeԫYh^B0WUc~џŷDZiq8_ɬIDATk*ViNQk55c A_|+V̓|=?vYCg K#yJ})RՖxE*I^V$UmuWl}2IFo#S~-3%%D?Uјo C.7.4 IA64

C.7.4 IA64

IA64 offers a weak consistency model, so that in absence of explicit memory-barrier instructions, IA64 is within its rights to arbitrarily reorder memory references [Int02b]. IA64 has a memory-fence instruction named mf, but also has ``half-memory fence'' modifiers to loads, stores, and to some of its atomic instructions [Int02a]. The acq modifier prevents subsequent memory-reference instructions from being reordered before the acq, but permits prior memory-reference instructions to be reordered after the acq, as fancifully illustrated by Figure [*]. Similarly, the rel modifier prevents prior memory-reference instructions from being reordered after the rel, but allows subsequent memory-reference instructions to be reordered before the rel.

Figure: Half Memory Barrier
\resizebox{3in}{2in}{\includegraphics{cartoons/LD,ACQ}}

These half-memory fences are useful for critical sections, since it is safe to push operations into a critical section, but can be fatal to allow them to bleed out. However, as one of the only CPUs with this property, IA64 defines Linux's semantics of memory ordering associated with lock acquisition and release.

The IA64 mf instruction is used for the smp_rmb(), smp_mb(), and smp_wmb() primitives in the Linux kernel. Oh, and despite rumors to the contrary, the ``mf'' mnemonic really does stand for ``memory fence''.

Finally, IA64 offers a global total order for ``release'' operations, including the ``mf'' instruction. This provides the notion of transitivity, where if a given code fragment sees a given access as having happened, any later code fragment will also see that earlier access as having happened. Assuming, that is, that all the code fragments involved correctly use memory barriers.

Paul E. McKenney 2011-12-16
perfbook_html/img191.png0000644000175000017500000000516211672746122015314 0ustar paulmckpaulmckPNG  IHDR8b9PLTEb``MJK# hffmkkcaaXUV856KHHC@@wuv.*+n\tRNS@f IDATx]* \>W֗DUTb`I05do/*AqƲ>i@'%|u "lY(/g):#mt }ęo%B_OS2bcf+wx)׋s7Y7Gfz1B/osb=,`MT#˯oX+s;E= c\׌ಙoo:'{#@&9p!,?&s^c*cqȖ{VkY˺|t@:YZdHj*EFx%\gLC(z5-gP,dBQ$/_s { ,Ag)]F"#zk=F[|~?A~R.ȏJ2kypUվ=i=b4^Qp:wwܷc6ː.!TRD}= `̉G;݉`@^ؙO!LM~}0;gS0{ܝ =RG8IENDB`perfbook_html/node275.html0000644000175000017500000000461111672746162015652 0ustar paulmckpaulmck B.2.4 for_each_running_thread()

B.2.4 for_each_running_thread()

The for_each_running_thread() macro loops through only those threads that currently exist. It is the caller's responsibility to synchronize with thread creation and deletion if required.



Paul E. McKenney 2011-12-16
perfbook_html/node187.html0000644000175000017500000003246111672746162015660 0ustar paulmckpaulmck 14. Advanced Synchronization


14. Advanced Synchronization



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node234.html0000644000175000017500000001214711672746162015650 0ustar paulmckpaulmck 14.2.12.1.3 Ordering with Multiple Locks:

14.2.12.1.3 Ordering with Multiple Locks:

Code containing multiple locks still sees ordering constraints from those locks, but one must be careful to keep track of which lock is which. For example, consider the code shown in Table [*], which uses a pair of locks named ``M'' and ``Q''.


Table: Ordering With Multiple Locks
CPU 1 CPU 2
A = a; E = e;
LOCK M; LOCK Q;
B = b; F = f;
C = c; G = g;
UNLOCK M; UNLOCK Q;
D = d; H = h;


In this example, there are no guarantees as to what order the assignments to variables ``A'' through ``H'' will appear in, other than the constraints imposed by the locks themselves, as described in the previous section.

Quick Quiz 14.14: What are the constraints for Table [*]? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node195.html0000644000175000017500000000640311672746162015654 0ustar paulmckpaulmck 14.2.4.2 Single-Variable Memory Consistency

14.2.4.2 Single-Variable Memory Consistency

If a group of CPUs all do concurrent stores to a single variable, the series of values seen by all CPUs will be consistent with at least one global ordering. For example, in the series of accesses shown in Figure [*], CPU 1 sees the sequence {1,2}, CPU 2 sees the sequence {2}, CPU 3 sees the sequence {3,2}, and CPU 4 sees the sequence {4,2}. This is consistent with the global sequence {3,1,4,2}, but also with all five of the other sequence of these four numbers that end in ``2''.

Had the CPUs used atomic operations (such as the Linux kernel's atomic_inc_return() primitive) rather than simple stores of unique values, their observations would be guaranteed to determine a single globally consistent sequence of values.



Paul E. McKenney 2011-12-16
perfbook_html/node246.html0000644000175000017500000002456411672746162015661 0ustar paulmckpaulmck 15.2 Shaving the Mandelbrot Set


15.2 Shaving the Mandelbrot Set

The set of useful programs resembles the Mandelbrot set (shown in Figure [*]) in that it does not have a clear-cut smooth boundary -- if it did, the halting problem would be solvable. But we need APIs that real people can use, not ones that require a Ph.D. dissertation be completed for each and every potential use. So, we ``shave the Mandelbrot set'',15.1restricting the use of the API to an easily described subset of the full set of potential uses.

Figure: Mandelbrot Set (Courtesy of Wikipedia)
\resizebox{3in}{!}{\includegraphics{easy/Mandel_zoom_00_mandelbrot_set}}

Such shaving may seem counterproductive. After all, if an algorithm works, why shouldn't it be used?

To see why at least some shaving is absolutely necessary, consider a locking design that avoids deadlock, but in perhaps the worst possible way. This design uses a circular doubly linked list, which contains one element for each thread in the system along with a header element. When a new thread is spawned, the parent thread must insert a new element into this list, which requires some sort of synchronization.

One way to protect the list is to use a global lock. However, this might be a bottleneck if threads were being created and deleted frequently.15.2Another approach would be to use a hash table and to lock the individual hash buckets, but this can perform poorly when scanning the list in order.

A third approach is to lock the individual list elements, and to require the locks for both the predecessor and successor to be held during the insertion. Since both locks must be acquired, we need to decide which order to acquire them in. Two conventional approaches would be to acquire the locks in address order, or to acquire them in the order that they appear in the list, so that the header is always acquired first when it is one of the two elements being locked. However, both of these methods require special checks and branches.

The to-be-shaven solution is to unconditionally acquire the locks in list order. But what about deadlock?

Deadlock cannot occur.

To see this, number the elements in the list starting with zero for the header up to $N$ for the last element in the list (the one preceding the header, given that the list is circular). Similarly, number the threads from zero to $N-1$. If each thread attempts to lock some consecutive pair of elements, at least one of the threads is guaranteed to be able to acquire both locks.

Why?

Because there are not enough threads to reach all the way around the list. Suppose thread 0 acquires element 0's lock. To be blocked, some other thread must have already acquired element 1's lock, so let us assume that thread 1 has done so. Similarly, for thread 1 to be blocked, some other thread must have acquired element 2's lock, and so on, up through thread $N-1$, who acquires element $N-1$'s lock. For thread $N-1$ to be blocked, some other thread must have acquired element $N$'s lock. But there are no more threads, and so thread $N-1$ cannot be blocked. Therefore, deadlock cannot occur.

So why should we prohibit use of this delightful little algorithm?

The fact is that if you really want to use it, we cannot stop you. We can, however, recommend against such code being included in any project that we care about.

But, before you use this algorithm, please think through the following Quick Quiz.

Quick Quiz 15.1: Can a similar algorithm be used when deleting elements? End Quick Quiz

The fact is that this algorithm is extremely specialized (it only works on certain sized lists), and also quite fragile. Any bug that accidentally failed to add a node to the list could result in deadlock. In fact, simply adding the node a bit too late could result in deadlock.

In addition, the other algorithms described above are ``good and sufficient''. For example, simply acquiring the locks in address order is fairly simple and quick, while allowing the use of lists of any size. Just be careful of the special cases presented by empty lists and lists containing only one element!

Quick Quiz 15.2: Yetch! What ever possessed someone to come up with an algorithm that deserves to be shaved as much as this one does??? End Quick Quiz

In summary, we do not use algorithms simply because they happen to work. We instead restrict ourselves to algorithms that are useful enough to make it worthwhile learning about them. The more difficult and complex the algorithm, the more generally useful it must be in order for the pain of learning it and fixing its bugs to be worthwhile.

Quick Quiz 15.3: Give an exception to this rule. End Quick Quiz

Exceptions aside, we must continue to shave the software ``Mandelbrot set'' so that our programs remain maintainable, as shown in Figure [*].

Figure: Shaving the Mandelbrot Set
\resizebox{3in}{!}{\includegraphics{cartoons/ShavingTheMandelbrotSet}}

Paul E. McKenney 2011-12-16
perfbook_html/node264.html0000644000175000017500000000452611672746162015655 0ustar paulmckpaulmck 17.2 Shared-Memory Parallel Functional Programming


17.2 Shared-Memory Parallel Functional Programming



Paul E. McKenney 2011-12-16
perfbook_html/node411.html0000644000175000017500000000520011672746163015636 0ustar paulmckpaulmck D.4.2.2.6 rcu_mb_flag


D.4.2.2.6 rcu_mb_flag

The rcu_mb_flag per-CPU variable alerts the corresponding CPU that it must execute a memory barrier in order for the grace-period state machine to proceed, and also records that CPU's acknowledgment. Once a given CPU has executed its memory barrier, the memory operations of all prior RCU read-side critical will be visible to any code sequenced after the corresponding grace period.



Paul E. McKenney 2011-12-16
perfbook_html/img113.png0000644000175000017500000001011311672746006015277 0ustar paulmckpaulmckPNG  IHDRPtHPLTEgdeb``MJKPMM# hffmkkcaaXUV856KHHC@@wuv.*+ftRNS@fIDATx] R Un+65zfN>.# I(S֩nTd@*ݸ=ìZOF۔Xzđ|苣sFBJ)q' m l38^z¤ほTfP']fHOR<h=_ @lՃ]l 71Û1saYlP5Εzy` 1=Y=VtQzGhh%PLGO3-Ň)6X6A}*vUX?2jPkMBJS7e# ,N]uEXx{ UTZ"=Kj@*n.y#/ʕvy=YI _'%  IITu 2YiT.f'i8dRXsHE 7V`s>Kx:t+qoឌ,+oԞHժP*rƻWgShƁztXi33]:C ?:Cju$oIYlME=+\6َC[-xo Wj?ܙUf [^0PE;Ph@:6eP]`|ųU+^BzUkNZuh'IuCY[]B?c}@_H~!e nx/-2fC|` _vD*۬ _~AP?y?)$"zZUyuUy0dڸ=1.+Oɑ&f*a2$oƱ R+'Xq/KG7k1fzn/ O?=ǩ @[?Cb/c|fA-LȂz6X̹~U4D~HO)VՍTTwd垫ʄ$ƒ㉊jL&jcy[,qg+wgl~H2=_K-v=4-OcV85]`i jjR4~W?TY3%Pc[OTbD(5' (D!tu@>Ipט Hݔ%ctV'ST&jNm{] CiA3l/<,}U1 ˎ-^mGmGNEPxтA<Ń܌?ą)̉b<ω8b {%y֬ ݗp-iQSu'g{@wd f1!r7GR c$8ujIVbJeT[Xf K#%)^2d%7ŖQc >?qᬧ~rQRO>E^yzSC!2Q6l/j0X8$R&QoS!mԵ39 %Jv1qޘ=ֽ2 ~CM=-FqQ;*xss`\0@IW[_Й"E)0Q^K7W&G?( 䤫W GK=p!Od'W괯]Ve($ _S/`{oҏFNlO9MLsV'a"ac3OXV&*g rv*aӳud43+Ms"qyI%+yq T.v*ZFߝux7%u>!Mz .싕Yon"]#ڶվESh7# zOAԜtV"PsGţ!oΤzhwM3Ey_ٶ zO|Sr=B{#쟣2~Kgy]}_OŨ`qSD>/%嬢hY^'1adRZ>į[XtR8C_.'J47 '/a|$y3y?u0l>8Z,lIENDB`perfbook_html/img206.png0000644000175000017500000000026611672745773015324 0ustar paulmckpaulmckPNG  IHDR::PLTEMJK# b``mkkC@@.*+9մtRNS@fIIDATHc`>p`0*@el^ͣ6Hy.Tlu@;/hv^49:ݑIENDB`perfbook_html/node480.html0000644000175000017500000000410711672746164015652 0ustar paulmckpaulmck H.1 Authors

H.1 Authors



Paul E. McKenney 2011-12-16
perfbook_html/node357.html0000644000175000017500000000573411672746163015663 0ustar paulmckpaulmck D.2.7.8 Offline a CPU


D.2.7.8 Offline a CPU

CPU-offline events cause rcu_cpu_notify() to invoke rcu_offline_cpu(), which in turn invokes __rcu_offline_cpu() on both the rcu and the rcu_bh instances of the data structures. This function clears the outgoing CPU's bits so that future grace periods will not expect this CPU to announce quiescent states, and further invokes cpu_quiet() in order to announce the offline-induced extended quiescent state. This work is performed with the global ->onofflock held in order to prevent interference with concurrent grace-period initialization.

Quick Quiz D.16: But the other reason to hold ->onofflock is to prevent multiple concurrent online/offline operations, right? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/node146.html0000644000175000017500000001304111672746162015644 0ustar paulmckpaulmck 10.3.2.6 RCU is a Way of Providing Type-Safe Memory


10.3.2.6 RCU is a Way of Providing Type-Safe Memory

A number of lockless algorithms do not require that a given data element keep the same identity through a given RCU read-side critical section referencing it--but only if that data element retains the same type. In other words, these lockless algorithms can tolerate a given data element being freed and reallocated as the same type of structure while they are referencing it, but must prohibit a change in type. This guarantee, called ``type-safe memory'' in academic literature [GC96], is weaker than the existence guarantees in the previous section, and is therefore quite a bit harder to work with. Type-safe memory algorithms in the Linux kernel make use of slab caches, specially marking these caches with SLAB_DESTROY_BY_RCU so that RCU is used when returning a freed-up slab to system memory. This use of RCU guarantees that any in-use element of such a slab will remain in that slab, thus retaining its type, for the duration of any pre-existing RCU read-side critical sections.

Quick Quiz 10.20: But what if there is an arbitrarily long series of RCU read-side critical sections in multiple threads, so that at any point in time there is at least one thread in the system executing in an RCU read-side critical section? Wouldn't that prevent any data from a SLAB_DESTROY_BY_RCU slab ever being returned to the system, possibly resulting in OOM events? End Quick Quiz

These algorithms typically use a validation step that checks to make sure that the newly referenced data structure really is the one that was requested [LS86, Section 2.5]. These validation checks require that portions of the data structure remain untouched by the free-reallocate process. Such validation checks are usually very hard to get right, and can hide subtle and difficult bugs.

Therefore, although type-safety-based lockless algorithms can be extremely helpful in a very few difficult situations, you should instead use existence guarantees where possible. Simpler is after all almost always better!

Paul E. McKenney 2011-12-16
perfbook_html/img128.png0000644000175000017500000002344211672746151015317 0ustar paulmckpaulmckPNG  IHDR47ȁPLTE""DDff^^w<<3gggMMMw'''Uww3UU f33"33UUooMMwwU++||| tttZZZ@@@444fDffDD"D""uLtRNS@f IDATx} c8ֵea:FNB׃:' Mt?ćK d¾gg]{.@?3a7˗swKIkZ y+Xj~I| eٹ|?Ne{& vcUYpEP]zNj())Gd3ɇczd=9}y9B[5IZl;sm:)ZtR(N9{^T:YamYNJ~BḝW -]=fG/j3^+'ѺK Xה4Ӡ6;R:i븸]s\ۖgV#=$ok;ߖIq?KGƞDd=iW`5!Mƚ$QҞr ,k0e?ljXWg{&i:MYlK۾f]Y֚ 7gqZJpՇkt=~GS{S howIB|%nICj abYiAq:;)}0-Y7ˠdk7!;a$y^٢gZ7Yyv%Ou:\9-mm8U;-d3ʖtIB/HfwQeCQ_=x \Xse%RkDgIG7'se9rkGm᩵`j²P+6FNb|8 .k/յ.kj1ZFoQ2aِ^ 5*Kh4Y#ZF- [3*mFxhƷ/Z6栩}ҵLI{g$9k-M\cl98P3Qah8YfR|l)sv)Z7~~- ^kI͍9f ,[iA ꅰzG7 P.{7O/V ?C`_nC Om1;͚^nڭAjv{H\k}Ǐ[!&0 QH `1o酢e~x.w_4ГH6{1dMҧ {,]:y±Ua>u7bi!vu} ECiqQL %?KvWPJCY3M_\pV̖9WamOe-MJԄ5vBH|zN!YS fǗ$1Bw-&oō> lT/zTHC~ԹV4XV^( ]O5rIT JgBUWSu3Y~Hsvi]:4L2_ 6-y}Kg#kkj5ebQ\aF(VqǴ_')u?'&C"v1d>n0ẹŐGcd~H992)I/Mģޠ-TX}穄[61mͯ#MI t%>Ƒ#&\u oK|:W`RCZYEyOjY8ocr& ҥhA[:nګ&'e5ZؒD^N\[ t,Wd#${y=u7XF,A2R(pK{ h 7c퉽h{<:k#wǣEkp}Kκ#^ɾXw,c +Ŏ |g17v5%!|WC,+Bѐ`TEi珜ПY-lX5 ș,W@%LtS;:P:*뺳gTrv6Z5R;V-Hlqzns?*j$~:Sc?~ioښY@mHqzOi 2Bh5GCm~g4-0bT aKϸYKod 4`P;6A65)y;?YsjP L zCMr4>ˤatKɁCMKPvXNj%GwA m.Bsk&$}h[LCܗn$,DDcBp+bY-bO4*|eŇeQ?^UeU2On40kܕ4jCc@fK}@3I }u@>عuP뼭N|5rIقc/]ppL$Is??125#ښtԸPWPK]6ٌ|< jl5 Nq"=<һ#j6 /J|jl* 5,ZDͧ789eis@KEAݗ8LKmKǯhєld6^hF["lho' 6z;:x`J㼨8cKt}&ϞXyֵULh%L8>;?VkE mSS*.xjL]٪%RvtdjFW ;#N#QwYyjKA.ȅXGvwZLZAs (}ݵnQ|)rG7v̍GMMq}HD%zI=gSshc~YAdw1tϬ>>CePArjN\<PkZ.%wtru* `AT=j(Sbt:FY@-byZ/j0@h1Gӵvi/jPt/{2iQ&\I4Sm:bh 5+y1C36쀒8?7D ŽFPsZf0!5mX@@~hp4~}y)[bSĪjN;,a_d#B=,&p@[ߟ/st@ Ч2:[saDh /ΰXGwŪ j@Ijԇ䣷s!ZVz6XE#tD})kh]QP )54 y 4а#Q f}NHz5Q(@Ou&N 7e8i@ uB?_x|QWO$5͝,JH1US{j_oǷ7a"53@ NM0χ?Mkb5m0xZPjP ވԤ7,`"+ A;}[R1xX<oct\#tY.szIKyoZwTD+ &Dx1ǹ:FMC}Nhj(Nѩp;7~>9)n肤BV×^ *p{*001c̃O}ԀZ[蜺Cxumج?Y\DYԘn/Qƫk&Em7^v@Ej@휩鄁 51 ԀZ'ky&]T & _& Ժ̬^΍\\(,a;Ԭ?1(c[b5]vd4Csk z iy<zÍۗ׷aOD`xPjҤ_uN-e 8eG҉| u!.G哩m}̷ƾ}F_V9̮ jѷؿSs-< ҝ5SřE1ْrW'7)pɺj@MVV5i1OO1♧kjPnD5\uC_OZmIg oGA49j&c?GipL-II!E" tL?bڡa6 b6ġ ٢'mQ{MGFk,_a5IDi5m'1 9k^1,ɒLHL?ףYP1jqFnք~jT>AQb'_3趇N#i/01R00kP;OjxPc`Fh(RIqqB":YSXצ1/>Gsj,Ȑ~!.D 5B33Z+j}j|5v:59tAM'NxDjPrW'L,ȯ.PZ YOO<<60!1KŜ}ۿŪE7Gr Ԏh3XyhUm 9,5W4=!H)j|@ E Z(LV-s щk /W7&–G'db<6TjNEx[vLPjt|&\4_;|L8QN[RD 1]daI`ۥɐh^"bj߉MZ(L wAK!SXEL!/!inlMGz\ l˲ϑhNaaADqH*45 B[rzp;MM=F7ꕌ51D ~K$kxɠTH Po ]צ%HƘ )DSX/&-_&ok_ ]oe7A442>M Z)$  DDSp a._._Dssw8$$pf*k)q鰢HE*qӪ kZ"y-Qt% RA *$!5t2㡪qxC":C _;h;>Y4ceL û4n_#ɉ6OO)lJ [QqO3~Jڙ4&~C kZ-$Wza?%i5p"ђȽűG]8iK[1˪6OwσrPrhpt!V"\ `1ZՈcťSɆ8Zti&j|dsk4)B#hs],0 CcEnFmiIeN )93C4V&ꨊf =+k#sTm.6k+VM52R%ZGd^* $~^82sumZDKPM @4E{O3Ƈ0`__]ȭX( MnޯooWq4>1=$ŋvCZ<Z+i|MbhBh L&0 @3h T +ZQw @~ W-2>cJ,mwVAnW2 'wm|5GT,MvwpYYR.;K"iݣDh}\mIcsբI,w)#Yg2knxɊd+#vxu%ٵpY%wo|gʹ"S%9Ժ=8ħ[#VK7)ivI迓{d:#?6?h#.c.ekekKP7T\ ,bRD7Eh45ECȚ`9< ȦTۻ<Ѣ! ph&b0\ l6䇴)4|zt3& yE94ES&sa6LC.]1 ?XC3*9' dROX`4:cdHmK"ԮI$* @0w)DSmvސMqcZEI8f&cBjeӘ^E~Jg^'߈uL1vu: ޲K G;Ar^6A4m@4!@4h ډLORFDShM74֥f %t550Ifנ%.:؎+}ޭZoX}IU  \P:2G9{hw4#0+Zpo5eNˋoȫj&!eoe @~ @q jj[]d@LH50 !(eկt` 6EVEs($|"Xh0 7 D6t -6FNc,C!IZM]FC ȘjJ6‘5'L#F#| IXCTvDCLI vEK4$g D y2JO+(6O mӓ< j'Q0GhBv<'QtND x1=vi AES E8@SHQz;IDAT2 qA%I d T$h 0I @4h $}.YPFsG,YM-_9pp̦+%8=M8qeP"O$]K,xs(h}l7DqOba2tNѴD) Z}  hsK@]rwްuMc йf}M>&dS.ǛFWM`DS0w9xҫ!>%'_l;W-2cZC;aMKD[:ŢOwfouaSQ%]\V.⧍5BLh@4s/Zc ,z߰[vU KOxCqy7^OVXWZ^7 pp=J_jVpի7 pEzd|MOxC_~?1ۼJOچE3;aQӺm6"&7Lŕh .D4E0tjߏDxAh1?Fιh|tKm2ߖ$# _ix4]. hx3gAiQĴ$p36Q*Z1- Ikahm?Ӣh|4hhjmZ£I #)Ue}Hu@, `<Cs9z55Ჱ+֙ɒP`4.Hƥi+VD( 銕쀅% 3þ&YgbETSmϊa:vg.bLb._._.I?jrIENDB`perfbook_html/img138.png0000644000175000017500000001537211672745770015331 0ustar paulmckpaulmckPNG  IHDR:HPLTEb``^\\\ZZMJK# b`ahffmkkXUVJGH856C@@A>>wuv.*+rpp\tRNS@f`IDATx] n HQU8$hN,qDd5XVǽ gmɘb+@*ސj 7Bg S0cs/_bֵjLYkVתN(ԋdXsʛ {Up+V X3+. ʽ.[Yəvo gb|S%E,KկUSRʑy3Wՠ//KWolk5J8uBzyCŵbr?$vwjУ}eN8+jGIr6ڿJBk[K0zlna}Y\ gƄ-¡De04D{/:)f}0H=8Aw!s%hR{EE8wDXP H cM;V5Z* [qa-[Ku:Y^WU '%϶KE_$^IMs+@sF[΂( CvrYx +).8nr=M-_wι U V>/FQGV5έBPkŞj"8ݧk^ҋQg"I`aD4@E"%VmRGr&=} ;ډG`lr_9[ԑՇu^`(^DbjoMQ/1O*C{vq-(tڏٺְ$1JSًt?/CςI7J߱?f[)!*q#lWSAK*9Mچ^AD~4oW_'h^՜VXaKZWF?hJ Gދc<eTa ZC> J5`+pת۫uV{W<1c$Q#L\$J%Ď<&La|M|%uL`aϲ0' 3J18"Й+82(FWčMFO jF誨 BZr.2Irm xظJFPKF4z`Wa_x`N8$x*Ux{3$ɉ]q L*u:dyiQ9'k2C 4Um7yd{##I@cQPׂ•NG=|[n[Q?nT A6 0i&HaܹXc6p/H8݀tqN\d,:ˏX (q#/3 றzW;F.}D:HAH[$ZJ"ATt#H+_7<`J5b4HB ]$MwJ_ -E}V}=㟔P-e% IL^oI..eiKtF U[DRò iyܼ\d=Ms~D^aJO@c`"B w=×b2룜gG 'QV*%2F*CflUkxo+JG 'HRe7Xm]Xa$E[ H@pG`WUU%  rOJLT̅4?~>+m4^B9Na|yHx'nDK0$*W"=v | \x7 8z.ѐ6Rd_tǢQ"R;Umm)>5^x+Sji͕ʟi/?znCWlԪѣ$ÀaOXOw:FγKN&=`I"AjSlֈua 9B-剧fc8ilXӣ^% {\861RݽUB`GKU)M]y(5VIi\"m\X8vlkQTdu_};Q)hBQbN,pېA; ol>0#~24vJ;'#$[͏HLtbKWI])<^1i鎬bч:R瘏tGVtQOzX͜NwdNw Ƀ>6?Aƪذu>0|})WJg>-HzE>0h,kH6T v=^::f)UfTV%7,HN2㱢lƗz]|}AJ3=iio10FvY ;&bgǯFW`P&8\@ s~̞hI.0P2?B RK8ӗO '}IÉJS]h5jd}!h>ͮaf L=gJʌևfD2-cF%e:njP>UfdWYfe]cMcF64<Ĉ^ʏ,Du9ӈiDe{O,Ho$d>"@Œd/Q"5g 6.5V{ yI^#2xHw .fQ\!C/+[B*p=Ӷn"(3g\DŽuB܀C'ȡ80ŔvNm94C&'9.UUWUQj]K*/A\ ^G ch pl [h4ȍkCpS@I5lS ci1Լ}7nF@/əA%}i\& *$'aLPQj|AW'|Was)@iI+Do]/.bzZ,p/P}yJƄݑ Uj NK2Va68vf卫BَWaJl +W^9 O'EzZ6K'Ae7nwLjf6}ݵlqYGcwS+ O-llpfp:CBL8>^Q#H[^P 3TAFQ|XH-B^"okc@3d=BTI\#Tbh!#r/I\"8i1|(}{\кztQDCtQ*gӼlÄVo5N37b܏Sa{C.!K>D硪8T8O GhN%~-\pRZLS`mѡm|Z$H.fG/{G:܏ y/ڝ\tdNNCu kss> zFnOx$ @uD2 *M}Cݽ#*wx*]WixHT~=ݞ(B8PQG$2L7E%>>눳1cXZۏ!olq`qIX5-q!++)+* q]R1%FhGZa 8fix|4up]zyC^ɺ I/Ɣ>ENM׾ma6Dwi"T٤$-Ƣѽ\P/z(z8BZڇ|'l^ӴJ9~4ME}c历ŋmECw3ĄY(!,%:$7|yj*A/щe{}jB݌`5:$7|So\mf,uCp/@ V+$:BD%`.A-[pAaZ9e.;nQI"PIq]YBd_6 `u7VcHai]sl唌P']BhrDhIJ `U9dP']B ۮ⺳$%A ?09#I;CdIJ`c9p#I_D!azԛB~&x>A yNEQaaMp'MptJ0Nb& 8`Ώ\ Χ?s1j^w6 $ϼBFnlOp zG.5BY31jy^vtâgd5' f#*Ee1jw0v`oJKCL+3[!9rkBRfؠe4 ]}?gؠ%.WI&!I6H ]=yYz _GozlV2=L~XPyӄS) I$qj1qht Zgn=;,C٨( )Hdc,<Lyę%0R<{-QXg6pvd,$;LijgB{qst .;|GHHI7 RU+$Oc # 0Ct)yA CV(P0&:F KE!v#&|_ ^"z -N*i 1L!.|Sv o;Y!}e.T/]Vvm!F:"(!jQWQp! h?`{ ..ۜ?[R%n1e󇐞F_4C݌A.~v8n5 0ߋ !jBy||! -W>!(4")I{>!' 7FO ; . yOeI'Aݖ!kⰲ]~\׾bG~YXY*_}<r7?䵰2 C.4.3 Invalidate Queues and Memory Barriers


C.4.3 Invalidate Queues and Memory Barriers

Let us suppose that CPUs queue invalidation requests, but respond to them immediately. This approach minimizes the cache-invalidation latency seen by CPUs doing stores, but can defeat memory barriers, as seen in the following example.

Suppose the values of ``a'' and ``b'' are initially zero, that ``a'' is replicated read-only (MESI ``shared'' state), and that ``b'' is owned by CPU 0 (MESI ``exclusive'' or ``modified'' state). Then suppose that CPU 0 executes foo() while CPU 1 executes function bar() in the following code fragment:



  1 void foo(void)
  2 {
  3   a = 1;
  4   smp_mb();
  5   b = 1;
  6 }
  7
  8 void bar(void)
  9 {
 10   while (b == 0) continue;
 11   assert(a == 1);
 12 }


Then the sequence of operations might be as follows:

  1. CPU 0 executes a = 1. The corresponding cache line is read-only in CPU 0's cache, so CPU 0 places the new value of ``a'' in its store buffer and transmits an ``invalidate'' message in order to flush the corresponding cache line from CPU 1's cache.
  2. CPU 1 executes while (b == 0) continue, but the cache line containing ``b'' is not in its cache. It therefore transmits a ``read'' message.
  3. CPU 1 receives CPU 0's ``invalidate'' message, queues it, and immediately responds to it.
  4. CPU 0 receives the response from CPU 1, and is therefore free to proceed past the smp_mb() on line 4 above, moving the value of ``a'' from its store buffer to its cache line.
  5. CPU 0 executes b = 1. It already owns this cache line (in other words, the cache line is already in either the ``modified'' or the ``exclusive'' state), so it stores the new value of ``b'' in its cache line.
  6. CPU 0 receives the ``read'' message, and transmits the cache line containing the now-updated value of ``b'' to CPU 1, also marking the line as ``shared'' in its own cache.
  7. CPU 1 receives the cache line containing ``b'' and installs it in its cache.
  8. CPU 1 can now finish executing while (b == 0) continue, and since it finds that the value of ``b'' is 1, it proceeds to the next statement.
  9. CPU 1 executes the assert(a == 1), and, since the old value of ``a'' is still in CPU 1's cache, this assertion fails.
  10. Despite the assertion failure, CPU 1 processes the queued ``invalidate'' message, and (tardily) invalidates the cache line containing ``a'' from its own cache.

Quick Quiz C.7: In step 1 of the first scenario in Section [*], why is an ``invalidate'' sent instead of a ''read invalidate'' message? Doesn't CPU 0 need the values of the other variables that share this cache line with ``a''? End Quick Quiz

There is clearly not much point in accelerating invalidation responses if doing so causes memory barriers to effectively be ignored. However, the memory-barrier instructions can interact with the invalidate queue, so that when a given CPU executes a memory barrier, it marks all the entries currently in its invalidate queue, and forces any subsequent load to wait until all marked entries have been applied to the CPU's cache. Therefore, we can add a memory barrier to function bar as follows:



  1 void foo(void)
  2 {
  3   a = 1;
  4   smp_mb();
  5   b = 1;
  6 }
  7
  8 void bar(void)
  9 {
 10   while (b == 0) continue;
 11   smp_mb();
 12   assert(a == 1);
 13 }


Quick Quiz C.8: Say what??? Why do we need a memory barrier here, given that the CPU cannot possibly execute the assert() until after the while loop completes? End Quick Quiz

With this change, the sequence of operations might be as follows:

  1. CPU 0 executes a = 1. The corresponding cache line is read-only in CPU 0's cache, so CPU 0 places the new value of ``a'' in its store buffer and transmits an ``invalidate'' message in order to flush the corresponding cache line from CPU 1's cache.
  2. CPU 1 executes while (b == 0) continue, but the cache line containing ``b'' is not in its cache. It therefore transmits a ``read'' message.
  3. CPU 1 receives CPU 0's ``invalidate'' message, queues it, and immediately responds to it.
  4. CPU 0 receives the response from CPU 1, and is therefore free to proceed past the smp_mb() on line 4 above, moving the value of ``a'' from its store buffer to its cache line.
  5. CPU 0 executes b = 1. It already owns this cache line (in other words, the cache line is already in either the ``modified'' or the ``exclusive'' state), so it stores the new value of ``b'' in its cache line.
  6. CPU 0 receives the ``read'' message, and transmits the cache line containing the now-updated value of ``b'' to CPU 1, also marking the line as ``shared'' in its own cache.
  7. CPU 1 receives the cache line containing ``b'' and installs it in its cache.
  8. CPU 1 can now finish executing while (b == 0) continue, and since it finds that the value of ``b'' is 1, it proceeds to the next statement, which is now a memory barrier.
  9. CPU 1 must now stall until it processes all pre-existing messages in its invalidation queue.
  10. CPU 1 now processes the queued ``invalidate'' message, and invalidates the cache line containing ``a'' from its own cache.
  11. CPU 1 executes the assert(a == 1), and, since the cache line containing ``a'' is no longer in CPU 1's cache, it transmits a ``read'' message.
  12. CPU 0 responds to this ``read'' message with the cache line containing the new value of ``a''.
  13. CPU 1 receives this cache line, which contains a value of 1 for ``a'', so that the assertion does not trigger.

With much passing of MESI messages, the CPUs arrive at the correct answer. This section illustrates why CPU designers must be extremely careful with their cache-coherence optimizations.

Paul E. McKenney 2011-12-16
perfbook_html/img286.png0000644000175000017500000003551011672746117015325 0ustar paulmckpaulmckPNG  IHDRa,c\]PLTEb``\ZZTRRMJKPMM# b`ahffvstommmkkXUV856iffC@@:67wuv.*+[YZRtRNS@f IDATx *. W3s0FKU;mEDĢ0v%gO׼ ;Yſ@7wfwTLV&݆֒kQhp&_/~.D=-\ʖ&u=;ؤ?WGUy$+.½rF,teB{|P!~|wfaǐn,>7Q{pda2!J?庩 4X@tn7289T ٍbJHɀ_K+ @[nPS*Dgh``e2-5}Sk.j>n5p)fSg,a*ux*]<>* [nn(fn;sa@Ϭ) qw:3gxWMK}:I9?6’({}e3Lvh!ߔlrM4]!ǂԓيNFexOUkƼPV[n$=qR=D oz9̰݅ѰG&m&n%[)a_NNȳ?l*~a!YJRuaFUzv MĮoika|nYb?dwKD(~f~ʐU99s~A\w]c"U찮kGkxʚR!I_'v+uBGA5t""@˃b )M-쫦\j"M/VCQS:lWՖ|oy{NK(9ʷZ9Nܚ6d3~gzpy 0[m2i2eK &i s0v>kl*<1 ղ@;6v؏pF@`;'8QƳ+xBU륹 XJ7 bMc%R" 8VhOy40#]F/DTMAZ+F~-_Ī"2K=tR X#J1lXD莗ZH< ۶#X _nn2B'C8Ta-!k#Mal ę+O%g8SmBBNqfN?'?A^f2-Nˏ 8TYI|U`.IS ' ɂ{ݧ M%WDcx*lȊ"qhƳ6k;eeC#& PvWϮ+nAZ]\s3B>6ZV3p%<{2fA\yWrKrT&{TLЄu|C)vP Re=h\+IXWX|T|{ oѸbaLl d&5nO rٻ[R8fLI gY\hqYҢ-N!Z?<ށ;@ՙ &_~q 5Ϡm dKSv^ԍ3 /S*?G a85 #ޝ, ʡb,.e*_~#f]HTWq2᪲;cUV쟸؆ehRj2Zu6F2+KaJ9LbPdp =0EO@ӔP"&gҞoJjgaJP$%w17]QuaUcZ3.6Jt]%@ϼXNf1/\D~"~vdv"~Ovt8$j2y0(ѷO21A$ybŠ=ўX6=Wn5U|48wT Lû5|@^>-ujDT)xh3}~F|cN/n%oӔN $,)*ز|0@;Ӣr|N?qcS4=^Tc"W*6 pǞllI MֶNр7v_Em}K\s?!*,Xuctz,#nZ@k\]u f$wroAJ 2"*L4`h{?fA `b<@.U,&_ގ:<揯#YbtW|_Q; b޹ &/ $H< 2݂Ya*V_ ݪHͻٮn (P1VqRƕP%` W ~u_4aPH;HnWFm,iDVH?y\vL~jjé61ʁv\t:`"xRRFPAߍGAG7 bIu08>̱̱B1Pxd $@@$dM'nSM{|k@7xV ;YU 2{] YӰ%X#Aff 1`htKFUHq*3n+P8vQEu!Bcڎ0O*kD(%ߒ|V6^}cZg;{ ϑO(@X^r$NP.Խ DΦڄ4^t=F5ENvМʾ-\pn?ԚM+3UqR2w~$HGݪ1 -1~)0@_w~Ѯr[p|9kڨL`쐨x<$\hH0햫!qT+|ƽ^3mYV%3*WNljE0$m l e` Zź^{dMc1SgVM 8p[YBLRLV)pNӼҍJP=eX\Bm2G歅CܺſnXUhkj%d/eX|MgBc[eYAP|HfZҒJ27Vҏ8Nt XEr";9";K?2 ,ExpόHvˋ.@ 09XfRJwIB:^Z#&/8UąY8hVA%yllu@>bCp<S8;|z%^GD)"-FE?8_U|-Tl}mV]3d/i,6B$sތE.*Ť|Ͳ2,WwhphL[ե*'FB߱G%vtS~s{x-W<8;%k^7l%, {޸D!̖ߠ:w򺁬Qϴ,kvՁ1({ƿ"K9+j0C,Quc>:9F[hdvsϪ$H8K5T噷v^wk.Rs Q9|5Xw~+ot"l1깆}s-"]BTKyW 0 /._<0JMՆG npE;/u Mbj*(ՃFOSWlgWM,BcN0ot[ܪFJ.M맠ע%MQYX6A(cL\+ Gr.$J. "[<#TS~eUUOSyv 1 Y=UWsQcJL|` GY)3DBmyU>KMJbYԄ=KIo҃СKg@e"*^[Dk`a"i3LA硸gq?!xpQseZuJBm%ϫKZ?{:aX;6 f37Z` jgaB?qZ0PAj`.2E[FSa7Z`a Nx!   Ev he"u?mv+\X1z#Կ-A;7N㮃$b5L 3O* pĚr`0OhIKK:J`r(iye`nAXvkې L:Cъa} ^zȞĠ=e~@jQu1PZ䶓 F;Cé°xP N}ސɱaåqVȂt<8D^T v`V%x۝lWs `%܄í*p kUP^Yi  .`)QY,(AS^mP+' R Ns*\i%-g C Z+v%C 6fnESW|0zuP9學3M H[=;?NC|; 4..n=S83)C&QҨ7skaC@Bmt5L{o@` k1M{~t1}ʛ}7i@^F^$}"POL|A5 !SH0785MFv$EhfRُ2hIrKzr'kڹ㚇l|6f;HpE+l: Yje ]W{K_c?%?>t F?(K#*ٙe]s8&ɕ[7y$"?G"[.$*Iy=vDT $"H%D->cgbe쬕yg8jg$-&jm<g k|%f>fM!Yf1(A\hJXbv=҅2Xs׎Qn$+V!@|Cl4˘, >o]kg} LdL + )!{&4яʥ9vW٤Q[Zz~4~FMe֦7\(i(5cL(^)zXY[_e߆Y[H(݉U9qR<]BRO1sԾK&ֽtB;#bA;ï"]67c"nƌC}_L1Q +1 \EEY9>,wz .W E᭓mö:GͮI &deY={AfM[j˶$釼g MeW9IǦ육-4׸$yk?&mIɌ}s[Rl|ŵ IԱ-i!hhK{bVuSo":%L-CGrC1wEo_ss4>}P nBucmKZ,Cj 7jLX,@gi^Ch-\-R#pp2h0"*tvRL*|.tl:Y ?:.4P8tuT*aEL(Ln`3J _j[λT;A%$c}RJ[gxFpo`,u,ЬZ" uPec.mw RcDI|re Ih-˙FL"~-H}EږOy^v;%$H>%C~ڭ}Ra1Z<8q,ҶG!QSl2ȋH,İWۣ "R">f~Iq9`ADO`G,H3v Cgp~x V.ȋxU?|ȋxQ?|%:ˎ-p^?y/+vgjraDazG9マ\rjM*r@zyLA ($_ض|k2]!9'O}%Q*^=_vͫz,= uAJne`~=eOC;L?̆<0|$ol! ArMYK?b=C -LV|ePK~ /,4aZxciRϮc@d!O81X*c8ȧMItCP6xlZ1r#[P!Q_At7DZB.d krּ {M(}XqيMH ұlS Ƿ  eiy*g?l1l (}j߉rTfy*g?:HՁnyHGP$؀x.۝v2?y{y@99LInÄr<NrO!]BIP.[HtS̼z-@/ND gΛnJ"NVxUK☈PX6&tHNk.8-D.LԱ_f"OPçѐ Vw5ump1<*]- GQ::|zIDAT[#(tnO&twEtNԔf%bv :K.+r:B?3]xu7 $(&r+N4%l1 +SdApeId.=\y/|؊d,~ؔajB3JE}.yB309D*Ixj}yI؅v~TT ~ݾ\h&b {/ͅ 69:ne!y W;GEeOH}t3~c321 vM\7gxY_Z893޼Lnw;.ze-eh%\o>LlGAX*N益 *1TI+L `c5Itt*<4F$I|&? I 3IL@MVJL$-jx.Qup5^,G`L7L*0C !_+9Ҋ~.lДj0!$jrz#i{ έ@dS A: MG^K }_ёv T䍭um2UtOZ[ヸP;Mmߠ?fƗ,M=]N$'-+> QFȟa o@Uk cvw-$ܒz!X} JϢt4{!{aQ'48#_oҼѩL|1/19`L>چQ'08,2g&ruYKXZ$uI*^R&;9B&-BTDG!DGd)ߍM!4yBoǣz@L=Nlo|ꍀԟ3?x )UJO"2FYb%K?j¸$Ҧ WuZM֢A.gHF`-Rx Qu/j .r&) 4P-ADLD4g4pxu蛎y(4Ei\p^Aq1A; Ǹ$ZFiLsK;o "{Q7A `R1TQpp?`i{xL20l x?N9n8I疙!GڗGE?+=#ȢZ T䒬 g'$3t'kqYeB Qי\瓭|2ģOz;C J࢖[!y(ӵ)D[VjG糮 .5 +>˴3ON Sq5360̧C$Gf 7LjxQQ@vWub8;Á1,4?].aԵ8@Rbi_vBFPŮ2<qTBAzi*Խ/3=ß~"jLJ^s|x/}Ċ "s|E`qH6/wh y<~m"ۚE8y:~rJ<\Wj?x0gPcdj]ě4tY4P2mo':9Kz`1ym~;pXG+ޅ=f<;7:K(ކ nn+{r 8jlU8#B'E#bUpb~1Hs1w&,{{KVw#a4F6MRN,{K[ﲃ0>If+pB)*mY|Ү 1!W= Ek>,~-S֨*ɖQ !W&۫߂Ht=TfDsxrq庍ɭ} ̈gK>TH F H AIi"M.͍bqFbHb."($jtƳ:7.GRx[o˫3wUf}'b訚tfMRxۄQ,w ~k#/a_]D\D'w.xV'Qbcy%Va<؅7%]PtE,iK FD1<)yP޾Ct69{mq_̼9_c!Cd&xbsOvt\A2޾B#QȘ䝎^ǧqr GpN#K|0d,Fw75T;>.x6f9:ގ7$dh))wi$NI6񬪝LGemxlUۃxc"nkȩv2\fMZ+ox Ứ{ҎNХ`ɏ niߗI/MGcFM xE=SI43_-fEڧ:+f<diy=7t 1+lc=|84]XqvQ*)fC9 >T.V JeFڃ28fEzȭ{_)EuFv-cVR>Ŋ_O7@AG^N|nC^L|ƀC&t`]+\P!/' >?o.-/|z}.\qM#2~A8L\Fbyc #=~` ;^M'i2w>\3̖ΰwd{~,8ïMp7v| Q΃oHXV+ {ٌ'K\ dE}mbY4V@nK2(拎^혨׭:+FU'4mIfeȊ$4ŪhԉHSlHfe('H퐦(VB躻k-i %J)KEgY+`C;q<R9xBFAv#w3/^W>\îHs8gQ #1,"e; MELBY#oaf!1\HAtyܭ$)*ԼX*TAoaf! c od1tոmd^MCcS9`ތ}J%?0NM :vprQؤWxbfڙ~n8U#g$ sM?fT{v3؅e|i%o`Oʇ`RyҢkܗ+ %X<9 Y,cT\pf## |AQH[V1^0z%GCҼ?B2+PFq;f3HCGZ8!A۰)̓ /ꞻے80}s̿٠ˇl\Vf3ڞEuϺ'Rl`'(3=a猶g9avoڡI{i{mϱxT%mOFsR:Ps0Gj~~4?Ϭ~4?G 'h~ Kv3"iJ 4.3.4 Existing Parallel Software


4.3.4 Existing Parallel Software

Although multicore CPUs seem to have taken the computing industry by surprise, the fact remains that shared-memory parallel computer systems have been commercially available for more than a quarter century. This is more than enough time for significant parallel software to make its appearance, and it indeed has. Parallel operating systems are quite commonplace, as are parallel threading libraries, parallel relational database management systems, and parallel numerical software. Using existing parallel software goes a long ways towards solving any parallel-software crisis we might encounter.

Perhaps the most common example is the parallel relational database management system. It is not unusual for single-threaded programs, often written in high-level scripting languages, to access a central relational database concurrently. In the resulting highly parallel system, only the database need actually deal directly with parallelism. A very nice trick when it works!



Paul E. McKenney 2011-12-16
perfbook_html/node19.html0000644000175000017500000000727511672746161015576 0ustar paulmckpaulmck 3.4.5 Composite Capabilities


3.4.5 Composite Capabilities

Figure: Ordering of Parallel-Programming Tasks
\resizebox{3in}{!}{\includegraphics{intro/FourTaskOrder}}

Although these four capabilities are fundamental, good engineering practice uses composites of these capabilities. For example, the data-parallel approach first partitions the data so as to minimize the need for inter-partition communication, partitions the code accordingly, and finally maps data partitions and threads so as to maximize throughput while minimizing inter-thread communication, as shown in Figure [*]. The developer can then consider each partition separately, greatly reducing the size of the relevant state space, in turn increasing productivity. Of course, some problems are non-partitionable but on the other hand, clever transformations into forms permitting partitioning can greatly enhance both performance and scalability [Met99].



Paul E. McKenney 2011-12-16
perfbook_html/node364.html0000644000175000017500000001054611672746163015656 0ustar paulmckpaulmck D.3.1.1 Tracking Dyntick State


D.3.1.1 Tracking Dyntick State

The per-CPU rcu_dynticks structure tracks dynticks state using the following fields:

  • dynticks_nesting: This int counts the number of reasons that the corresponding CPU should be monitored for RCU read-side critical sections. If the CPU is in dynticks-idle mode, then this counts the irq nesting level, otherwise it is one greater than the irq nesting level.
  • dynticks: This int counter's value is even if the corresponding CPU is in dynticks-idle mode and there are no irq handlers currently running on that CPU, otherwise the counter's value is odd. In other words, if this counter's value is odd, then the corresponding CPU might be in an RCU read-side critical section.
  • dynticks_nmi: This int counter's value is odd if the corresponding CPU is in an NMI handler, but only if the NMI arrived while this CPU was in dyntick-idle mode with no irq handlers running. Otherwise, the counter's value will be even.

This state is shared between the rcu and rcu_bh implementations.

Paul E. McKenney 2011-12-16
perfbook_html/node482.html0000644000175000017500000001144511672746164015657 0ustar paulmckpaulmck H.3 Machine Owners

H.3 Machine Owners

A great debt of thanks goes to Martin Bligh, who originated the Advanced Build and Test (ABAT) system at IBM's Linux Technology Center, as well as to Andy Whitcroft, Dustin Kirkland, and many others who extended this system.

Many thanks go also to a great number of machine owners:

  • Andrew Theurer (Section [*], Section [*]).
  • Andy Whitcroft (Section [*]).
  • Anton Blanchard (Section [*]).
  • Chris McDermott (Section [*]).
  • Darrick Wong (Section [*]).
  • David "Shaggy" Kleikamp (Section [*]).
  • Jon M. Tollefson (Section [*]).
  • Jose R. Santos (Section [*]).
  • Nathan Lynch (Section [*]).
  • Nishanth Aravamudan (Section [*]).
  • Tim Pepper (Section [*]).



Paul E. McKenney 2011-12-16
perfbook_html/img124.png0000644000175000017500000000731711672746054015320 0ustar paulmckpaulmckPNG  IHDRlPJ߰2>rTI8aykq&KEt~;(W ޼(Df>Ql';ɡ_kpfWWJަVlxwL˨J@$#+}>}3ѬMH~Cy rm7؞68VmFM`[)QFV`íLdd;]p4ogtw쿅7.5x51voi{)Ҭز)|"Q |n9F{ڀyWQm'faa\H ^M))-rQ,VrЍCv^Im[K;Ûca iYOSmQ'y,R\5xEnI6GTIPe?T$ԞKǜcGPXG E9Q6*٣8j: wЧJ@Z{dzX߄Eg;%t4z@tb뗢GZ<ҧybumB {:7QA2RQX.X2ŖV->G؝AuY:DLqY"Q`dR* -1v҃ bdEf|Vɿ"8cBbbyCم =4yz./"WYrڬ$%VQMG P>4{A&[E5*b戴9WIln&7\$g "T0yCZ{n;R{|/ .v&6|ͭleϱcF"~P'm ML Ztdk3FFOUf8U:F9[IOHL$UK4x!XZ{4q 'iOl9/%8rKilCB>YVҾAz…Is3Us/=r7% /l`c6|Ð>\%=y;Y!LZD6|OXYm04r~2s^o洕EN te2 3@2PE9ѣO߄ԇNh<۲~8,SaQkYtFvI:OOyrK5FxED%! n'>mײSnI>IY$ q'6 >/ϙs7X)%,Y!J~ |#X\J@۹" {` ◌<KjYۜCCWgjy6 c-%Coq-FոOOsN-!'< MEg7_ G8+ Avq^4j?=7р`%Lx9BZ o%ٮgzU#FG?8CMW$  KW-Wd3N=:IHu11M=v= tf)qЦ81{`If[1#C&n-N:m&'N܇YS!n?O8q3]U;@W:- |[1w4nFr=%W$ĉ=k:쪿Җ/] ^bXr8q_޺rړOuzLĒ],bly -X:SS;˻x#+4,![[Vӱ gO3M0gOl rqM$:qx mC85?Kg"IBL/^5YC ܳFܛ+$= r|N~zHġ$yn.TgK}.dSW߂2ta sf Dzo"Jdh֭I6*VZ>T6/ I?etbDm7\bəuWJ8O`?ia|e Yd\K z핲8"( w]rsKWa8ͦj,wtw]ː9w]`劻[].1䓻8'l͗niBLvQ5miK3gf[;S#'Gznre6#iY8^A; J΀OZs^ys9AJr']T "3Ny]SZ̞;fs.tT>yJNWf# zAQ8iY?87M<j$zӲgǼ ɽj gQ1YT+,;e (rTu}|*Jl?%'O)T'|UHҢ/@/҆VĤIENDB`perfbook_html/node30.html0000644000175000017500000000715311672746161015562 0ustar paulmckpaulmck 4.1.5 Cache Misses


4.1.5 Cache Misses

Figure: CPU Meets a Cache Miss
\resizebox{3in}{!}{\includegraphics{cartoons/tollbooth}}

An additional multi-threading obstacle to CPU performance is the ``cache miss''. As noted earlier, modern CPUs sport large caches in order to reduce the performance penalty that would otherwise be incurred due to slow memory latencies. However, these caches are actually counter-productive for variables that are frequently shared among CPUs. This is because when a given CPU wishes to modify the variable, it is most likely the case that some other CPU has modified it recently. In this case, the variable will be in that other CPU's cache, but not in this CPU's cache, which will therefore incur an expensive cache miss (see Section [*] for more detail). Such cache misses form a major obstacle to CPU performance, as shown in Figure [*].



Paul E. McKenney 2011-12-16
perfbook_html/img17.png0000644000175000017500000021476511672745772015256 0ustar paulmckpaulmckPNG  IHDRZPLTEܷ80-뾾H`WT򢞘YQMܻ<50LECԶ'VNI{еɶ @83 5*(pie힚Ҿe_Z-&#ǻ) ѷûظG?<ڽ黹˷ʱ󌇂yuo3,'ϲD;4ռE=8QKGMGCƶͶ*#%1)'upm뚕{x޷;2-HB=7.)龼ystRNS@f IDATx住w}' &t7r.%ȊyGΈ;($y :Nzkr(f3^O'ҐJUa,#ayqІ(5Xfd2%}/@VfϞHwm[ufmЦo=}ҙ۽W轝 ^炘8عyE9_s$m\rl!1:3!z'e4vEl4g8Мq n[g9p?FC~¾'EiD }qޫqUUA@[^q]%>:uP|~;9CH.)O݉Bg+>bwq4q3I)ϟ_P"eN9'|Hm߮(>eT1v:'ZyN=bU9m2,QoVڙNůM]bЭ=zs4Q!S.2j/fn6+P\2/3?Z#҈梶be$/BH'7)E/=V*ڠB+N^l-uͲCΪĤ%ee#G"Y>gpy6U+h!>#?2FllQވH㧛2.ޖ?莗G;{Z56~?)isdI֞b{WVy-bu}_@걛i4.q V+~"?tE):N:ӿv]];E)]hcic~b- _aWxv)E($H,VNPogY @fTDf?ɰ_ (c}a7g ,181O1Lܹ~\nV1+^$[*rjRtƭx,CS;{ &6xrj"xO㈪;:7]jpEr}.;33Xh F3poe6{WkɧČ!FٞΚ՝܍Toi:6Eu7O 7MP0ОM/(h2+Hyf_IBV,m9V`$2,:yĜ)mRE7MYC}OՅ_ubv'+y6_Ɛ,HGzLy_G$M,j)b;pIzWT@SzG͕n+#ݳmvTFm`QC?|Gru+7ICq寡k"_s j0=RîQ\f? #|{q4˖yA0N#&30,Pb_"ŪJRwpuG;Ewt(KaZv*o<8;%AV)tdGcAʂDу (""݉V/T#3W8[ppP d#qB pԱ͙% r7bt5)ȥ\f_VըCX釗rj`xo`bg'XT~v)콡.' s[y+! ھ-fW',ɾ˄Dvq\Z4c]y#m1힇Vme,j_ftXOZ{enY38:g^cEN?= ||_zBE9P5ۑU̬54ά Z rE9^Yz}#R[N]\xjW!דDGS+IUGP$6)l,Ƒso><0In[/._ˤXmH|;C،7l *o׫LTGCL>^=yn[(FXPSo%D*AO /ˉφk_MMC;:들d A#^4[={9@+6LyzN\EAA/tSFdmρGLJ Ty+hK 7'jɁ iTžrnub,^3-?ikK)T?"f)o=/#`Vro%-]gU (v P>EPY$vwn9_-g8V ĐXL!xNRD 3Qŵ 2V*,!>r0y ]C6ꭦ:BMjQod|+e%+u.w tL`c#ɣ_(ͦ](~$tn#cEu؜43]«/La|ѫ8HQAqbrq]4PW/J V6ӊ 9؉hj^X3rCz ܽ^Nՙn5=9t/<6|ᱹ}\ ~]|;QY@٬`<9r5Ԏ{\﨨R3|}|;Rrja4no}<||;]@T{];{AHX]S~k1T#'֮Nj"}?Bۖs7KCwi1U4މ)b60^\fg Ȃϝ/j!S\eA_g"9hJKIljyvOYl+eg<w,ແ!x&]x+u|o.kŖrQAdG5\u5/zRU,&[_nzE&g胯{/_n Nzo4z%H\1!!gCv2znE#pK j16:+xWIi&:gϞo\}`̒r ap "~UAꚨ#db.OO͍Y5S041r It \6Tƽψh/lWD6!1lt{M R\2݂gxۨ>𜫀,Ax}բѭ~-4l ">z]=\di^4q',GХNF0 ^QMjCD<\gBbeDQ`PՖ~h^<~8xny|;/p¦W*}CmG^>c c Eg@$&/hڮChʹmiVУD5E" 7b$,%utǢDrSjaHN 7F^z]5p.|& ^d{muHXm]8~@@xp"F}FSr>pԣY~j*\E?|R*SDmiЩSU(:?#倿* H{{{cʳ{/!Ӱ\MQ4W0mT؃eiF TўL/yRP0i6[~QM EXO5єFQ_ړ{ IL]7gpN9lh)#4CJ!^\Ki.|fmY<22CfIe q9fPCB'`Bm'-~/HZޕe>cJYSbY+b͛ߐ,QaQRADO2:j1jyoW,ɤ&1'ґR #ꆺşƩ/KVK05$AQJLM #? p4Ez*(;N_XtMj5C 1f^ܷ0h- ˽?LV :vo!^z>) RL@W.Ihd'A2"?%yY_X6$d̊FS|$.8RK`R!lV"H!SokJ|_|9P#Lok;o"Em-]U?cZlv{{(}^"utك4g1J تP,[ۍD6Ӝ}qngM]zrd[B6 '`0֙QOKzvl^k \sOUE|OG}X=6R}mSn@EDVA+޺Q!";I`^pbLVm0~r:X&]dJN)l!Kaq!6&?_L&u#)tauIU@2jDѣ867:W#5.M%Oפ7:f4iϫ$>EZMc;ls+f<9]_$b> ;=Y RέOQ ^3 5xHz\-uLuN,O޻+fɿ90ۚ2*\a?ͯ]]. JBw۪O{22ؼt3$Ze)ڇ^VT:d`cվaϰjω Ⱥc~oK*nfj%']jDla_W[;'mC 6m.\RędP FZlᕇ턬game+*V Z㝇 l p"8r_Y7ݕtq!sknˠ5]\`%Q62ou8NM'wY[V蠦3#$ZŽٙ\)9w߭&5i7gvjM\ijz2: d:\1+^A~H&cCӞN=s_LaWmb(g|#n,tGw!ILG;ž[]s/_] fYtG0HN`VimL&1Nl:3~ynf]&]nIj\k:{D#9g:y9dݼ#wm# :ߜkN-*V<͂B@JЯ:oO"=&}~8;'y㸅yKlؽ v7e _ 8>gϞ)ȼE2Zi n3Eq+9ҙV3eҹ2؟pI'5=S7'-|9" Rv# 1ZE :՜) b+dZCUzq 5 rV\ⶰ3$,fۢ-x;݈}ĴduDnrr}moLޒDpFi:X7.DS{ aGSZyj7yN]߮ğ# ]V.UbU@آʮ5W_^}TvS?~ŝ#E.*(cWQGDEWY Dp|.m^! 1)9:mm*f;+۰}A'ݷL~L OX^* ڜ~:Qm,gK[v USo :xJ$ڵo >'89: ,꡷ ahyAjug<,g ,=w:ҬB^mR)9R5v:Y\~N\MȻa\{R5WJY]&)o`o؋:s vUaY>6e <ȶ4WL+h!\q#C IDAT4O7F8^,|*9\hElpp53h AGkN|Jn<zfyN/ (qkdwᖳ}BnAämہWYh^`Pt4Q)k*J]O|ꃵ jp3s2(* 2J- X$̀e,__/PmC)s*S\dшkӬfJfWds-; JuXc3*p[M6(r+肨ZYeF_" rl9wԝ>{EؠHgGJ ^p50W*ClѰޢ)b61 ɬ+g_˓7^8i ڹ Fn]_髚H%KAiRj(%Z7[,z̶}Nm$v-(^QbEf!RfJ,452C?8xuV Ԧ*bW!˗ +vmF9s5IfT9ESt3o= pNjFaJQ<ߩ6~2ׯ K7 zaV \%(0gd̜4T= vNNoI{x?F5LJW#Za^S;H+`@.n]y>> 뀔?OѬAPT7PMfWBwoåF"lCoj<-::_ ,Pͯ8c(%U\q8=0gSirl3(bSK{P6W }ew]p_G|6{ [~&sh|HnD7G\1XOnPh6TҿV!TmޖѮ[0},*{ܮ \ W.J:l U7< ;٪ V꼡/j@:,>1yid;l|fckXnktl۬fCKcCN_=}qng0dQgҾL;պ4&/jR[zfw`從8:wGx%GB,a ;׍Yn',Ès<ݬtEafnHum>K Mƃ<쓙 .CUH4aw|]orҭk8 L*|w&(k1X6+/4nL+D$"tpDĝT"-|[^b:b(JlVϲW0 vp --,F ע!_LGLԣN?հYb4^IreW*mk0w7Qvnr@QqquQ8qs:El񩂛RFowoS[oM#ͬ]04dRGC d9 !٢Q w'8C-U.\a$nC' 3)B:f0qTwe==wNu,$IfW֌Y\UfpFǯjmNr3+20I^Rkg(*˰6ۏ#F5UK{{ nWEM툼jvw Lutq"h0̄tOg;Odp BTәL7Fzr\M/wA5s]S)cG}/JQGov&K{c]ggEv2& wQTJC`W0NBKg*&5" ćHoP4\CtՉΩ~M\;U3x凿,v ȩy[L.= +B>g{[mz Iz۩AoGW%ۺouWnҹ5e5n&'2|CwoaTPyL+n>pj-KHsRx}>cdz v۹Hin7Fwpjapab:)j[Ǻn0ZB^</PtAeG,fS!BRJ) .l60 b\O!ugzF򛓫`;ҹ.T(Ň/|gf/gsJX27;G7+:HUpa K _λtUsZ=ST{i`kh \xooowiӡMrO$ 79b"~;!p ΅`Prjq){f*4L^xLOu=;ɹDv4WW⵴S-vWf캹w>>##qoG֐D II߾qӂ{+<ַM |~7KSwS>7x ѐϷQtԉQ/>'F+IJRtgutS`KϞ4U:0C@r4l7^vcP\&6F8ة$*WxÑ^&/F':Vy$&e;Ž8?o3yn|뙀|K7M:z \S-3lh93Q>pS $¢NLNjE/[}seީꉨG:~"p'G/:]2p?P96Ymm g zTQWςd"|4z+7Q{;J,>޿~j޹չ9$r?3U\;F#dw%O#tZ ERÇfHЎ Re ɝɞɷu/Ͻ;z>A7CۇWUR7}H rWt#WZ#TP] lg\NC],bbu$$G2[|Y ]zBe̒ܫRR}Cck*ߡp\MBa[ OWp#֛N4"HքVE5d-+%[g?y\ ̶ߙ9pಪ72peo'vzntTaqAeK%!Є 4od38fZ!ӟ6t>Þ?4z;Ã;BsUץu2nT*rK<]#B7م6xgizB=dpT(mP &L]蟺~!AVfr9$v#sfk{IFIcX b5~Z'X47\ FeNb÷E+eSc^-,&!kOLfwtk*UK[7J[-v^җ9=m|ҥN+Ѐs.@lV:Vu97. X4 ֔l_q\{i|ɕSMOI .j>_5]@⅝[*;Jc U Ls<`4W[#ྲLvCb$Ɩ%f+؝Ed@-LɁg&{έ,jTT:' 95&tW/W-NZ65ң@*}pJ`rw)L%M DEC=f0dF}bǘ,Rzb=}o=p䩁㫵~QS Շq;-oو.P8fj '.55+$Rv&Y$yԃDzð^ɅJeŃ]䦹ػM$nef`oZ" Tmܖo+,HVܐ1IbL|.h? S?-+/&1.h<uBLKHLuXU'UzLa%ϓ샟Ӂ3g&}"?mYC t1Mٛk?ܖ2;hN. ; 8 <=4C?u4#/TQr'#)8zd\}H7vT>Qu$@,rM(DCށιJn-i}UsVXɤ,zbA4#tKwƣ,eWמWI@%f[*<2LzϟO M'r,/@By.Zt5שM nw`yK"0RK\{bB@N}ɳvsꑩ#ߗe'~n1@BXpi P xA3)D䛪nf3-[·)FTc#-dl08ئ6Iѽߟ! |ӭxoC;7~Ů1dӢ1BnT2) CA7C"MRHDOfD,oonvny B^:ܣ+c•{OY1ă||6yRuBLHݰ,=q-ˠiU–$raWML5K' tb]AOVS Y:55躆c]#\^&=O] Hd8ҝN'b8,[4(zΰnpZnL4H6L Sp5,#Ɯ)W e# }/hy?=={>>#~s/*,<([fL/&%K-=3&MKd%PLKJ!AiAsk4׫28ᄆgmmϞ_ϟ?>%fj \i1m iqoyxyMLTDQ f1˜4u5ɑ$~-}jdSyx)ydH5ϡއ>gAthӥ39%S܂-|p6IAK\#ZM4>C6E#2w.@hhGjX?)yn_PD:P6 AdPmh ;ᚚ%*7bA IDAT jQDIIT̶FVBXu0:Qt5^aLCiЙ#g?U$puU*Q2+R"K H/>JB]ޡ1ô"- AƉi`h&1{:$υsSڋ_՜^xg0[UTaAG/6,ё)VS׸ccϧeaof #(CZ(\P0 XL7a=FEmo$zi \0Y ,+P  nXTe-?96^oq==/2+`X- 1cA rNj)*Ȳ4 Bz= ̽#}[7nɃ bFv>tK3~ƑI.ٺSܴ0_]9f(\03"Ymئu.FPKn d$KfHSgz9_GYSSYگrȁ{pm8Q?r㯓GBF2j^%ЄMڥ0z >0T q8A7cf `CXSH  BRB--+HO"3< f 4uqQ:r*X ϟk5IPfhok MN=ڣYҭɛt~ 6%6Ӄ۽d!=p < CǙby+ڕlWaA$C`h;M̩ //#?:=} j6WaRQzR˘J( QФxGFJJjaZ! j5:A DxA!辶pEH"vNG `O+Q0!€<踏5Z'*A=hfy8&2"%dF34Vsx9Zx39  S)M7L7tK0Gn`[6$ =" o(I%W#mYOPJQ)) C"qMQMdPQ![|.ro \rq3)GKѧ ^0|VAnVDr U ^i_UǻmN㠠Ȧg\uIڑoOd}S+R +F34 OPgy.mO&<<ФU5NuL%PU"_HIIne"ŋs1u ,Vهit`6KK+ƶQ"质/Kvn9v{aWaw Й~ DP eB}plǑR~JYIyf&͢<\4Vν(^B$QgPdgMlˣ ٺnAc |qΆᦺ'˜N3OF@+rPCmRK>nyLewь. Wf2>7ȹtt>Դ8RE]̳x/J<,ݪTE4mԔH2YH<&>62q.мqr}1ٱ¸g4TyǓIJ{eJd7r ߑL3ޣG_uMhL %3ѷ[K(ҫ"-*/|Xۧ8 sq\/ŽiӳB~Y٤J"/% o^X4Bҕ[#v'Y6^Rc4#Z@Qy 5'BӿlB=w% @5$DOFN@{O>&QAΓJIKU専#wV xjvvl3s֙c#ad-;ET\Ab.8͍?S%4@JeC֮GF+7ΧZIYCQcGjߞXݰfD(ڳhj{'U@uexU*_~3'<ރ";Ε>UrZq;Zv-J9Q͕rWmTrN@|JF))?MөrN%Xeʤ/~;EEJ,ZUXbt;*UPA_[^^zZRӳ*UIj3~OǷ 5zQ]'EOl}dj?Q;mg;š:Ono7mESa(/ TnUHjsew[jP)Pux+j}O`}tI$s?amj?ed@mU§omIalWQU\O1{Ӡ~`z^SRNZu}4jMڃhT̔Ō1Z6R )c9fm:h< ONRrmV< JI*/x\I2Q3+.lfO͔I%'#$ri>_AfAD<*Faq, 7ˍpwOmy,"C4-y$ޞ~=jPsĨ?L0a5C72׫ZԘD42RUE΅xZM %GQ9kHȱ5@R#UpL+IKPjR43!fH[V M*6󼫙 yxJ <H+yxڒXBr[~`;XUtl1ӌ\f/Sկ"pnnm̀-B?nv,EP HDf-ɓ-dz8Mwe)o#>u]P?w9dF;ew׽8Zpu0ۆ:Mj|z&] -IoW#% m"chGOn1y짱6bTUPnIQ 5]Ǘ&.c=TfX G<ۂnxep)ds{>`c72ydyիv0i]CE?٬^zu Vpl*7d$qXT43$I%@fHyjDs(QK:H*rw8: ٴby>~saڬ˴ټ 4LB͘fEIgٳ/n,8dFB)4tnxޓ5Eߵ2$IUfnul<ӑP,IrV=y!,DFMkGmI%R\8wJp!U-K}*?uDq_B psIVd R|ɛ}z$GIDIImw#bb $3f;N$MΝvN]Yfa}ϟu4݊Z{䳠+KMd$NEBT3ԒoqF EmXpr{iIRZ{f(/YxPϓif,KEb8K#COu.ϓiڮ!K >niDjz.iݗ@0nβFJ|N_ 奼dgftk @GQkxTd<#6B"=؛Hxlqs3sܥSo\VsfRȉPɣ Ir,skNu0!`hru+Ō+Rk+oٸw{O|GA󖧦ywG/4 uK x蠚34gX(eߵB+@u ow?ϳo^t?{v D *UP%x}˒a_4gD Ѣ(ZtZ 0`յM8 H >?O {bbkxd1??nW:iLSjL;l'?Kw. P-j -,f&›GSGh@Iy/ ݸ08\ۛfb{1Qg@Ξ73ȩR5M>RFH;IIEeYۭ^tϐRD6du Gp+;s_yF>΋-W>wcb}*[aݞwNc$-ں@5+?-D 2"Y.!` Ԅ)ݩs:O[]Y~"~|?^htjbWU|s?@eIr? oKE n<:"N,\̈wEb\wcMl>7u㑾 bC)_ lߞZ^ȍxMJh`eYxNUՊQdMo{nx\woOcn;vin>ʹLr@lƼ}|N(E(T͢貚DizOT]]hBM3!p92:gݗk}I`;u]|nGǮ x1VڞhUL8nGcd=b™:$͇x`M?}ԹTTxp33'cHphcmu{ CU`z~'VԔPH1) )Rqr '2qe dD ,#bގ3h471siKQW7Ft)[wCmhflTgG٘wuv6!HdZNaۏa N1C7 E.݌ 'ۮ rKŸ\Z\q3hmc?i4K* pޥhyܒ(0LLEK78"'ZVyq ϗލ=;y*% IDAT/FNIiJKw9c7%{LX/IdNIЇ+xD3Sh Jy7,xg'sݗw?G>7 z@r.b>tW-oqmO7zV%EQʍpeRe¼yv$2q?a^k#wmEcZEK&xV}r5A\j6w壢 .{Z^E9 5g˴" ]H FteՌb)xvϹ-sxwWvȶ.־9n)e4 w=G1Wdv`yA͠a:(Yh5h&C,γ.<+)1]6lŎaba~?|=0}ܣ1鬚OdYI\p+@B T4A H-BC'"p(]rk(r;ֲH5YB^^ Nnx_h+/.5:8Ÿtr推-$e9{j"q.l Dv1Mu`~е!| dq;jmpar@׆˼)e\A=wt%D(u+ݬS.ˎĢeѴRiNe7g‘͂NLaƶi2̃KݝtvaAe}9{Nhm)-r0{> nh}V Z{qj1e*ڏ:93ܭ~iQY;\%R_ۇh G.[k_yIKE,gD(@-te  Y*t1.ʬ{U4g5{]@]s;Q>slǿ]r:Fۢ+Js,Ni :—|^4l54fD,j'jF8-0n)Qb`ǀ`ѪnS`¦;Ud܊:}dOsXnV .Z̾ L6ے$K3.َvS MBsi4b yزM2g&3Ҡ,1ԜLz;f/w #Èkϼyb שTZ0S+VDݎL-c}ۈF0 4%]!W),4 _P5[k~`&iH@ HmPCҢ8Z*$'49lvB2 9NIGPiLIaមˍ .v_uCI*O` !@[lQD"c RhDef I?K}5Y3if-o5L,G E_a:}|քCЕ"W6X Eo(8 AHUZC:EP{5Us:55"3]0 YqtP$i4xU2dH͂@I7&L@;2Y9&(mLApݏiO.s~!}Οt]B)}? Jx KeCVvzPr4fY4WOq PEhu 6Ų+pů (x=rK#q4n̈ Pmuźpx1>HѲ[D!'ȷVCTv=M(| !`EGe [jĖw%"EVEYG` Mg2pÏBWp/Ѹ='ooXV0o*Ȣ^뼴չ{-KdR ڢh0\+hKKHeMEÑ,@0MS f9(~D?Akw=I4..ƇŰw Ş*6L"c(Wb5kK&2%s*BYsBD. q<`'0Y MT&/oI:x}LH\Ag1kY(bt7ۍ'X^d@h{(-ӮBDʕDE+~&cKXbzh66 SyX/&C %u?tYkEdέ'^0DvUl$ā*aj$C\ Ybh=5NQ1 .!`*Z~q'{'}MơCh*xW )?X$Pw>ǃEӦ)+#zqe0bG0^#2W7*aEL'"3{/^ɓ%dkRH$&Z>X.WTP!:?wN ֎c. h Em;/rۦ9Kv ⋞F?u7]߆K=6l߬}tU`EYul _/`Q Q $e| Gj;WQj/]ð,_!V,&_xcq1zpAXA%Jc*j xY~cǮ^ɱ\/d(F!GQ@d CB y^ 2-y+.vsR.i!ᑸmwwql7 r:TqרrkY Qg{ls%[bn­:RMF\J* f؀гd^ d'౫Sm /6-CC'ĂA3kcEjrLs^e'3iL hvkJ 82ʓqcNz'9nXiԍLmOprpҳbh}{ft4֤n6*_}E{>cH*Nj( #Ij㪓-.YY'^o3h 6]Yv@L<O\g޵K `fX*QK6MwЗW Fhtn07]xqJ 0쟼^k԰LHˑ-4Lx`a`e|V'yբVVS[yRUae(DdP h =dZ?]˃DLsg Q}bQo!>-JܶjΖrNX@!~d [ KVRf4q4ӳE7k;վ?;U|X;\8wD=)kD,iwɡet[ˉ/T=jF"@ m2/,jρNq},<ҟe|^Lx ]osogS{Q*92 SKJU6ch|+iYOɀT&,(1w mO7 Ht*]/a{b[WcLՒAnרVU]"2h:MP.ų0XFL==b[:W?ݿc(9{uyc#33#ŋ]X[n@R2*B U:TDm~>Hj~$f$ki8HP+Ҷ"$'#r3s8n;9t a_2>^3\K7.F?ϊ Vg ݑ"&(* K8=z#=gD틯?\L$ [v3!* nl%VĂ `@G`P1SUӰpC3"UƯ@/8%a';{6Xl#6}B/9{f IE;y\'7]z oSzNE7eV[f@grѪ3{ ^YSGґzP`+_M$r5Vt/75:_u=up|^-x(&!G,Ui\G"87Sy*4yCElDn^!o  vvܼ ] s  ʣʲ6Ƒf ,~BA?ه'2}Ƹ؃;Z1k"d1ܸhOmba&6g큑37cn&`v/mrh W7X;^vʩޢEY5E"@CˀLrӭYZL{"㍍hM4pq1 1'h)u\5q᫖9jw%{!Y . ] K+"jʦ#=|/> Q[gb\q1[-XT+HFlf~H,bqΨ-9Iui4ǩPd:CΧAD8n+;vCg/N]kz3tZqCU;d'#"k",MBA2Ɋ!o| 01-G(j|׶nyLJ'h-/a nu5_SC]Gy`*$XX_!2PNvDA2K-}í=ޓ[N<ա*7w?-m҄fy௶o;_p% Z~&%2iC7V`i'XYt\!IA YE#o#EnΗy;}[Q赁lw7OB$(#ئ)"V!kw#s-$WdaidVN` "F;Al9hD疀s1wkk _ݍoe=3rT ÃŲUha B"#(T0e:ՃJz&X$a/nv־$7Q|:.xo0u?fqQת>ck󔇒fx~4M@@V Á_! v"TT$$[H^NxAu5]'{nMi!:*J rͦrc56 0hb`LAȄc0̏k-,QXG>hA0oܿϖw`-<>cG)i:^** ~`hSjQρvέk;\(h(,ƋnciBP@ : 6mgk>ж  [oG'F9=_ Y AcWK#"6yܴ^lPai!ZۣU#$hq`fbh1sQa_{ qϽ}5#?3f(FPtY4Fҕۼ* _+M^$A K)D`2"Y 4-bV`5/A͎?7ࣧ..r7TAA8& `-ڣc8@4zLÍ]c4dYc ;n"оM qY"v7\^n=4cnzhdcS0pp:vM#0QXPddUJkw޳ydi_`EeQZn *`w"VW7S7/>Ŏ0P+g IDATPW8;8}JVi:oX[kԑcVK@|E#^6~D@AcFIp!"Y3r%wu{qH-x͍LO 0t6(*|HN[_6r7FԻh JdF^ѐ&-Ŷ&0qU4la'}gv yqQߴd! gG⭰=h_7hlث2pu՟uXv S-DV=܈AZx՛"YbP{3"\':‹F_]2g6ÔEZE딂CVy&3(4{^ C3`_DG{N uk~AY ^+es"QMs}@g1\8t>'6Ca''5PY؄WH>#UM3*+%vY4ůfStP,!LaRTź__?^t)]7"7$#ox Ʋb;kVx[|E`G0E/ u rYQ@D6E0 ^ocqA`|Pu{"|` wn{g uEP;ܸo^"lh,GWURUgΰf'iO 8Zli&us\0brͯk l?ѯˬ&t@67 3F gwKE$7(oyϹ@*8lF)ߵĂN|%H]&m8ddU2D_SF 6АEPTU P~FYkh0"3{[vosӍB9ta֍7\WW={ \< +0j Ք@~P-IՒDWVAԻ4D e B)!⚆ K.)׍,\H {$ "X,:~+YPklb+_ƨFy`U1Ģ- "wAW&] :m k ޻b5 x:x;N/LAt󹛗l}lYlvUu^uMnkQ %J$PDc(';%EP1"%@ܢ&DyCPڄ߀ς(AS Z8{m4gs]{&h'ָc˱==fa5@P͇] mȌhIv݀|z?6$12)4C[ l ef21] >Vbs=R cMRM@Bb)(ھ'qC9KhݠP-#pEL~i/6tӚ^&7=*sa ~-q7O;uK@+ތZ`=zǀ Ө(#raϚУ4>qYI090 d3ut;ǁځثD2]DQQuFUqC]aPX1KAݢRRx8DQ " ]um"%ꠁ,Ii&}٥GkI}kql[eIT R̪msw}M<(fI(QSY9B;gh鲘06^U?\iAQeVbW>w XnP 'ٔWVZ2i%jV(TJUb1dz~ ef1 &n09ZܭFIcumTQrA~ {ŏ~l&>eowE.8D:1L@xS)d̸9D.(ȩ 'uuMyx"8RǕvi P=T.EVԢ/~:vJz<9FJ&__^</߳zd[ISHas IF%, \ӵ׎~t14Rg\cr M%iXV50[ix\'?yOx䞸 m Bm@i! cP@F- v;F7`4 ZS1q>9hj>k'Wy 5Qxfco=7zllg Zzϊ7v]K|˨ Ԡ15SdyƷMhݜYA†RHKݸJIIȿ-ՓՃX+-O7I(M x7^x˳FgcO<9& 9Id2IUe %קۃZ(gUD!GꄀK%biK].c` qoog+ZaNM9x'>^K&TQB*82imcvA 4 T*u$M;2ounؤ'n&} d"76;fof+ج xǾ>,E-[v43眻oWe!,#KVVe>/o)lIAvv5o}jv쭧ޚ<X> ' FiJ3vRhT%"r&XnmM-R l/ uydEt'OC"ler5fUzc{=Zfyʱ74;;nRe&L)yrD"UZfLJ ϡDGV'Mñi>Q+J \ʩ}V:+SSvR QuF&™Y#bSV9Q2m < EUMKC8P96V rT1SKjo+?QD;JTLQ oOikmQJTX^U!ZcS{J@j*ѫ#kl^{sBl+Sj&zl:ZKGWwE\+_=m7ym)yP$`֪Q*5ޖB<AMIUa%~P53ݜ gIU](7Sj"oDF'ޠDZJ.u'C#Y[]};'~ RgڝߢBxnڏq7ĤRVQr1P5W|NJQd-'uGm]9*~wSGUi8Y{kP҇8",JA0whm:em3ʬ>ڔTYf`?9h%9y\vH+.uuͧCK|*u;o<;4ޱrK_y*RHrn=f䞯[,GuǯkmEPiGU6(׵ť7A]n$֭~3휳{q>򵚋&Crs5<]Rk/\#~|Ϥӡ֭h$fI9y?Wuؾ 2KQ[2#iAIR\]uVmX+V$Ζ؋βUT}e$5R—v-[ƭP?z;ۓ.rl9ItÜ~+7<Q0n\[^jhNM4_l<0Z_?RշmlS\0:'5wLg}Gʡrڄ޵y*XRݓ͓?s} [Qf}ٻ2v^23$λS>n ޚ@uqϲW^܉ޫupsԹ9Z-=A^N6:Uns*:@ئ?xg$?~G|<-#i?- h PpWiP`SL;zpl1~{f]w<8v;U/y`F@eXQ7㵱k=p潙^rO8S QlV/uY=wÌ:C Ig3X=?DzEѥ|Rt/mMbyYElvHKI)y:(;-¡XZ)u|HbȚ$Mh"H,BV/YK&(|U=KcPR] {dU@ #@\ xpKˬU:/Ʋu鑌$D!j&:4F VL| a*L'G@?Pph u*.'C|Y4Z0_gf#: $AhAQ I}ڑ=d(ME_8zG9->_&ܻ #Σ{.{ f$Á2./ 1 E#bab$qm=~u79eyiCkk0 dbX-Bf}n->QdBy  >| n9aOvEDS #Q;ҙ߻O@/'|7D5Hƛϕ|uaݏ 읹]鿉۽e}l~gL19& 1℈i^$L$R$Df}}'juP؈{Ecz`]Y `6znQګǘ,31Fh@ar1a]T ډN 2A< snw=%Fl&µwܝ{r{C˖|^ qݤ%V 3,8 S`I-TU$QDƓɩ~il2 +P"PD F\HtĈ),G8km)Ҕf@zȵYUe)!B˂)&p_X2M S#cBTq 2AvA& r*HנU@j62l;ahU[ J[Hds }7OWswފVLZ"#pCi̘K)E$#FL$U"L#"P^*Y2-1s$iE/҆5d0wiwկ[[WZ+/U ݇P޼>YE0ZYH$fMOЀGb$ OH=@h=@)Ūȥ%X#S ):kcIQDEFIa*ǛJ;-A~i^ 3Jiމ5Һ7d;@keQ W7C&.$ $M $IS3A+p,xgwX%Z% P^41^Ŷٜq:]y\)W=nEo17%gA, )6E"%44 c!m0a2:tp@*+-x&]B".tr$F`l&k|ʏP"u)+e*~ګ;-8D,3 ;9I˼ %hv̠_ZHPR✕⳸ʒMRx|vc,`G#+d2uTRۨuL7*JQتbC IUMS$qyb D[h21IAtDwYMq,nDX0~_eu #d0q۷ R޾k}㸻4c+.+{m*>KtDЄW ܫe[*S$s/^@_?ݿnwftfBgU8.0ZH#0II_Ê#`XEfe .дD{"d-EK4fכ:>R~mwYQ@qiPoxpX$#(.1վ%fig e]$1 31 E N]=~i;**Mir\?nz+MdeH&Y}>+Vn3Pש`t/Ox~kIa$L1X/!EY7]g;x}bhKyfohf+Ouߦ[K8$ʙ VJ,FscGP ?PeMRs.7VW{;pknΰk:XIֶ>)1F&U0\/ [~{׮.o OM $ʵʤjBA|h-r3UKsr:ε]g}#⭮48Uh5VMٝ6^קLsu}Jcʸ#z1 iyH`D>!ˈfedJ &o#$H-w5X=0B>Q/^=uՓul:n Yu8ױ֫]]n{?hJX1hh,,㛩K7ku}5%/ 5uNYd|C4 #1S9Ȑ_tF D!d@vi_x*[__uwǎǶ7Wο8UP=s2xѵVw7`K$)Ys3ΝMMM^&fщRqd|Bac' v5WlL W!2`+mŧaVv딻ܶunnxc,wm7vA1VwU@7|FvjUy!ZgqpPᦦBőB325\F(*e5¤]ߑ(,8!+D  2Q]\1YyS՟?x'_^Z➽}nZev+q)& "|Ž{ I`$ y.Rx%PDղYF A4d>a붜:=Yפ?4~}&~ 7:;w^˙l5H[g_}0gr y4ʫylVRM J͚ɽzw!M 0≁#%;igSdOW=涽n|2[2Ňz㽽F/MĻOl]E[[ol2+>*r!W *uw1~oTaC`sfbNe 4 H>U]9l'k%Lql2u$@jaLֲ҉HՖceG8r-KKK뷜'^>v ޵Άcrn"r˿̚]:"~/@P%j$S*R+(潒ae| {$ɤ[j#pQ%b]ʘeN3)t%uO~lk[V)# tJ\3KuuG}K|~itbi棇ZZx~+seh4#YĪ"];K%C+vv4ͼPPPk^E6'ArØ4.MUV(\ĤM !D{ !Y6CQ2 6IMWMO;|Y `ߛǮpQrwx]HϕVɸnv"@ЖP &PnbsL_"& `fy!$-$v i"VS oo/a`ޖFe-]fAt8˃˛]'^;\?qj˖xCny'wm=q"ߜulwخ [~.-b.UefyXD\P?wvCmzZJto'qH,KR* "³A=fb'BxlB4c~ZS"]@MHHH3# +@;D>8/K\w[0`ۉmhTJ+Tm\[YTf\ip?9l Vkn{ |l%=˃ᐋLBB4Is!0 b*zp`鏈(D G E s_v^.It^4lƣ5O;()׮kmݿ9^ckuOخbqLgÖ δpl&s0fX+'d*rwj纟= $4]emF*c#`j&| a A5vS_1W I&%")] aDQ dRૌ&z][?ۻ^>v(?n>v]gXaoO:aӕQiHȭ${grCUiv~`?bxg2a49}w)K qMW.ZO&DSÞ;42$A ShFAwwm&A%Qhq:=iQX<=>19_Y12 DN]Mq}K|b\c>ӟlKϵƹefp[{rW >h~ Cȹ+j;g2LdqI,9ːbx@"" T+BE`hB4&}{րHtmb%)4I.\Ci$9;~bmo'G__yhit[N3ǃ! tp+aǽxi^Fnw_*y[URd zUgb֪(9+Q˃4 RLh 72mzD3nQFP!UH)PũeV"DiRt&&K2[0Cs-s]53vϴ}-`Cj }7N/_|Wꥄe95\d^?8fe(;!928V6^LB!J h RІ TXF鏅b11IЁ4mw նoXJ cG~m+{^ݶ+;C`5+ d'Xo^ iΆ`k.,=2ǷݥQ:8**Q槜Tz^ЮQ<&^oYyĞoD'i=q$eUKUU>Oɒ$&\  Q[qbl,72װ Mٔ8/;LleŇV?A-q_::аW:9Dtp)f6v蹳My%wDՊ˽z{A[- 9Q>%f}>68͝g!nTNUr,2OT΄C@j+/ -.l(&1PeCx!a8ZC`3528SS߽2kWN՟`plvu蜻ղĻq xDS{ YZ*,m{BU:%Bbs%06eY)ظ]#d-<|>ʥݹŽG8 sֺ.Lt:Ja#ؔ.DlFbϞZ9Y7?ZZZ:/̀j-띻.`BkNl _zbډ >,I2}-[/e~&7[yF7r+I "2yt,|buӱgE;@q &k5B%]gι+[~C+3OmJ6Tpe\/Q m͖Grػٶ37b}5dpgÒRYUX{rieA}7ςBoPXsцqo.6(9WnM1t-8X Oh`Xɤ517_!Zh=|쩏k?ABKaow׷}p vncQZ+Wp]֞SY*y8ў^Y,V<="z)tctTe2hZK $4F}B>q|JL$Hйxo㎴<}vaܕ7wyٓͼ{02X+-j'v TvExBG Zhо3a Kݣ钊w,~Ю %JH y:=;:<SX<*9m1 o Zm h8)DqNz3&~"% p1h_`cm othi\{r|{?zB܅lo~^h jxu~geڹxkRƽ4r"vU +1TN>m5ۀt?`r`Ӽk 82.?,p1Ӡ%T2c-Iة3L#79tݸao?,䏟w_߶Kv`j\tˠc; G٣Kv#TŕT(]{Ǖ-7FGun}ؖ2p%ziLGG+.0ը+4kzp 1h8aLc ى0>9ӝ>M;Mφ/Rp|S`,W󎀨Io02{s7&UaRNYUrA_ ^6]S,oZm,x;w ;x=J"< @ں04)DU vɾ$%锪` KkWJ箹@9b?z~yۏjڏmm Xme>qo96:<.0Q`T:PVqUښ*;F<ʵ&B,Z 5dl- KtUBr9KCm"!0Mh&C1U-_&ЃM/4a8=wn:B27F}3h+XƢC@[f d|ݗ'$+?~EsUbmQzysW[7vnUM^{-882^>óD(*Hh9 wa+v3sVT7 2KibKT&8ѵn' "dFU[1q͂>д4ɅG>m694u&7 %nոyZB_Yi L5N Õp9#9=k1k=titt=Tf5!kwA=|y>v5u)m5_YZ8@+d2Z lP]i)}t.3"¬X;;_ D%͓ ?<  l, t=DJU!(v:zI &̗V|p?=$]]IYF\`G3)ƨGd}>LC#Nx,w$QώũgypF>߾Mv_Kp'yc4#LGy#{j/s,EW\`mխT*K/.2bek^}I])kX̂Pr0dT`(AK:].ǧaCTrbƠ6RdRfՎt Wd4Nojk}a2V(cE_D'"fq?<$WD\GѓL<}|-BewyF>h\nav> ZN7QKll'֖zRl9g$`hk/Էa@1',vd*b|go:Er )D(W@)$ƕ˅o+ wO^]|/DL bHӡ"Z /;y}5'>Ũy?QLx+Y6wO4jJ#1ܹ<62Z 7W꠶B#G\VF]BUXa@&`D!EPq ~1J/FL6ahb\`xA$Z37禟NG?ݻwéT7:v4Utag_0xAvB;\9 )RGA&Yee0sp mEg IDATOQ ldug u Vv`N ORY;C]pDMb3}9B'2UkN9(n%>w? cL|<}8Reh0="C_>8=b gŌO.~zJծ=M7 JeE)sF_Yxcm>)<˖ȩal`g%p`Keǖ3|R&TO,o2d & "Bp;UK_<6Lz /;ǮxC~ua ԓCBdWZv[Vm3۵ @Z]=ͭkjd sRe!Ϣz`L 3eL`f;͵b#˞%"p,/)^+<`|B *WUI'yMWxI1Ø6cBW4|lg>/6 ?vʷbHL"-O:4͆3ߝXcY.9 㙍CmXWWOmnH[!{d('MS Q8s]brQgXE,HAKXXFӓpcBh=.~P7~>agpq%HUe$%J1?`YW{ϓ#-k?tJo?=gBhiU';f#wyNŐ=Z?zD1;9RUca2wҥQ!+y>ʙD؅2bv@{p+&aˠ 0KM^䤖T[30>`uNhM">de5/I $C챸C{sqoJutqex]w+b7?߱+V֓5o{I:؛,=e?޴FքZfl2 l1J)%llv穱A&pYKb.Jے ҍb?*XE'3 KՔ+\v'y5YNZKҞDJ\~R\v`XvO,ms`]mɎP9v*[yʋmWwJUкo_%Wfki4^/< $XK ,Z9QaCDpb +Ĕ"Պ1#$xD/Zg$OߔجT4^*p'{koR G݉r@Ʌ[3{fK{6]i^I=.]\aeUTKR֦Wm%ʤQNmW g8B>[:r<Vp:Y=fpkP 1n$j#3&$Oqlq E2 .\{eeDUqq'Wl榟bn{*[,h[,r˗>{ 5oyW>)8 QJ+eT/^ ;E/2z?\UDɭc|ۚv'36#A{KݜĢFA%㑶dm5PgsyT_)\Q op+L&\XEzr,hO}-'.&0񑗯k~ׅX;i`!c ?ּ5Ks6ںT+GO^j~f> >IK69 PwSlRK-}Ý>_-@[Eª{=Si",x 8YEW u;XdU/9w˶X0TF8\E7gʞX7piYxYEk؟k)sV>t{g Md*I]l?y@ĸt;ЯMNp NѮ, ~Nq;ejUc^]͹ʸ5s]ڝ@*`CL A(pj 3,څ(@ݠHAJ _ 1/Xw\bD9˂!_ ꗖCi_s嚒ZAc#!RT{zO47mSI;ȁX11g{ʒHjavD/70v $jFOOG v雛`[އjl9 <]vE 5,aby <>m`w}iՍUjuOPKpGl8%?qAS'[آL*`FE$Q=e`l? I11&F1W#Bl|YOVVԎ˂N Q+v; ژ x]ok9I{¾I- Wj;wyeg-uKuxjof6o} l`]l\J]و32f.C*+:Z 9aG)h3m3ÛĩvSc`yZC f[#Dh6Je?aAG]DRitph#@ûOT{лv4.2 TV ܛ znooSu`Vnt6t6|e=ANy/@PI LsΣ3v2R%doT d})9~rC+)<`I4  Y@t,cKfkTQ/7.Efpp#Y5LbU^Uۻ4ٕԒ gXZ{Mh{Pi$):5q-Ƕxr屿~zo}5~P6;mܠ_Z=bX!Ơ,T|BW[v!rcXw4lKq(PbŁnξzB JWWy6,hUbQڿLH-i&v/&Ӛ&vvQ mypkOG9u&߭9Dǻ M[pC=?okomc_޶#MK/ǧ7De3*`Í"A (~S TEP?룖{An4? d.s-\\t{ F@۵G97*MN XkAk=ZJVHĮ"50MW?fu׀#;?vt#XmGtm'BW 3լxnit4~j$lI.>{Ty].w,6uRrwڽoGs/t\W))V u\ #b=V&9ԩ2&E@p|4CxD F%>)ߪdVHEEGG~mSݭ~Ed8%D+/Ҷ{9w]]P<GhO;]rڐގ_8f9DtW1 w:Rx)TV8#Ȧ(}u*( `{du8% ˘=DalZ$Nj䙥k I";d [4QhIj5?ٻZҶ.+m6-Up 40C >FJ€H0jOwh4AzG/H h~Rqw{uk)5u3 Ҡ;ڀ ZN<>Q\[ ao8+xiN=*~iʲM4ļ|Fﮆz{zkm*`k74[uXnoa x3`8񛑊E:w# n_j S;5vI:zȞpJMnޞJ̡mOԬҶv=UqVx/=|lx`xWvS;O"rD!U"s뼻mvʣWɈN#{*)5@:6g;rt 1 ,#)yɔM۵GW:Q!uFX-v`65pff`(?,l&H+͛!2Vb"JxY`7]ƶ/~'#{ 4Ѣ0z[i]V讛?eK<8=S7 ?sv5ɪ/]]+ ^ʽI79V=Zˬb}.W|%\}TGxzpyD% [kD 4B+C r!h:кys'2 FrJԹ3Cp ̵=[|ww|pk:r8Ji8ZeUU1vQ !{A~x=$5jH$wԣiTBkMSW_=I ]̼pJ!^im?xienuwO|x9>ݽBiBgۍv4inXXޱ#ChL7ڵů>$4 G- HN4]$ &P3'J]ڨ 0}\ {Y+ >^1cj= LL}^ x{V%3~(bO38h6MC!?Uߛ ӆη?yx$-FZ)/:aY;Biހn Bй\eGu : BYp&B`Kxd2lO4q9qi&=6A' [ylis 19K8~hA"8Z<&jC۰hĢѳC}NZC@a=D>L}*]_]M:`om^m| je= vulpRokvwލzq~'U ϳy׾}l)%1a0>2̧P +?4c8(&ϩ_c}G?8`Xt0igY9JLmw7vM -<_?NJ#Mk h>غ2<3Ϩ)l$鬮P$&>;j+кKǾy$}LHr}b=;[ Yؖ2i&Y~!u@f ¦$9V՚yyǟ]UbӶoo%ZzkVζZB1cAZɲy J!j탄n^)I]󁄘~%]@v./ױ"  x >Ұ* ;̦ʭУg=P ?\g~- ;;={,v5kyW'O[;Q5tM9; f%e&+IxP5Vx`ͼ$є\PfK4 >cL1!ZΔ[4l>&eū@gӝHWoV/[:Zޣg9KKC5'DI[Rsfm PQt{{G$Bh҇qh] IDATմ?Ƚ|lVuc4v=_.hD1h.9 v@b}lG[)aJ*al9g %UUdppZ?2~ t͕mWoZ:424֭uGڌPbDQ<1yemw8P6)phtJ%egsZeo2QS/S^;@sծv}ݳ4}q6+_ČJ@,˱XZ-+)S2[Ā?}ӁM)x q?cf%xWkQ?11߽Rqʼn#gfNmjXleK֏ [[뺃VXgqӵ=]IƋm^l$Yp`qT6@BnK6=0CT2$R(p@**VKpXSxTlxbc`&I~D0tmzζ;C0g!{9>1;s-u/o>XW7?\33hfxφW5m] t\ L B}5Icݲb ѹV}N;fLl2ITN p~`(ɇس8qm;'SKM*V[zsʻntF~7WVƹ%[KEIQ)FvY, .d-ϭ,%IK..HY=m:2hd[Τ=VK0oLt ]Zpd}f$7]<V4sY }p&o6wD7>ý|?S!?ܤxt2j \ΤD뗥93Fkz^%BDzV?5Mev&-[6caZ~z9j%dG cEuS2X©Ru%o3EhpBa㛗6 s]HEJ%LD|߱:[Z* Y:R*1e *`%S:#]7s=}>+XgOC\nf$lC:d~a_k ͨPըjNQ5p:P+yU1K,ءKglbf]^M|u\#lp@y)(5!NS:gƞRm2^%V*~0[Z;* `MŞ~tt5|SR>bAڜM7ҩr]2޹enE=[ڰsFu۴$@!3謩Tl.^P=˲_0k{nȦ6+S?K^l-}p 8ؙ~bTy+@ռ%ao*J% )nKo=͌@%%gyڒA7~d!ĬUڵ_iCNr/e,s1A a縮E;휩⛇l}{~v񏵟a ߝѓC:U)U%; (6E0b_S_{] #K׉73@Z_=9w3.ϯ &NյNSZphhm (]fuoI}{mdԨ;Bd_S}}+LUh(NUFQuIVJ2`SbhAݞOD=&HKU{r[õ[*s?>fk" &Agq8 Nr< W'DUywpN_Ǯc:P3l'Ma|KOXivޏw2B ?'Rۏ8O)raS2S3 ^܍]Kq`Â2 ѡׂӴՖd9]I8}%Kl0 b!;l!yCsrv w6=A+ty'2{d叞n&siZ-@ܠU @j}ggn8W|gzTR:TqJdK;D"o. È}v6y"껬Z;T^VUAX&k+OO${meAdiJn l\l+`_ǵi.>{&:{઎]'N9z߯EփO}}#,rCεVz,qͮ{??FkWF؋BBƶ-G%6OMS9h, Uk "xYS _OmEִu)mQg$1QQEe}.8T'h _{D@'褩ml%~_VXǺ`s_sG{c.OP"gk5wgvvc;ߚrS~Е? OlE _,[|:`4>~pi.9} HN;U*pr¯mn]SYH@&Y]q?nbVW{;a;-˾M@5`%֊ &0_u$̙qm[|hE5d67yoG @%͘L< ~MCge,NY1Ɠת1ּianR10aW$V!ؔ @ TUhFE%'(Z&hY01G|Xq[0[^_Xa>̝͑}reVuW^xUT#rX cxhr*4Ԕ Dc!MF,b@;>6Seȭ7NT.7fB U6Apr!oI˔Z W0.6XZLPeQ ڶ= dXzୄLK$ .z.xx%I:್i+)r_f0K WP*Mе!Zc:K2h+18 ,r8-M،jϦcr&zv.1BiVm#ʄM$/Zsv쒱4Ne*g*-Q#ՁR*HW=0GFq6}O?c@NzesC:rCxoM`FroFvf=%{ 4Y]@3DhQvυ "mygI?NĖAl {,eoa<"Z(=9TG>}72:q~V$~zdI|ȍ@?(I\c^ ;l8KJhd?5nukn0Tx1 (D˲:#:aYxF\褤[tjhrN`. suD&Ow@$A؂e$ñEI:oFYBS-5ǍavmŢn_#MXJB+CCGdg±X3A?a;;uwo:䚩JG:[0:1 qatnJ]cch 7I2!JxGqb0z˃w3̆f<}3F] +-6Gw="WSD#YPMg ٕe|%EHLۢ3lSh|ܺe~o|\E]%rOd~7ַiK8WxaJ'[6:5028M!Э~e='NlleYcl`;t]-XK; muOmů3z'`L\osp:3t8xs*\lY[y#uY#>P̤nsv9hFsn|`!2s!rn?(J_w ]/WFFinh,+U" 7FrH pK$7W޶-%Td$6mmEV-ZD:9vS) (͓ Uqr<ށ)/8pLBI6 Sdp}E ""pu*lpjFdS7eɺŲ游;;{n}3PD^(5ݯ^iQu#?]䗷\IO Nc W.s޼{r϶= ['%Q3LwtpN`WZ"BҒj.hOjeNDT1t06^`X3YGв EӊbHr>?ΠMXDycYuA*Ϡm:ڙ[/^<>R^yF;R#ަ [?r0-8uI޳_c  '_>‚8k5IUe qk&p״eX2ԗ\n$05 ΫITRu:6!nZC Dell0 h I&[f\AyLZ;;?f[60[\9~FTDWe_򎔇3r륎F +x=zGHѳM@[1AG=.SIEp5*b2jQ4j/r|Zr7>S6E)8{o :8\`bb/rYC (J"˒jhsX ,R lu:4&P3\nk,x8i(kiHSh#/*Mq>y~T½dG]R \@9~ooL9_ח" ~XL[" na/ W'gX XᏭK9ө|~GZn[yLu8Qs?q=}l8)Ee2-Ej#GmI"WtIl(=q`iʀN_؎̀&KZ>ћZ/Oa`65~Ay/ږ ŒDӧc \ڔF;BڗC}um^L[g@bAϨ]E[W8u'LѓP.;ƗX'?Id3V>A9sJD hed QMj_}4]nV*7^gZ;PVػb iHKqpSC3+u66lTqQ5M9Eڰd^תf'?_BۆV} 'BأmuEy >V-jbUyފ۶Of0ڨ[: G!Q-Zph>1%ԅsEߣXS\ 7u=]y녦Gцt-u5aToGoc*-R`ΤJ73䱓GQ͛$Jlт a}G-&hm9JdC c}f?3K g33E|kr."ȵQ?<>Z.aD'LL3SUmYU%2q Cw/ Ⱥ17ab,P8|r7;ף(q竱BV*åTԟɤ2R(Fgd}Y¨IXM-aFp?hO?YE@ס- ew @_1Ł$-lwe,2T_fOgCBfYm#{0`Z fi Ol18˖6h$09l阅4l$R^ U]_N)Ss_Kza5 088F n``PJ74t4@dϽ wh)P^@eBVZU&GmIDAT<8XǮqaZ`1/E/XAñJu,$ѨeY>)2@.OQք'a 8NfŁJE iʑ٢; nUwVz2U*lWa .(:H 3 ig@<ШmX>Xs&LQʘj9k(F( Ђlα c 8UYEHM@Rawwq"<:cY7fSd%/PV13gZ$ο265B&fMKXLl Ş붺us.;U *L=uBgoތr(G߽k]XSu*ttB/+ zKR+GI٭YcΙs|&f|OHB1k^@pJxtQ~k@h֬f.qa ޴Jw̹a)8 Ie"0 X*д?aZ:A2y^eD̔; qVm%)ڗ|<6vX muRR8nK"}gS/rP_\Ud?_Jlig]z싒m3nk (a]Cj Pە/kd ~H&@B8 ?VdĚn5nL{%QYeXf 3Lqism̥ڦ##N4.NdES"3vo?ҲgϺRc/0[ O~9R"o*͇ U up @i6/_iS77xuARm>%ufp:jĖX'Py-pKmd o3ue8oK \ۈ240(c'v!"K|lGi-]m l/Xap\;#1uG9 .hپ(O=ێ~⋷A;=V.歇*h254XW$H5W@E4ykuGUp-lqK@!vͺd?J&v86k. 󼆫DܢՆv}8`j- Q Yd0}mp9qfm]UpT9nX-6]brMTa>jW' 7`УˁZ(5+pC [W``4<Fb#Zg#1 $i g"8t~Vgp_}('Zc Nu2Iz ťtE<#>cqKb\n2I"8 E wf @u]wt9*-!b >*GL<+8+8'^*|"ENA8;; H:ZzF[yD)K,@G7vb2Ս?߇ Xb0TQ.cC+9) 5N,sZ N-y!4h -%O8u"8uve o(tQgA\^DMo\Q~(8Jo{ӥ̹KRߍlP\|Jbj_ =ȂihƁjZezrZfp)q.2״[m`ś'nfD&6wn9Vz’m~ kT':q4 7Y Q$*L͎ sgJlDic/Dcc98Dq5\ﯼ6Ǥ. oҎb|kaYPq&0}7h9>4 R+\,Z>qM:8yJ& O;(ʓn;!0a@UQQ0p'9 dpNtPeu񦣃`5nbQ*LߩFk;1=ܚY w"+5<~>ۢ\(4)nfr٥(Ƌ>p6830>+CBjZf XI;xVmTU24MiGͱ|>UdϞ;w0 8́'=&("6E; EFO 3@D3zûdwz;P*{p)v?zN܈wҔKhIٳ5WY]S=|߻\$m䃖MAum).2 fV Unp[(F\mpL/Z2 j``pA:`$pX7Sc!q-!g c5G%J41O&򫷯O7yJ,6pe]H"k}_GCtըO<)1R ܛo /Riڿer2ćSM0Eq_M3Ywݑ!%Xp<aÅ149T~>l$y:ۖ1S؄$<1MG ,e1xc4f&:&!79{-&):+-ͼү\="WlݻJ `/æ,Fy]?DǙRtTØh-2;- VZU \1-Gxp(p2݆;!wt4nlUS UZeHd&k>K6JLb2L(KXOagϑwFGw[-:[ġ#ޙU˼W* {O  j]{ܘ2:Zlj]CeS;_:B) qtCÁk@ݱ8rТZDZ̝~hqOw@mҥ|a  m'A(8ĤH1hăzX\FBǪh,dz*Q0X_K+ MV]5 < З& /Ne%|oʦʁ |c Tkˢ?Jy!27<\222ݩ7fxPt>w]6a$5hөJjHb8.SSMA$68nP嫔m0bn$UVk~92H%ܖ2ݧN0 oE0 dP"l<9X]OOwt砈-Ab9Jb|"]JyuZnfX|#̥ `,+ /7_sN|ׇ-uލ`.`C ծBpf̙T&%/{mST]1J2=L!'jG/wOn ̒D'0&kX9Yy8t 80ɋ"4{yA(cȎ7MNGmPOMxw_m=t#٘E.]P5m5PUWDlPj_ hKY C ?"Ieģ]N"DsՕ]EPpPK3)>x"[;a=@AxÚTh8.8ƶ9i СU}kt)P`18iKڛ:7A}:<_Q_Wou’MRHN/Ŏw6 /Z*p ͵@ ǦPW? UTM?. [esϺHZHGJzJ-^)mU/nq,c(.R RvvbXVtPn k 5~/Ky纊 UtQG~ Z_;j 1dCk.jz Z4hvf0Ds XȕWmR |՜47O :|kIENDB`perfbook_html/node273.html0000644000175000017500000000504311672746162015650 0ustar paulmckpaulmck B.2.2 smp_thread_id()

B.2.2 smp_thread_id()

Because the thread_id_t returned from create_thread() is system-dependent, the smp_thread_id() primitive returns a thread index corresponding to the thread making the request. This index is guaranteed to be less than the maximum number of threads that have been in existence since the program started, and is therefore useful for bitmasks, array indices, and the like.



Paul E. McKenney 2011-12-16
perfbook_html/img248.png0000644000175000017500000001672611672746005015327 0ustar paulmckpaulmckPNG  IHDRE:ـWPLTEb``^\\MJK# hffvstommmkkZWXXUVVST<9:856C@@A>>wuv.*+-**mjktRNS@f-IDATx]vCR{ή (*͌w(AD`B EzZTp`x{oP%=ւm?~ioR{hCMHe 'ku)r'9V(E S Qz0X5RŸ1x.оO=.hX/xT?>zuo9Yi݈ہ&nFdKZz.?E?3 ';j%p%Mͫ:ԡV%L)tf l9.;ng~=nG_ʄqzT g.iYE"X&*%f8|5wl%XJLd]qIJv  sRN,<-)x064/32 e," n+RFa MS=rb:KJc^5<)`lbFsuҜj>ZX@4X" =a^k`BG3=1PVzG`xu2Zelʿ9Ѭ$6u*@үժ >c5ͧ+pK;jL8 {#keOuz^9+e#J,^Narxp 6k<u,E0nw{aʫaE5 V?Z1:C qs?CE/Z.vppŦ;ӏ {HުQFXVrOA?T/&m$  ۨ1椙=Ӹ)`3v-+:QLm@Fi"%'a#x8^,-&)BⴑmEAgPifp(kMc  l$Y.K&˸ܺ".гteWcjU"2 AXX\V}eCn4QWO#n3U9"VH7j{}UjX j2XVn^GG;18s\}-M}}q#a}KjS?B9S0TBG K+nKLQU*К]+.q8 ܊4cm ;Ȱ-IX&jjr[y$_t-@4iaC_H 4̐q7۠zT<ҪĤUs,p&*[0 U* FzHK3RMԻوMqtȢc%Hb`+SwJiYzvdrܵ${fd_C3HSR Z/FWbcIQ)Q@XfK8έ͠E'"5·Lc`69,G_!W@xm04FiI;',q3c7LpD^BDbHTbjgp;aT1Fm`AܝHS.{*安AwjYdά6C vW-l B(cR0],lDg].23_jPɏ-*G:Qay렋&1Gݺú~bh">s-olCYgm`m;V׬q>:FH!_Jb,G xy^I.>5kFM/?ݚТ`5z OróhpUyyQe.2Uz\F#-uzFYmw,kA$ 1Plbѝf~6wQ >>*qh`M/n& oyRg*I~#sϡXL1n> -A*dǤв Oqsӂ jzu+ᗒ暹z(lbs dF?i't[ZT})f]m,B}ř@J/(:8WsvK?Ű>ǔr/7r*rkLuvd_iCA݀^ڕh+HQ61.5e$_e$MpJbLH3E$ےH#$ğM8RE٠јtsʣw\jawm3BN/y% Y)euɢxXS_߂p?GnӡxG !EKM X+M |}<xa.],ԢOm8 HM(H!IH| MD#' $M|}TuY?;Ϻ8X냆ѱvD"Q5j)S>Rt9Ί\bn:OxynF1LPx:j!&h8 'Ogwo#/; ft~fG sXiJݼ N C͆Lq\DwxU(BkBv@`ʸDl@Ш[LOM$_Ɯ<7Q8p=RcfN"9)E<L|mQwxDMN MVacK)h?D|(ThsZFAAw-"19͈M̻K{Y:NJ:oΜi)s*9{oDC"gt ?Ϣz81DchRK8cL?n^:4+8 yL>K4fvFQeD9|>F,= NÌkA덯x=%A ak[DI *EE9;§J+}*>8儝 HwLB5M%6&8ߴ2Ťdh.4K-(!Lݑa5 AWӇ씂lo΃aEq6{jL7`SlDI (I Z1*ݾjc!pѢd! u"o,8e|-l;8߁Ox1nOn 8c=֞bH ZN ,Y9_^!rO@)e#]C]gTЙ24>v7ogYFax&|46S9m>Ccżj zA}VFť޾cD} Nn~xEg.E#)k-FH!3&Lt7$yWȡY9-xyHj*Q7/-]꜏6s~(z$[_d 5DgEK1{b.D ^<#9V+T#bB+b4v$(d{žXd{N||)`:'`=E0o e-RAy{Mېa^?5|xŷBgd4/Ay M= R_W|3=fN26@5ӳF`$N^?& t6I_\//c9k,T%8gԓ _ZG׸y)C"ڸHmͳ{X@U|OsyƄqG64+ 5"*D~1RԹ9 g$z甊&6X]"i$W3sJEC}D`#@0hsZF M.) 9]ANi|B4ԃ븎̄2|onwaQLXZƊ[ 5|BӁ5"ы\"-#"t)rCK}BB~Ϟ,^yF$Ky6}48;"f4'7q/zɫ&v9Wm*xkʎgr1LߋV:TMHbԇ?.Rt&[JWVyHg袯hh+W TSwί.ċep)Par>+\[ooW4Y~}U5EԦ5y&Pvi`  $UДR*H JI״22Q^'9 #~nUq|;ߺt(>+XH(bD H5t˳Xdpx*Yg^RKg}Lܖˌ:yоn Me|VʧF+MX:kU~?Ko&GR~Q#3k\u;Ii4n1u}:CɎ:ۦ֢4h>HbY@WM:wW`/fF"8ԳL8gwß AUPh9*z>YG*w|A*_]Fv=v鲱 \lRF$rH g v 2z6!AoA’mL ]¹&%R{ʰݫY @lvp/G[K=+0 A~S2'6>|Brj!&pQ?x9Vr(Aq Zs_6_֦:RTUP۫h6шZnݿu!K=b*RqqQVoL,~UָHPv܋U^bvE.}LLE ԕYzQ6n#2OV JHYb_ms߅6LVtyse_C@PEJ}Ne~lfm`AEDslz$%e7% Al!2'oLv0 ^n#GZ}h18GȄl@US;0 ^nq^LΣeJN{B,Z[voobl؀h͆m ;ChiIH\@aq=tͮaz&ZLjN?@; ߐbUy02my/k 2ߋϟKj{D/O=ynxxHmUaS0"]n cQƁ8^nn,v7j03A;%[* eߢx zg'{F/Bx-*>Xq+xf_ o|"(?A~`/؋,`%B v{;Ne>l*Y#A*Ά&9:wc>vgd2v3O_M3Gqo0Nʌ7Bxɤ/r81}jnWǽk+` *9)3$^98=#'@=s_wa-#9Po {ed /qD{r$%=j<9 {.P"RF<9߀ x,|1h],pVP {e`hlX+u`mE`9 ~DaoUS)h9 Br|է0Vy 4ƛ@"7'42WTFܝ/v,Q's\N.ZR1v/^}r$?xX1qb78DMg/y(R*ENtYt9.b]x.+h2~'OhG^<8> _St6@EaXOT)981,%(VÏlkv&A 5.z?Wu0$-gn`n+xGpƃBY3Ȇ})1e @ $GVÏ+v+#l_zEȚIA>ف\xD_\"fƚD^>|XRUa{|Dr?#2%S(@fGQL҃= X4K6f&AB0?ҿ|>8JfϰT?"}$&*oy 17.1.1 I/O Operations


17.1.1 I/O Operations

One can execute I/O operations within a lock-based critical section, and, at least in principle, from within an RCU read-side critical section. What happens when you attempt to execute an I/O operation from within a transaction?

The underlying problem is that transactions may be rolled back, for example, due to conflicts. Roughly speaking, this requires that all operations within any given transaction be idempotent, so that executing the operation twice has the same effect as executing it once. Unfortunately, I/O is in general the prototypical non-idempotent operation, making it difficult to include general I/O operations in transactions.

Here are some options for handling of I/O within transactions:

  1. Restrict I/O within transactions to buffered I/O with in-memory buffers. These buffers may then be included in the transaction in the same way that any other memory location might be included. This seems to be the mechanism of choice, and it does work well in many common cases of situations such as stream I/O and mass-storage I/O. However, special handling is required in cases where multiple record-oriented output streams are merged onto a single file from multiple processes, as might be done using the ``a+'' option to fopen() or the O_APPEND flag to open(). In addition, as will be seen in the next section, common networking operations cannot be handled via buffering.
  2. Prohibit I/O within transactions, so that any attempt to execute an I/O operation aborts the enclosing transaction (and perhaps multiple nested transactions). This approach seems to be the conventional TM approach for unbuffered I/O, but requires that TM interoperate with other synchronization primitives that do tolerate I/O.
  3. Prohibit I/O within transactions, but enlist the compiler's aid in enforcing this prohibition.
  4. Permit only one special ``inevitable'' transaction [SMS08] to proceed at any given time, thus allowing inevitable transactions to contain I/O operations. This works in general, but severely limits the scalability and performance of I/O operations. Given that scalability and performance is a first-class goal of parallelism, this approach's generality seems a bit self-limiting. Worse yet, use of inevitability to tolerate I/O operations seems to prohibit use of manual transaction-abort operations.17.1
  5. Create new hardware and protocols such that I/O operations can be pulled into the transactional substrate. In the case of input operations, the hardware would need to correctly predict the result of the operation, and to abort the transaction if the prediction failed.

I/O operations are a well-known weakness of TM, and it is not clear that the problem of supporting I/O in transactions has a reasonable general solution, at least if ``reasonable'' is to include usable performance and scalability. Nevertheless, continued time and attention to this problem will likely produce additional progress.

Paul E. McKenney 2011-12-16
perfbook_html/img274.png0000644000175000017500000001377711672745764015344 0ustar paulmckpaulmckPNG  IHDRUzZPLTEqqqgggMMM---''' xxxtttlllhhh```^^^ZZZNNNLLLHHHBBB@@@444tRNS@fSIDATx](EZ8Όz7/Wb%xv+WQqPӫ:Q X2:/ր#iߓЌGj-s@Z kBu+rcۨT46AA$`'lF m6EƯR w-0P3ᴳ&5*`\Z6kq$E iSD+{in:^@8e?3ux}Y]$T0Ir꾐iuQ T-NǺV\(Pr-RJ A YAs{a݊F"Mw>o%{{c#IJ.6^Gip꓿*'8Ҕ ]>i LH|l ߧj}_~h=e+1MNzK!q(k.ØXv{jxI{ Nil EL=Lc;mYd`xnnы}|qyMJY{K56mkc9/Fe΂C>: N\W!5&7Qh/V +H\BK((վ!˚VACm ([8_Bҏ{=?.G #(~6 RGc(/kZl?rʱi:xEƼ4g=[9<7@ӿ۳.-Me/tMⰞ9UZV=5#Ov1VKkm!!27z2O+aHzLYӮ?mKw3VȐX>409[mM%+ zH,e5ّ)3RקZ7a{6QnJ"k](gb2{5ZZ10ɩF'0em` SL:gTm(L5?#.Ya)0@J/lR[e.4]ۗkQ7qVg Mu_jP>@'r_5|(MaM ,o:eYGVL5`0R髬Iø[cl)jY;7ٴ9 hsjж8Ru'*BX0y2ۖ|1R5qZMm{K+Rs~07]Oh~Ÿ164L(鞪kz,ևɝgxfAfΠUj赛u[An+р33H Y+ }EYKB}QVt^$;v9NgijV '2N3;Okc-6-*܇ VnbkܴsӊAgzrar6Z/߯T4Jsa Y+9k 6Gȯa.Yf@[~ 6̄Yq60462] ` ;\MU:RrJC~܆V!/. &L|{Bm[8UCdVW`DF*cM "[c'WGy[뀪K]U7R]@%a覰_6!cVl5}Ƙ hmy7M1@n@_кMVVܩ>ZiZ)@v1F]|AeL=6 }XӶV~E߽nk.96v^O>fpw .k2s_y;o0Y}`YNps|n/Dc@-L׸u"lY)^Z VeEmC#dgJCb7ؓw.Ȣ茱>!|MR܈G38pgMDkiDCUKVbZh o2x 㦐rB\4`Abı^la_C \J[ZŖ,yHu}XԹ]!J` SYvQȕ-f$eٻbfcD !K g,>Roryд7rXd7'u\,,,}3 O"I =C G8'g9Tv,owiIqr1M5ܤ½aD: L %UUr1M5F[ƳKP9" 1(1:/gQEeyTOJ'KȓRc(Y*9K g,zrn3HtW`ȏ ]RUI$R(כ0[ LCr)p uai .f> R$RnՕHRKZ@b-f1.x ںÕ/ZXn{?bvkk}|LCJP/z cUBHKk%G R QB6M؍k K~Xl=S⨝T&᧎ޫֻs\.=RRR~I4RRRR>Ro~[aT G)SNZ)@ 6+\,u"D[ d}qV4HUA K+J іJ*mRu!sQ*ѭ= c_hK=۽2Jb+a%黄]q.o w\Ydݏϴr^7BBw|S:7N39~7DG~qc^FY؜ͧӺ((1Z'|Ū8_e3pf@}+@voZ 3\OsLTڝ8 }W{UZt1:o5npz'c?C+U"s0բoݙCU1f8AR_7m?V-DkK`Up>3*fl KG埖ZJ/;}3B}t[}KDž >JWwōƠHYyڶm#e)kFSֶm)+OY6RUkG*',m)+OXR\ү,Y٪dlU 2*[JAvܪFhL̓UzH }qJ(4aƇe 'VLtqr΍N+J_ S9*3<$V&B sn9ds;fתq2cd1Pg= *=].&PCr1{Ĝ|PT[Udo*U?t9}V9EH̫gdYK{uFf&EϞâ"/yOgتdlU 2*[JAV cRU)xK@Sֶm)+OY6RVm6GiZIENDB`perfbook_html/node66.html0000644000175000017500000004005211672746162015567 0ustar paulmckpaulmck 6.4.1 Atomic Limit Counter Implementation


6.4.1 Atomic Limit Counter Implementation

Unfortunately, when causing a given thread to give up its count, it is necessary to atomically manipulate both that thread's counter and countermax variables. The usual way to do this is to combine these two variables into a single variable, for example, given a 32-bit variable, using the high-order 16 bits to represent counter and the low-order 16 bits to represent countermax.

Figure: Atomic Limit Counter Variables and Access Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t __thread counterandmax...
...< CM_BITS) \vert cm;
32 return ((int)cami);
33 }\end{verbatim}
}\end{figure}

The variables and access functions for a simple atomic limit counter are shown in Figure [*] (count_lim_atomic.c). The counter and countermax variables in earlier algorithms are combined into the single variable counterandmax shown on line 1, with counter in the upper half and countermax in the lower half. This variable is of type atomic_t, which has an underlying representation of int.

Lines 2-6 show the definitions for globalcountmax, globalcount, globalreserve, counterp, and gblcnt_mutex, all of which take on roles similar to their counterparts in Figure [*]. Line 7 defines CM_BITS, which gives the number of bits in each half of counterandmax, and line 8 defines MAX_COUNTERMAX, which gives the maximum value that may be held in either half of counterandmax.

Quick Quiz 6.29: In what way does line 7 of Figure [*] violate the C standard? End Quick Quiz

Lines 10-15 show the split_counterandmax_int() function, which, when given the underlying int from the atomic_t counterandmax variable. Line 13 isolates the most-significant half of this int, placing the result as specified by argument c, and line 14 isolates the least-significant half of this int, placing the result as specified by argument cm.

Lines 17-25 show the split_counterandmax() function, which picks up the underlying int from the specified variable on line 21, stores it as specified by the old argument on line 23, and then invokes split_counterandmax_int() to split it on line 24.

Quick Quiz 6.30: Given that there is only one counterandmax variable, why bother passing in a pointer to it on line 18 of Figure [*]? End Quick Quiz

Lines 27-33 show the merge_counterandmax() function, which can be thought of as the inverse of split_counterandmax(). Line 31 merges the counter and countermax values passed in c and cm, respectively, and returns the result.

Quick Quiz 6.31: Why does merge_counterandmax() in Figure [*] return an int rather than storing directly into an atomic_t? End Quick Quiz

Figure: Atomic Limit Counter Add and Subtract
\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
...61 spin_unlock(&gblcnt_mutex);
62 return 1;
63 }\end{verbatim}
}\end{figure}

Figure [*] shows the add_count(), sub_count(), and read_count() functions.

Lines 1-32 show add_count(), whose fastpath spans lines 8-15, with the remainder of the function being the slowpath. Lines 8-14 of the fastpath form a compare-and-swap (CAS) loop, with the atomic_cmpxchg() primitives on lines 13-14 performing the actual CAS. Line 9 splits the current thread's counterandmax variable into its counter (in c) and countermax (in cm) components, while placing the underlying int into old. Line 10 checks whether the amount delta can be accommodated locally (taking care to avoid integer overflow), and if not, line 11 transfers to the slowpath. Otherwise, line 11 combines an updated counter value with the original countermax value into new. The atomic_cmpxchg() primitive on lines 13-14 then atomically compares this thread's counterandmax variable to old, updating its value to new if the comparison succeeds. If the comparison succeeds, line 15 returns success, otherwise, execution continues in the loop at line 9.

Quick Quiz 6.32: Yecch! Why the ugly goto on line 11 of Figure [*]? Haven't you heard of the break statement??? End Quick Quiz

Quick Quiz 6.33: Why would the atomic_cmpxchg() primitive at lines 13-14 of Figure [*] ever fail? After all, we picked up its old value on line 9 and have not changed it! End Quick Quiz

Lines 16-32 of Figure [*] show add_count()'s slowpath, which is protected by gblcnt_mutex, which is acquired on line 17 and released on lines 24 and 30. Line 18 invokes globalize_count(), which moves this thread's state to the global counters. Lines 19-20 check whether the delta value can be accommodated by the current global state, and, if not, line 21 invokes flush_local_count() to flush all threads' local state to the global counters, and then lines 22-23 recheck whether delta can be accommodated. If, after all that, the addition of delta still cannot be accommodated, then line 24 releases gblcnt_mutex (as noted earlier), and then line 25 returns failure.

Otherwise, line 28 adds delta to the global counter, line 29 spreads counts to the local state if appropriate, line 30 releases gblcnt_mutex (again, as noted earlier), and finally, line 31 returns success.

Lines 34-63 of Figure [*] show sub_count(), which is structured similarly to add_count(), having a fastpath on lines 41-48 and a slowpath on lines 49-62. A line-by-line analysis of this function is left as an exercise to the reader.

Figure: Atomic Limit Counter Read
\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long read_count(void)
...
... spin_unlock(&gblcnt_mutex);
17 return sum;
18 }\end{verbatim}
}\end{figure}

Figure [*] shows read_count(). Line 9 acquires gblcnt_mutex and line 16 releases it. Line 10 initializes local variable sum to the value of globalcount, and the loop spanning lines 11-15 adds the per-thread counters to this sum, isolating each per-thread counter using split_counterandmax on line 13. Finally, line 17 returns the sum.

Figure: Atomic Limit Counter Utility Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...idx] = NULL;
72 spin_unlock(&gblcnt_mutex);
73 }\end{verbatim}
}\end{figure}

Figure [*] shows the utility functions globalize_count(), flush_local_count(), balance_count(), count_register_thread(), and count_unregister_thread(). The code for globalize_count() is shown on lines 1-12, and it is similar to that of previous algorithms, with the addition of line 7, which is now required to split out counter and countermax from counterandmax.

The code for flush_local_count(), which moves all threads' local counter state to the global counter, is shown on lines 14-32. Line 22 checks to see if the value of globalreserve permits any per-thread counts, and, if not, line 23 returns. Otherwise, line 24 initializes local variable zero to a combined zeroed counter and countermax. The loop spanning lines 25-31 sequences through each thread. Line 26 checks to see if the current thread has counter state, and, if so, lines 27-30 move that state to the global counters. Line 27 atomically fetches the current thread's state while replacing it with zero. Line 28 splits this state into its counter (in local variable c) and countermax (in local variable cm) components. Line 29 adds this thread's counter to globalcount, while line 30 subtracts this thread's countermax from globalreserve.

Quick Quiz 6.34: What stops a thread from simply refilling its counterandmax variable immediately after flush_local_count() on line 14 of Figure [*] empties it? End Quick Quiz

Quick Quiz 6.35: What prevents concurrent execution of the fastpath of either atomic_add() or atomic_sub() from interfering with the counterandmax variable while flush_local_count() is accessing it on line 27 of Figure [*] empties it? End Quick Quiz

Lines 34-54 show the code for balance_count(), which refills the calling thread's local counterandmax variable. This function is quite similar to that of the preceding algorithms, with changes required to handle the merged counterandmax variable. Detailed analysis of the code is left as an exercise for the reader, as it is with the count_register_thread() function starting on line 56 and the count_unregister_thread() function starting on line 65.

Quick Quiz 6.36: Given that the atomic_set() primitive does a simple store to the specified atomic_t, how can line 53 of balance_count() in Figure [*] work correctly in face of concurrent flush_local_count() updates to this variable? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img178.png0000644000175000017500000002142711672746153015327 0ustar paulmckpaulmckPNG  IHDR)tRNSىH IDATx]lٕnY5j #ʻJ&F0Xl`h"y MjJ4.]<0K5AL"F2h`g9lrJVt룫vzTHSuԹ{Ϲ3KKE-fHV"P 4N@/w{Df|.fIkEY~Vb#Yh}ΟT⧵ .LGdGx82\ >oH6Wȴ 2x0)h2c Cr Jl:"`t0K ~6PKP =y>A.ae6leY.ɲu(SNP3AZ^lC^nl:<>nBX֑hiM .-)t6D~I`êKѭI@OrARwMJF0ŐBԤI y0wB>mc G: .!8R+=aեˌHVehǝI$Gx]pK  5e4_]BI`$ab\aŲI,>x^Y|XߑL; D=8v-cDr7hy~¦=Ķ?i~""9@*!eZD01$v/G]{U!J=ʖtH*U %20$ $PGuw&L6iHI46VzI1TDd'&>lA(}T~ɣh'x&, E QtI'd[cߐhu=Mo|#ss+Z? 8 5[R6:lh<0 x}k0{O}#ôn=h\^n *,rQ۲,О&պ =^U6$IeORg \/XցQ%-p*ZF} Yn mSlC5*E(uC;*m~Bw$ː^PSR-ȭT$k%@BqZ9R~w*|9$vSSaVѦBWSë`'nlCJ@h3DNj;$R0>4k !T.iNmr0L&Ԡ)Ƒlk%l<+!ij(1R&"INP}EjB+ߔXO~b %L0o_I=!U+(Rg @ٸ.Y>yZe *ݧKt> qUU]N[Eo4SWH2'0CEϮVC# ȕ.\P']}څ˭ 5cG;j1w'K K<_i7U;f4RAJjIE0`H6X}EO[4\coiU[ց;鸭$H@XәlwRK&9I~v -啻\ ^R1{ܤBlr;ɯY-џI,o,|2_>u?{mSa^SZ~Ko._=o_.,.ӿ\X<˅E~d]@@d&9jI$Alah"mc.4pV4LWR.Is}dhV[*.YJ-WڥmrmAD( bv;1v7y>\Ԥh?BkQ:%,^@ۋJ[.w$(u@$C砄=D֚(`)&zp) Jн 4ϻ KU,'d*eh!:W9 g6 Bt uJoܻRL ! iںCՠQQ̾Lq5n\p !iy(W\Y[R2oFJr>Ô+pfx>ıeY*ʲ,%ku&'Xa,!rU/hS31Os3wFێ DUS &eDeV@*.G}kC JU0& J2(vE CD0B"OdUHbJ0 4=|Җ wd0"˭bo4)йB(yx~_JY!f,n (mD|A?2[Äb(J@)3vY7Ϯ*kWni]h&%mG B tNiv:+ԾMSX9uD3%W΀0wH6r$cS >1!'*0 D? mG},E !Re8(Mg4Vy! !rǀή [X*` Py]b0Ȏ7DU (R4Js@5Qv]y`tV:c y@t4o1ƆDQӵ#⠉*iV\"[눾} RFqt|`Ru> ">z}xr\N=@9u,ӕ+s}Z{@k{!/5EQT]l$oz*][OƁM ;ۈ \O ϧK܀r(~h'qV Q:Z[_\ +eZ|?Ȥ@dRC[&epeJ-Tv եeQrZI()8Yr#ovV^ioIEή;>X$sA [qj=Eea),t7׭: Ԍ >*Tw6:Byo锝^>67#)w{[Ɣ{L쩚?`?*W0SS"N3;,op£#~ xe_4ϞezN6?NMaJ}sZjY7|As/?w5ۯ'//on?JoX'.n. ^F$XOq2(!pj2{_G}T-m.3OH9㵚 N-G4t &L<xA[%q`ClAV4wn=EZw͹sSjL06׊|muD` B :ZE}l8E+ WuZ3X*ޥTy(h t~0E! :U]Ag1mڡNmM;+3vplYluh8 ~v{AS9q^ řFqSʅUvk1ݱ֑& ?[.[sg3 x&tc)jS2ыbƫQ'G=d!e]bcܺ()F4őF Z ,#")z4cj T%f܌5s=.PZdQ8Q]lAkXZaW "6hN_^$bd,lr>^ j͌홞)FR{*EP,OunW=LrK,ƍj&ݧ@UebcP(T5 *.wΕdR6>@U)Nf>t:'-g,j8+jMx So#SO7F4őFywʓ_-[/b&?c5fQ0sE8 (?3/狜8Rb}ieeH3yڭؔ9Oɋ= ?dҢ{W~HX;[;[ƯolpbOX?./lp?w<;?Vlce~)|OolxO2^]D ˂А7JƵQMqcuu\E!i,2lI7.\Yf1mASzYAAjXu.Mq؎gLE2gOycS|)0Sȧ8|ȧ8BOqaDSc|#O<ۍ㻰~'tAVir+}Ǝ*f-$! ]zV 'AQJDfS}=dDFKڧ?"YO|"Dp9 GŒ-cZ@c51;FAтE8I@c3~eSQP E³f!<!;zJl#ɐuNY)ݔF$rjB}\ XzU];T_=rql?[ayͰ G 8{VcU/I%}@O\I4ԗڜPsBJ1$S~oTܛU~F%q5HugLbD)-X2L9di<%P/; \nGʔk0x=?_jU.4C2%Ӝ2 W>&2)Y}F )s.ugž֯;`[[? ȠLiJ3:&%'\ 32^_buV}J&UwJO9em R*sUV^Pl9&8|폋BF{s f+u:W /"QEo%+Ӱr/Xj) > PJ7n<l$! Z4((#oA+vJ1g'F`.CVOl|wD" ̳T_J]>tj_p~!VޗkU*> s=>NiuauTUqdHdz 1ڊ0 *WձӍKtz{ 1;-D\(2wuj*ssm6V٩lyvەWS *23ܹ}>xǑ|lK_?:RXWOWOÛ/(g~{WϿLN?;D^p\.*(ʴ>Rvn)T/N|0rE`D>?(_\ @pq ҥ ,B_mמ>pٟN/X.!$hi,h34Cx&j`#df &. IL!OG`1O K3;.9m[r5䘟sʐpg8Y^#Z uwdo T4ݾ%J rv9E~s0 j|P JxL[0rc'JF rvE(CMBكS!kPAp٪x.jҐ[Tȶ$KS;a27\z82/7tx4Qpt×xDq3"ҵ398lN sT1C[x:)")AHv#۽qpt?rVtpʡ4 gqP{v*rg^V"'YHEUfSl]ɻ_88rNaA}= dSF1jt3 ij#ǜpOlKJ@l{FPzǑ q Dɉ 4dOl#5A>e#$K2eTȲUv4rJנY.OwȌVh TeJ W*Pj'>h6cYbyy^NwPK,a! ]}IB}erN,b}_5쨢Y2%0_SM/w /׹~FC]{!]>и`7Xn@sU!\@ݠ Alj!.>Y[w9!24dƋC rN6r/I{q|!ősJs򅁔"g a8,yqWecg/<9<`D"}"!F[i\1paӑS!@[I: O/ xA)=1k"3qRg]g~䶹IDATG!G@>=!D=9%!Dr9j4]Ū=|s=%j+<˫z-4ʚcj+v{ה*Ob()Ӈhg5; {=WBnʞGӡmQtJZ_z~>H}ğ/ջ_+{]ܾ4pƒkNJ@cv%R@ HO=TEN[9!)@[|G^hkưk3,X[؟wx܃}h|.9`𑳱 GpӐ3\ _rJ("!&L94lmVA;3Y'~~E66|oc|ulg?q76$J6y64`yG.SEA;@ o,睅"h)" ɷ$Y¢,|%qyeJѥLBPrF˔a@A#mL6?х"9 G9HSFLyq}.SFLyq8;nsk_Zts+yXM3Q=4WVԛД D.3.7.2 NMIs from Dyntick-Idle Mode


D.3.7.2 NMIs from Dyntick-Idle Mode

Figure: NMIs from Dyntick-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_nmi_enter(void)
2 {
...
...18 return;
19 smp_mb();
20 rdtp->dynticks_nmi++;\end{verbatim}
}\end{figure}

Figure [*] shows rcu_nmi_enter() and rcu_nmi_exit(), which handle NMI entry and exit, respectively. It is important to keep in mind that entering an NMI handler exits dyntick-idle mode and vice versa, in other words, RCU must pay attention to CPUs that claim to be in dyntick-idle mode while they are executing NMI handlers, due to the fact that NMI handlers can contain RCU read-side critical sections. This reversal of roles can be quite confusing: you have been warned.

Line 5 of rcu_nmi_enter() obtains a pointer to this CPU's rcu_dynticks structure, and line 6 checks to see if this CPU is already under scrutiny by RCU, with line 7 silently returning if so. Otherwise, line 8 increments the ->dynticks_nmi field, which must now have an odd-numbered value. Finally, line 9 executes a memory barrier to ensure that the prior increment of ->dynticks_nmi is see by all CPUs to happen before any subsequent RCU read-side critical section.

Line 16 of rcu_nmi_exit() again fetches a pointer to this CPU's rcu_dynticks structure, and line 17 checks to see if RCU would be paying attention to this CPU even if it were not in an NMI, with line 18 silently returning if so. Otherwise, line 19 executes a memory barrier to ensure that any RCU read-side critical sections within the handler are seen by all CPUs to happen before the increment of the ->dynticks_nmi field on line 20. The new value of this field must now be even.

Quick Quiz D.51: But how does the code in Figure [*] handle nested NMIs? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node223.html0000644000175000017500000001164211672746162015645 0ustar paulmckpaulmck 14.2.10.3 What May Not Be Assumed About Memory Barriers?


14.2.10.3 What May Not Be Assumed About Memory Barriers?

There are certain things that memory barriers cannot guarantee outside of the confines of a given architecture:

  1. There is no guarantee that any of the memory accesses specified before a memory barrier will be complete by the completion of a memory barrier instruction; the barrier can be considered to draw a line in that CPU's access queue that accesses of the appropriate type may not cross.
  2. There is no guarantee that issuing a memory barrier on one CPU will have any direct effect on another CPU or any other hardware in the system. The indirect effect will be the order in which the second CPU sees the effects of the first CPU's accesses occur, but see the next point.
  3. There is no guarantee that a CPU will see the correct order of effects from a second CPU's accesses, even if the second CPU uses a memory barrier, unless the first CPU also uses a matching memory barrier (see the subsection on "SMP Barrier Pairing").
  4. There is no guarantee that some intervening piece of off-the-CPU hardware14.7 will not reorder the memory accesses. CPU cache coherency mechanisms should propagate the indirect effects of a memory barrier between CPUs, but might not do so in order.

Paul E. McKenney 2011-12-16
perfbook_html/node99.html0000644000175000017500000001441211672746162015576 0ustar paulmckpaulmck 7.4.3.6 Performance

7.4.3.6 Performance

Rough performance results7.9are shown in Figure [*], running on a dual-core Intel x86 running at 1GHz (4300 bogomips per CPU) with at most six blocks allowed in each CPU's cache. In this micro-benchmark, each thread repeatedly allocates a group of blocks and then frees it, with the size of the group being the ``allocation run length'' displayed on the x-axis. The y-axis shows the number of successful allocation/free pairs per microsecond -- failed allocations are not counted. The ``X''s are from a two-thread run, while the ``+''s are from a single-threaded run.

Figure: Allocator Cache Performance
\resizebox{3in}{!}{\includegraphics{SMPdesign/smpalloc}}

Note that run lengths up to six scale linearly and give excellent performance, while run lengths greater than six show poor performance and almost always also show negative scaling. It is therefore quite important to size TARGET_POOL_SIZE sufficiently large, which fortunately is usually quite easy to do in actual practice [MSK01], especially given today's large memories. For example, in most systems, it is quite reasonable to set TARGET_POOL_SIZE to 100, in which case allocations and frees are guaranteed to be confined to per-thread pools at least 99% of the time.

As can be seen from the figure, the situations where the common-case data-ownership applies (run lengths up to six) provide greatly improved performance compared to the cases where locks must be acquired. Avoiding locking in the common case will be a recurring theme through this book.

Quick Quiz 7.15: In Figure [*], there is a pattern of performance rising with increasing run length in groups of three samples, for example, for run lengths 10, 11, and 12. Why? End Quick Quiz

Quick Quiz 7.16: Allocation failures were observed in the two-thread tests at run lengths of 19 and greater. Given the global-pool size of 40 and the per-CPU target pool size of three, what is the smallest allocation run length at which failures can occur? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img192.png0000644000175000017500000001664711672746134015332 0ustar paulmckpaulmckPNG  IHDR=QNPLTEMJKKHIrpq# b``mkkiggcaaXUV856iffC@@@<=wuv.*+|zz[EtRNS@fIDATx} *%qdWG$GiUY}=_@CBl@n]$<0-PY_'!oaVF勃ֻ=۝59H3o ݶ=9H:inQmOG+ P`8C)ꤡHM[~S%h:D xC?h'̚MtԞdh4V7k=;oJTlY~sQѓk}o ȘUCjj=72fK W?a:>|ws/0Q:oů7Oa4Cjwjad-'|)>Y1}ψBUWjah3۩v^*E4;hiT4#E A)UaK0s_jI1'P *up^U _>5jCF B8髠ÅTlˁC+2c@h>b|BdhS%:IT{3Xl r`KaGZ#v\*'_!9U 5jh}?WvIdRAJ[QǦhGR_{$d󻌡|QNQya`6fŒx^~2_ 8K毼 (e&=496=4q.O-a#idW䇩/~iEC}+@Q+[ 9slY;2Ʌn$) a[v&Z4jmS߆fDk3~"LՓnԡ|z26aWp+eДt.F`eJgY5(EeRhpD^vix2A87/_P6 |OaХٙXBIS~1}:QE3' w$g_{6|N Pro |9I)+;fӪKJ?~k_W*U]cF,MutϑM I O Vh> 1?9L6#kcYnG]B3`КqhcFk)+@ *%E7|Foe3zs%hES>8+$t"wQ6WW ѥ< fSItl/p]G|xyh/ wٳ񊎹7墳1[)| U WPS-TƓؒ[3ɞaN6 2N*?Vc2"6Ҋ\ڹE^(+ʖ ڞB Q)N (cMt.C7At=7 *| D pJpL ԣ?daW,%hr V]$-b^.?=Y]Hܦ, C tB6C'T7+r7uR/]b[\C R?iahZPNzULjriDl"}gczAq'D^MS&뿼T6^B]mt׸X7#j|Nr֗acVu2-2X^*w3I 'xDY\7 Qˋ6,V\cBCq0Ay)U<3 s}+?̫<"k. FkLL^qQ<\hW3lv1j^0{Bgq$Fsw.20|YR53sI?"`3(٢Ɵe-E\"BH(|\H},Yj.o0Ƙf Jhjk=vKD/yqn { 1JJ|j_N@\zR쥄6.9CʜkWTnzo^~O/P*vv; bVM>= 4x9vk {9١—2T{_%"Fvk XPR|_: ,³7α6av! V noWku^LW+d^MDMލ`{ij'+DDD4a.~N*GcX1dA:ffECe{X+iy6Yn ϯUQWh=̉baeYLWMo QSx^7F3Zo%p@zcr ~b5xxW#5F -YBoe^oC13F嵣ҕPá]/>d{}Ǚ'-FA 37ib3/[sxʢڸJ(^8<̯~tm*-BV3N1rdؿ3ߘ<`N#';RsmܮMf[b%-np%bidCڰOPl^c/Hc ,[ Gf+| YڶR8²'$nNBCA쎍|+S$'$(kOS4(I@>?)%uh:{<3o|}$`-֏<3-؉n"OΊqf> 0LqE{>k|}+/۴ދR/\)R (vV a eu{\ex,~? ؇8l.y;yl) b@jh]X6qi2iZ@F%}IyPA%c1@]6p `gKMg@+^'3Yѐ"spQ<@W״f=%H lv3FֲJ.:fi.q%9őE3吧GtLW֡sݿa*{"5I8dizWHN': 3tkY[f#޷"'P{ 6H5V8a$koX?!)lMfE#zof ߚϰnS5'@i~ ^ln~{t_Fg^p5?C4Nߵ$teesoܸ3dZE8.Ʈr@lR ZUIr=|ZowHhau8ynLSnNJJx4̵k,}8#y[*l\? .wd  w^n_nգD.#a4^ýLmQ{;Op Л{@C=MT{"f ;yLmqPä_6wX^?CRwңGJXVe7eiN2%i°' ,|5'YA7sy'6Ι:xpFNs>#S|{]l"ml0K_+_HDGDWHxPNpt+dCj/•Olj%7]-jQt޷6$C/k vOY` |pyatzY&-wmi^j>s)J&nܘ㙲v]I2"?G!0>ˇiS_c<7gd~*s%w}opg,&[5x~%_5m:wCY_BETBmsHʇE<%؊7nl ϋWljks -o;X/"_%,2ǵ칳ݔKag~]m+"|셿[k/,/<|q-{l'lvg9MW_ZrxdjD,hgm/\/3J,g/j cp(!T] @CNf|&1la7OR5HP{S|S8AKxȦUJG}s@9wq=™)GM<9KթKrE%8AKx@:33BHK,sq};>pXLs.'RwgP;]L>'&orzBvF%,AbE r 3XؾWĻN>7p*Mo#6X[<x?Tð/0T{0Z(GL,T cйDHY 6.6 Parallel Counting Discussion


6.6 Parallel Counting Discussion

This chapter has presented the reliability, performance, and scalability problems with traditional counting primitives. The C-language ++ operator is not guaranteed to function reliably in multithreaded code, and atomic operations to a single variable neither perform nor scale well. This chapter has also presented a number of counting algorithms that perform and scale extremely well in certain special cases.


Table: Statistical Counter Performance on Power 5
      Reads
Algorithm Section Updates 1 Core 64 Cores
count_stat.c [*] 40.4 ns 220 ns 220 ns
count_end.c [*] 6.7 ns 521 ns 205,000 ns
count_end_rcu.c [*] 6.7 ns 481 ns 3,700 ns


Table [*] shows the performance of the three parallel statistical counting algorithms. All three algorithms provide perfect linear scalability for updates. The per-thread-variable implementation is significantly faster on updates than the array-based implementation, but is slower at reads, and suffers severe lock contention when there are many parallel readers. This contention can be addressed using techniques introduced in Chapter [*], as shown on the last row of Table [*].

Quick Quiz 6.49: On the count_stat.c row of Table [*], we see that the update side scales linearly with the number of threads. How is that possible given that the more threads there are, the more per-thread counters must be summed up? End Quick Quiz

Quick Quiz 6.50: Even on the last row of Table [*], the read-side performance of these statistical counter implementations is pretty horrible. So why bother with them? End Quick Quiz


Table: Limit Counter Performance on Power 5
        Reads
Algorithm Section Exact? Updates 1 Core 64 Cores
count_lim.c [*] N 9.7 ns 517 ns 202,000 ns
count_lim_app.c [*] N 6.6 ns 520 ns 205,000 ns
count_lim_atomic.c [*] Y 56.1 ns 606 ns 166,000 ns
count_lim_sig.c [*] Y 17.5 ns 520 ns 205,000 ns


Figure [*] shows the performance of the parallel limit-counting algorithms. Exact enforcement of the limits incurs a substantial performance penalty, although on the Power 5 system this penalty can be reduced by substituting read-side signals for update-side atomic operations. All of these implementations suffer from read-side lock contention in the face of concurrent readers.

Quick Quiz 6.51: Given the performance data shown in Table [*], we should always prefer update-side signals over read-side atomic operations, right? End Quick Quiz

Quick Quiz 6.52: Can advanced techniques be applied to address the lock contention for readers seen in Table [*]? End Quick Quiz

The fact that these algorithms only work well in their respective special cases might be considered a major problem with parallel programming in general. After all, the C-language ++ operator works just fine in single-threaded code, and not just for special cases, but in general, right?

This line of reasoning does contain a grain of truth, but is in essence misguided. The problem is not parallelism as such, but rather scalability. To understand this, first consider the C-language ++ operator. The fact is that it does not work in general, only for a restricted range of numbers. If you need to deal with 1,000-digit decimal numbers, the C-language ++ operator will not work for you.

Quick Quiz 6.53: The ++ operator works just fine for 1,000-digit numbers! Haven't you heard of operator overloading??? End Quick Quiz

This problem is not specific to arithmetic. Suppose you need to store and query data. Should you use an ASCII file, XML, a relational database, a linked list, a dense array, a B-tree, a radix tree, or any of the plethora of other data structures and environments that permit data to be stored and queried? It depends on what you need to do, how fast you need it done, and how large your data set is.

Similarly, if you need to count, your solution will depend on how large of numbers you need to work with, how many CPUs need to be manipulating a given number concurrently, how the number is to be used, and what level of performance and scalability you will need.

Nor is this problem specific to software. The design for a bridge meant to allow people to walk across a small brook might be a simple as a plank thrown across the brook. But this solution of using a plank does not scale. You would probably not use a plank to span the kilometers-wide mouth of the Columbia River, nor would such a design be advisable for bridges carrying concrete trucks. In short, just as bridge design must change with increasing span and load, so must software design change as the number of CPUs increases.

The examples in this chapter have shown that an important tool permitting large numbers of CPUs to be brought to bear is partitioning. Whether fully partitioned, as in the statistical counters discussed in Section [*], or partially partitioned as in the limit counters discussed in Sections [*] and [*]. Partitioning will be considered in far greater depth in the next chapter.

Quick Quiz 6.54: But if we are going to have to partition everything, why bother with shared-memory multithreading? Why not just partition the problem completely and run as multiple processes, each in its own address space? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img201.png0000644000175000017500000001051611672746034015305 0ustar paulmckpaulmckPNG  IHDRWn0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fIDATx\mř~K2mnlfXEQ"2Q"Nr rnسKn;&0|\f_Il]ڰ,^s肱eqW=Q]=ӽx^g}}v!1c$vm+-#BBVQ4 Vᴈ`+:(M~l=,4ɔAfysiF(֗YR3_5v;CcNsVPFORi,lAcCͯ&Ɋm[&%4x`R8莦nc*HɔnMd{,ʎx`( .>5//Ӗk|2BOI1О[0tfo|`7hDtU/n_,1R- RcgC Wvw#R# sU{4ԗ"V -xH2FN}P~18wFQgn(Ut#vtu>U=O(Ad|ྭ4Fs k\~ ѨNͩI ` >*W4'`<6_ϯC G oRi羲073fB- mJmjxV*FUl.,ΌώG 8hY +z[ߖpPa tҖsԦZ$J$J+]1Xa[vB]b]Hi3RmK-."ɘe#e7myX9 n&1!1 "hGh畽c7#n<A3vs!R7qK~`h>O Aފ4Ia (WHON$ICXS(n);B۞Bi@nZEf@Dl6߶[@d6`٘l\tHajSx"'PĠXw!c]7-9limc X -{M6',v[CBNɻz+A~&"J(ʿ{fA<51!AΚs@@Up탑iIa$}I3hs9^oP~'"7WŇX!OۧW,=~%w%D-$Bxcޡ[Ur2;emC܀JA wEAauA} kFX HX H=+eqqHͲ>6r gnYk#LtD@%xiFXR~k]-ZS[soNM3AjmVF`[ ssp!(qCȳ&0Y'_ZB7 faHV\KCux MgqЊ%L? P;` oU.B6ヨkm .Kx)3??Ӯ Z.GXf׵dhq )R*\Qhu2**1mggPBrL/hSi}%2d"S:~/1%i_8pX&H;YX|I5 +`}'G SvLC۷0ԥ3|'ʖb=30fn͚Roo;8r|cpo@V,c4W󷪤7gIJS\!Owĕ9  W=^w7 ~3>qQ: a ֔!ON -zvlEV5券[fLDĉgL_*&ˑ˟\lzxm|\R+/h7p2ZwrP<93![C{;rt-,MC%2bdѯ.qAXf$e*1.'6;'vȚȈ'&ްkv-m㭚OlÖaqawПÉ !()^"# |bAVU]ǁ2 T 3I<'#bMiS148wƛ9r-Cܜf]'Xue aq.~6g9a/a_]{1< (2>p<7Gx59 ~3d\}̀٭r$C#8%rl'RfU >O[vICpQUɣ8 D:n(t6#[o~; :(9,,Qy!n=]32d &o~%i9dE-UuKVpFC1ʝ: ianT3 x*Ϊ?wAOţ:9*$cSdq@"f$S@ Sz([h9ѵף_ /:){g:[&oKCspOW5#G ޓd_šۈ jӠIْ1#&Ÿ(]_l< m7J*>Ҏ.l0{ A.7l;˟\Ш2OQydDY/l ?rA"!XW$!//6 2 uŶ"!ZKj}iY_lZŦe}iY_lZRTBS bd1Mb(P#4% FhJ(@- ].sPV]~n*[.9 @F A#[廃B(s6k34*mZPr_p\ ӆ\VvRX 1BS bd1Mb(P#4%[bU_`R0IENDB`perfbook_html/node324.html0000644000175000017500000001206311672746163015646 0ustar paulmckpaulmck C.8 Are Memory Barriers Forever?


C.8 Are Memory Barriers Forever?

There have been a number of recent systems that are significantly less aggressive about out-of-order execution in general and re-ordering memory references in particular. Will this trend continue to the point where memory barriers are a thing of the past?

The argument in favor would cite proposed massively multi-threaded hardware architectures, so that each thread would wait until memory was ready, with tens, hundreds, or even thousands of other threads making progress in the meantime. In such an architecture, there would be no need for memory barriers, because a given thread would simply wait for all outstanding operations to complete before proceeding to the next instruction. Because there would be potentially thousands of other threads, the CPU would be completely utilized, so no CPU time would be wasted.

The argument against would cite the extremely limited number of applications capable of scaling up to a thousand threads, as well as increasingly severe realtime requirements, which are in the tens of microseconds for some applications. The realtime-response requirements are difficult enough to meet as is, and would be even more difficult to meet given the extremely low single-threaded throughput implied by the massive multi-threaded scenarios.

Another argument in favor would cite increasingly sophisticated latency-hiding hardware implementation techniques that might well allow the CPU to provide the illusion of fully sequentially consistent execution while still providing almost all of the performance advantages of out-of-order execution. A counter-argument would cite the increasingly severe power-efficiency requirements presented both by battery-operated devices and by environmental responsibility.

Who is right? We have no clue, so are preparing to live with either scenario.

Paul E. McKenney 2011-12-16
perfbook_html/images.pl0000644000175000017500000030453511672746164015415 0ustar paulmckpaulmck# LaTeX2HTML 2008 (1.71) # Associate images original text with physical files. $key = q/{figure}{{scriptsize{preform{verbatim1437#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_enter_nohz(void)
2 {
...
...
23 local_irq_restore(flags);
24 smp_mb();
25 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1629#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_enter_nohz(void)
2 {
...
...
25 local_irq_restore(flags);
26 smp_mb();
27 }\end{verbatim}
}\end{figure}|; $key = q/{figure}center{{small{picture{(170,170)(0,0){par{%Addresses{par{put(0,0){makeboxt{}}put(100,150){{framebox{(}{80,10){{tt{}}picture{center{{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}\begin{center}
\small
\begin{picture}(170,170)(0,0)
\par
% Address...
...
\put(100,150){\framebox{(}80,10){\tt }}
\end{picture}\end{center}
\end{figure}|; $key = q/{figure}{{tt{{scriptsize{preform{verbatim1193#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{\tt\scriptsize
\begin{verbatim}1 struct el *insert(long key, l...
...}
23 p = p->next;
24 };
25 return (NULL);
26 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim929#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_rcu(void)
2 {...
... 16 spin_unlock(&rcu_gp_lock);
17 smp_mb();
18 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{IncoherentInstructionCacheslashPipeline?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Incoherent Instruction Cache/Pipeline?}
\end{picture}|; $key = q/resizebox{6in}{!}{includegraphics{appendixslashrcuimplslashRCUTreeQSScan}};AAT/; $cached_env_img{$key} = q|\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeQSScan}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptListsCompare}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptListsCompare}}|; $key = q/{figure}{{scriptsize{preform{verbatim1481#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_check_mb(int cp...
...per_cpu(rcu_mb_flag, cpu) = rcu_mb_done;
6 }
7 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim505#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 long counter = 0;
2
3 void i...
...ng read_count(void)
9 {
10 return counter;
11 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashwhymbslashcacheSBfIQ}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBfIQ}}|; $key = q/{figure}{{scriptsize{preform{verbatim650#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...4 spin_unlock(&bp->hash_lock);
35 return 0;
36 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim517#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
...61 spin_unlock(&gblcnt_mutex);
62 return 1;
63 }\end{verbatim}
}\end{figure}|; $key = q/{figure*}{{scriptsize{{centering{preform{verbatim783#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 int search(long key,...
...ead_unlock();
14 return 0; 14 return 0;
15 } 15 }\end{verbatim}
}\end{figure*}|; $key = q/{figure}{{scriptsize{preform{verbatim513#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...idx] = NULL;
37 spin_unlock(&gblcnt_mutex);
38 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{1509preform{verbatim1537#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1 proctype qrcu_reader(byte me)...
...rogress[me] = 2;
19 atomic { ctr[myidx]- }
20 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1483#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_idle(vo...
...flip_flag, cpu) = rcu_flipped;
15 return 1;
16 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{2.7in}{!}{includegraphics{deferslashRCUReplacement}};AAT/; $cached_env_img{$key} = q|\resizebox{2.7in}{!}{\includegraphics{defer/RCUReplacement}}|; $key = q/resizebox{3in}{!}{includegraphics{introslashFourTaskOrder}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{intro/FourTaskOrder}}|; $key = q/resizebox{6in}{!}{includegraphics{appendixslashrcuimplslashRCUTreeInit}};AAT/; $cached_env_img{$key} = q|\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeInit}}|; $key = q/{figure}{{scriptsize{preform{verbatim787#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 str...
...>lock);
23 rcu_read_unlock();
24 return 0;
25 }\end{verbatim}
}\end{figure}|; $key = q/includegraphics{advsyncslashSpeculativeLoadBarrier};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/SpeculativeLoadBarrier}|; $key = q/f=100;MSF=1.6;AAT/; $cached_env_img{$key} = q|$f=100$|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashwhymbslashcacheSB}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSB}}|; $key = q/resizebox{3in}{!}{includegraphics{countslashGlobalInc}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{count/GlobalInc}}|; $key = q/{figure}{{scriptsize{preform{verbatim1484#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitack...
...rcupreempt_trace_try_flip_a2);
13 return 1;
14 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{1508preform{verbatim1536#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUrt-MBnowaste}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBnowaste}}|; $key = q/{figure}{{centering{preform{verbatim1021#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \centering
\begin{verbatim}1 thread0(void)
2 {
3 A = 1;
4 ...
... continue;
20 smp_mb();
21 assert(A != 0);
22 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{CodeSamplesslashcountslashatomic}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{CodeSamples/count/atomic}}|; $key = q/{figure}{{scriptsize{preform{verbatim1440#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 dyntick_save_prog...
...et)
15 rdp->dynticks_fqs++;
16 return ret;
17 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1421#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int rcu_needs_cpu(int cpu)
2 {...
...ault:
25 break;
26 }
27 return NOTIFY_OK;
28 }\end{verbatim}
}\end{figure}|; $key = q/{displaymath}frac{L_N}{NL_1}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
\frac{L_N}{N L_1}
\end{displaymath}|; $key = q/{figure}{{scriptsize{preform{verbatim1485#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitzer...
...rcupreempt_trace_try_flip_z2);
18 return 1;
19 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{LoadsReorderedAfterLoads?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Loads Reordered After Loads?}
\end{picture}|; $key = q/{figure}{{scriptsize{preform{verbatim1226#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}int init_srcu_struct(struct srcu_s...
...ng srcu_batches_completed(struct srcu_struct *sp);\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim918#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashTreeClassicRCU}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCU}}|; $key = q/includegraphics{advsyncslashWriteBarrierOrdering};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/WriteBarrierOrdering}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashGracePeriodGood}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/GracePeriodGood}}|; $key = q/f=10;MSF=1.6;AAT/; $cached_env_img{$key} = q|$f=10$|; $key = q/includegraphics{SMPdesignslashLockGranularity};AAT/; $cached_env_img{$key} = q|\includegraphics{SMPdesign/LockGranularity}|; $key = q/{figure}{{scriptsize{preform{verbatim923#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...);
4 DEFINE_PER_THREAD(long, rcu_reader_gp_snap);\end{verbatim}
}\end{figure}|; $key = q/N+1;MSF=1.6;AAT/; $cached_env_img{$key} = q|$N+1$|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashGracePeriodGood}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodGood}}|; $key = q/{figure}{{scriptsize{preform{verbatim1234#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void srcu_read_unlock(struct sr...
...ocessor_id())->c[idx]-;
7 preempt_enable();
8 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashwhymbslashcacheSBf}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSBf}}|; $key = q/{figure}{{scriptsize{preform{verbatim926#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
... 38 spin_unlock(&rcu_gp_lock);
39 smp_mb();
40 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim518#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long read_count(void)
...
... spin_unlock(&gblcnt_mutex);
17 return sum;
18 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashlockdeq}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeq}}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashallocatorcache}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/allocatorcache}}|; $key = q/includegraphics{advsyncslashSpeculativeLoad};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/SpeculativeLoad}|; $key = q/{figure}{{scriptsize{preform{verbatim920#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashCPUvsEnet}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/CPUvsEnet}}|; $key = q/{displaymath}T=frac{1}{mu-nlambda_0}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
T = \frac{1}{\mu - n \lambda_0}
\end{displaymath}|; $key = q/{figure}{{scriptsize{preform{verbatim331#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int x = 0;
2
3 void *mythrea...
...ent process sees x=%d\n'', x);
24 return 0;
25 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim655#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void memblock_free(struct membl...
...tex);
15 }
16 pcpp->pool[++pcpp->cur] = p;
17 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{AtomicInstructionsReorderedWithLoads?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Atomic Instructions Reordered With Loads?}
\end{picture}|; $key = q/{figure}{{scriptsize{preform{verbatim648#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...0 }
21 cur = cur->next;
22 }
23 return 0;
24 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{centering{preform{verbatim1022#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \centering
\begin{verbatim}1 state.variable = mycpu;
2 lastt...
...();
6 if (lasttb - firsttb > 1000)
7 break;
8 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1521#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashpipeline}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/pipeline}}|; $key = q/{displaymath}epsilon=frac{T_rR_i}{2}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
\epsilon = \frac{T_r R_i}{2}
\end{displaymath}|; $key = q/{figure}{{scriptsize{preform{verbatim333#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 pthread_mutex_t lock_a = PTHREA...
...ock'');
46 exit(-1);
47 }
48 return NULL;
49 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashRCUCallbacks}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/RCUCallbacks}}|; $key = q/{figure}{{scriptsize{preform{verbatim1229#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int readside(void)
2 {
3 int ...
...ize_srcu(&ss);
22 cleanup_srcu_struct(&ss);
23 }\end{verbatim}
}\end{figure}|; $key = q/y=1;MSF=1.6;AAT/; $cached_env_img{$key} = q|$y=1$|; $key = q/{figure*}{{scriptsize{preform{verbatim1525#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{ \scriptsize
\begin{verbatim}Starting :init: with pid 0
1: pr...
... (state 24) <valid end state>
3 processes created\end{verbatim}
}\end{figure*}|; $key = q/{figure}{{scriptsize{preform{verbatim514#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long __thread counter ...
...NLOCK(gblcnt_mutex);
8  ...|; $key = q/{displaymath}e=frac{1slashlambda_0}{T+1slashlambda_0}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
e = \frac{1 / \lambda_0}{T + 1 / \lambda_0}
\end{displaymath}|; $key = q/{figure}{{scriptsize{preform{verbatim913#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t rcu_refcnt;
2
3 stat...
...{
19 poll(NULL, 0, 10);
20 }
21 smp_mb();
22 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{centering{preform{verbatim2904#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \centering
\begin{verbatim}1 spin_lock(&mylock);
2 p = searc...
...&mylock);
8 synchronize_rcu();
9 kfree(p);
10 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1448#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void print_cpu_stall(str...
...(&rnp->lock, flags);
17 set_need_resched();
18 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1449#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void print_other_cpu_sta...
..._start));
34 force_quiescent_state(rsp, 0);
35 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrwlockRCUupdate}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUupdate}}|; $key = q/{figure}{{scriptsize{preform{verbatim1435#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 cpu_quiet_msk(un...
...cessor_id()]);
26 rcu_start_gp(rsp, flags);
27 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1631#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_irq_enter(void)
2 {
...
...cu_bh_data).nxtlist)
25 set_need_resched();
26 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashGracePeriodBad}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GracePeriodBad}}|; $key = q/lambda_0;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\lambda_0$|; $key = q/{figure}{{scriptsize{preform{verbatim1420#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __rcu_process_ca...
... &__get_cpu_var(rcu_bh_data));
29 smp_mb();
30 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1480#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_check_callbacks(int cp...
...2 spin_unlock_irqrestore(&rdp->lock, flags);
13 }\end{verbatim}
}\end{figure}|; $key = q/{displaymath}e=frac{f-n}{f-(n-1)}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
e = \frac{f - n}{f - (n - 1)}
\end{displaymath}|; $key = q/includegraphics{advsyncslashMemoryBarrierPairing};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/MemoryBarrierPairing}|; $key = q/{figure}{{scriptsize{preform{verbatim510#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long __thread counter ...
...ADS] = { NULL };
7 DEFINE_SPINLOCK(gblcnt_mutex);\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1423#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __init rcu_init_one...
... - 1];
32 }
33 rnp->level = i;
34 }
35 }
36 }\end{verbatim}
}\end{figure}|; $key = q/T_r;MSF=1.6;AAT/; $cached_env_img{$key} = q|$T_r$|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashbarrier}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/barrier}}|; $key = q/{figure}{{scriptsize{preform{verbatim911#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...rcu_gp_lock);
14 spin_unlock(&rcu_gp_lock);
15 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{countslashcount_lim}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{count/count_lim}}|; $key = q/includegraphics{advsyncslashMemoryArchitecture};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/MemoryArchitecture}|; $key = q/{figure}{{scriptsize{preform{verbatim566#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct element *pdeq_dequeue_l(...
...eright(d->lidx);
48 spin_unlock(&d->rlock);
49 }\end{verbatim}
}\end{figure}|; $key = q/T;MSF=1.6;AAT/; $cached_env_img{$key} = q|$T$|; $key = q/{figure}{{scriptsize{preform{verbatim736#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct hlist_no...
...p->c = 3;
15 hlist_add_head_rcu(&p->list, &head);\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1434#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 cpu_quiet(int cp...
... cpu_quiet_msk(mask, rsp, rnp, flags);
25 }
26 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashRCUDeletion}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/RCUDeletion}}|; $key = q/{figure}{{scriptsize{preform{verbatim519#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...idx] = NULL;
72 spin_unlock(&gblcnt_mutex);
73 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1482#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_try_flip(void)
...
...ck_irqrestore(&rcu_ctrlblk.fliplock, flags);
28 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{countslashPerThreadInc}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{count/PerThreadInc}}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrefRCUperfwtPREEMPT}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/refRCUperfwtPREEMPT}}|; $key = q/{figure}{{scriptsize{preform{verbatim521#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void globalize_count(voi...
...r = globalcount;
62 globalcount -= counter;
63 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1425#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_init_percpu_...
...dp, lastcomp);
42 local_irq_restore(flags);
43 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{introslashFourTaskCategories}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{intro/FourTaskCategories}}|; $key = q/{figure}{{scriptsize{preform{verbatim708#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct file *fget(unsigned int ...
...uhead);
40 kmem_cache_free(filp_cachep, f);
41 }\end{verbatim}
}\end{figure}|; $key = q/rightarrow;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\rightarrow$|; $key = q/{figure}{{scriptsize{preform{verbatim1446#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 record_gp_stall_...
... =
6 jiffies + RCU_SECONDS_TILL_STALL_CHECK;
7 }\end{verbatim}
}\end{figure}|; $key = q/{figure*}{{scriptsize{{centering{preform{verbatim784#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 int delete(long key)...
...(&listmutex);
15 return 0; 16 return 0;
16 } 17 }\end{verbatim}
}\end{figure*}|; $key = q/{figure}{{scriptsize{preform{verbatim671#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 spin_lock(&lock2);
2 layer_2_p...
...unlock(&lock2);
7 spin_unlock(&nextlayer->lock1);\end{verbatim}
}\end{figure}|; $key = q/muslashlambda_0;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\mu / \lambda_0$|; $key = q/{figure}{{scriptsize{preform{verbatim515#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void balance_count(void)...
...r = globalcount;
11 globalcount -= counter;
12 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1427#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __rcu_offline_cp...
...;
46 __rcu_offline_cpu(cpu, &rcu_bh_state);
47 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim338#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 pthread_rwlock_t rwl = PTHREAD_...
...9 readcounts[me] = loopcnt;
40 return NULL;
41 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim509#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 long __thread counter = 0;
2 l...
...[idx] = NULL;
41 spin_unlock(&final_mutex);
42 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashlockdeqhash}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash}}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashManyHappy}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/ManyHappy}}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashmipsperbuck}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/mipsperbuck}}|; $key = q/O(logN);MSF=1.6;AAT/; $cached_env_img{$key} = q|$O(log N)$|; $key = q/includegraphics{advsyncslashReadBarrierSupplied1};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/ReadBarrierSupplied1}|; $key = q/1slashlambda_0;MSF=1.6;AAT/; $cached_env_img{$key} = q|$1 / \lambda_0$|; $key = q/{figure}{{scriptsize{preform{verbatim916#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_rcu(void)
2 {...
... 19 spin_unlock(&rcu_gp_lock);
20 smp_mb();
21 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptStates}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptStates}}|; $key = q/{figure}{{scriptsize{preform{verbatim1447#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 check_cpu_stall(...
...LAY) {
14 print_other_cpu_stall(rsp);
15 }
16 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashBigTreeClassicRCUBHdyntick}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBHdyntick}}|; $key = q/includegraphics{advsyncslashAbstractMemoryAccessModel};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/AbstractMemoryAccessModel}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashatomic}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/atomic}}|; $key = q/mu;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\mu$|; $key = q/{figure}{{scriptsize{preform{verbatim1488#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_lock(void)
2 {...
...) = idx;
18 local_irq_restore(flags);
19 }
20 }\end{verbatim}
}\end{figure}|; $key = q/epsilon;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\epsilon$|; $key = q/includegraphics{advsyncslashReadBarrierSupplied};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/ReadBarrierSupplied}|; $key = q/{figure}{{scriptsize{preform{verbatim919#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void flip_counter_and_wa...
... 24 spin_unlock(&rcu_gp_lock);
25 smp_mb();
26 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{introslashGenerality}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{intro/Generality}}|; $key = q/{figure}{{scriptsize{preform{verbatim506#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t counter = ATOMIC_INIT(...
...void)
9 {
10 return atomic_read(&counter);
11 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{LoadsReorderedAfterStores?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Loads Reordered After Stores?}
\end{picture}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashTreeMapping}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeMapping}}|; $key = q/{figure}{{scriptsize{preform{verbatim1445#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 force_quiescent_...
...pin_unlock_irqrestore(&rsp->fqslock, flags);
62 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashsmpalloc}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/smpalloc}}|; $key = q/{figure}{{scriptsize{preform{verbatim1630#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_nmi_enter(void)
2 {
...
...ATELIMIT(rdtp->dynticks_nmi & 0x1, &rcu_rs);
24 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim334#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 printf(''Creating two threads u...
...
17 perror(''pthread_join'');
18 exit(-1);
19 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim706#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct kref {
2 atomic_t refco...
...ase(kref);
25 return 1;
26 }
27 return 0;
28 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1418#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __call_rcu(struc...
...{
46 __call_rcu(head, func, &rcu_bh_state);
47 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1539#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 proctype qrcu_updater(byte me)
...
...ert(sum == 0);
54 break
55 od
56 }
57 od
58 }\end{verbatim}
}\end{figure}|; $key = q/{figure*}{{scriptsize{{centering{preform{verbatim782#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{ \scriptsize\centering
\begin{verbatim}1 struct el { 1 struct...
...istmutex);
9 LIST_HEAD(head); 9 LIST_HEAD(head);\end{verbatim}
}\end{figure*}|; $key = q/{figure}{{scriptsize{preform{verbatim1230#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct srcu_struct_array {
2 i...
...t_array *per_cpu_ref;
7 struct mutex mutex;
8 };\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1527#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}(Spin Version 4.2.5 - 2 April 200...
...es)
unreached in proctype :init:
(0 of 24 states)\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashwhymbslashhostileordering}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/whymb/hostileordering}}|; $key = q/{figure}{1510preform{verbatim1538#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashwhymbslashcacheSC}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSC}}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashOneFighting}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/OneFighting}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashAdvanceRCUCallbacks}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/AdvanceRCUCallbacks}}|; $key = q/{figure}{{scriptsize{preform{verbatim1626#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}static inline void rcu_enter_nohz...
...t_cpu_var(dynticks_progress_counter)++;
+ mb();
}\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashmatmuleff}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/matmuleff}}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashPhoneBooth}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/PhoneBooth}}|; $key = q/{displaymath}lambda=nlambda_0{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
\lambda = n \lambda_0
\end{displaymath}|; $key = q/{figure}{{scriptsize{preform{verbatim927#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...= 0;
3 DEFINE_PER_THREAD(long, rcu_reader_qs_gp);\end{verbatim}
}\end{figure}|; $key = q/O(N);MSF=1.6;AAT/; $cached_env_img{$key} = q|$O(N)$|; $key = q/{figure}{{scriptsize{preform{verbatim672#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 retry:
2 spin_lock(&lock2);
3...
...nlock(&lock2);
17 spin_unlock(&nextlayer->lock1);\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashclockfreq}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/clockfreq}}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashlockdeqhash1R}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqhash1R}}|; $key = q/{figure}{{scriptsize{preform{verbatim917#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashRCUenvAPI}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/RCUenvAPI}}|; $key = q/n;MSF=1.6;AAT/; $cached_env_img{$key} = q|$n$|; $key = q/{figure}{{scriptsize{preform{verbatim507#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_PER_THREAD(long, counter...
...m += per_thread(counter, t);
15 return sum;
16 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1417#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_lock(void)
2 {...
...25 __release(RCU_BH);
26 local_bh_enable();
27 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1432#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_qsctr_inc(int cpu)
2 ...
...p->passed_quiesc_completed = rdp->completed;
13 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim522#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
...69 spin_unlock(&gblcnt_mutex);
70 return 1;
71 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{DependentLoadsReordered?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Dependent Loads Reordered?}
\end{picture}|; $key = q/{figure}{{scriptsize{preform{verbatim1428#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 long rcu_batches_completed(void...
..._state *rsp)
28 {
29 return &rsp->node[0];
30 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashLinux_hlist}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/Linux_hlist}}|; $key = q/{figure}{1498preform{verbatim1529#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1 i = 0;
2 sum = 0;
3 do
4 :...
...U_READERS ->
9 assert(sum == 0);
10 break
11 od\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim738#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct list_hea...
...t, &q->list);
20 synchronize_rcu();
21 kfree(p);\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{toolsoftradeslashshellparallel}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{toolsoftrade/shellparallel}}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashManyFighting}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/ManyFighting}}|; $key = q/resizebox{6in}{!}{includegraphics{appendixslashrcuimplslashRCUTreeLeafScan}};AAT/; $cached_env_img{$key} = q|\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeLeafScan}}|; $key = q/{figure}{{scriptsize{preform{verbatim1436#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_do_batch(struct...
...invoke(rdp))
43 raise_softirq(RCU_SOFTIRQ);
44 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim705#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct sref {
2 int refcount;
...
...ase(sref);
23 return 1;
24 }
25 return 0;
26 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim654#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct memblock *memblock_alloc...
...= NULL;
21 return p;
22 }
23 return NULL;
24 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1232#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int srcu_readers_active_idx(str...
...p->per_cpu_ref);
28 sp->per_cpu_ref = NULL;
29 }\end{verbatim}
}\end{figure}|; $key = q/R_i;MSF=1.6;AAT/; $cached_env_img{$key} = q|$R_i$|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrwlockRCUperf}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperf}}|; $key = q/includegraphics[scale=.7]{SMPdesignslashDiningPhilosopher5TB};AAT/; $cached_env_img{$key} = q|\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5TB}|; $key = q/{figure}{{tt{{scriptsize{preform{verbatim2909#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \tt\scriptsize
\begin{verbatim}1 struct profile_buffer {
2 l...
... NULL);
32 synchronize_rcu();
33 kfree(p);
34 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim328#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void waitall(void)
2 {
3 int ...
... perror(''wait'');
12 exit(-1);
13 }
14 }
15 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrwlockRCUperfwtPREEMPT}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfwtPREEMPT}}|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashsynceff}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/synceff}}|; $key = q/{figure}{{scriptsize{preform{verbatim2912#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void foo(void)
2 {
3 spin_loc...
...);
17 do_whatever();
18 rcu_read_unlock();
19 }\end{verbatim}
}\end{figure}|; $key = q/{figure}center{picture{(213,160)(0,25){par{%FirstCPU{par{put(0,50){{framebox{(}{ut(45,25){makebox(120,20)[c]{Interconnect}}picture{center{{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}\begin{center}
\begin{picture}(213,160)(0,25)
\par
% First CPU
\pa...
...45,25){\makebox(120,20)[c]{Interconnect}}
\end{picture}\end{center}
\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1433#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_check_quiesc...
...rsp, rdp,
12 rdp->passed_quiesc_completed);
13 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashtollbooth}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/tollbooth}}|; $key = q/{figure}{{scriptsize{preform{verbatim921#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim653#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{lockingslashLockingTheHero}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{locking/LockingTheHero}}|; $key = q/{figure}{{scriptsize{preform{verbatim1095#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 /* WARNING: BUGGY CODE. */
2 v...
...);
17 producer_done = 1;
18 return (NULL);
19 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1487#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __rcu_advance_callb...
...g, cpu) = rcu_flip_seen;
42 smp_mb();
43 }
44 }\end{verbatim}
}\end{figure}|; $key = q/N-1;MSF=1.6;AAT/; $cached_env_img{$key} = q|$N-1$|; $key = q/includegraphics{advsyncslashSplitCache};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/SplitCache}|; $key = q/{figure}{{scriptsize{preform{verbatim1431#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_start_gp(str...
...n_unlock_irqrestore(&rsp->onofflock, flags);
47 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{centering{preform{verbatim2911#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \centering
\begin{verbatim}1 rcu_read_lock();
2 preempt_disa...
.... */
6
7 preempt_enable();
8 rcu_read_unlock();\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{CodeSamplesslashtoolsoftradeslashrwlockscale}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{CodeSamples/toolsoftrade/rwlockscale}}|; $key = q/{figure}{{scriptsize{preform{verbatim734#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 struct list_hea...
...;
14 p->c = 3;
15 list_add_rcu(&p->list, &head);\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1523#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}pan: assertion violated ((sum<2)\v...
...onflicts: 0 (resolved)2.622 memory usage (Mbyte)\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1419#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int __rcu_pending(struct...
...(cpu);
44 }
45 raise_softirq(RCU_SOFTIRQ);
46 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim928#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...nline(void)
26 {
27 rcu_quiescent_state();
28 }\end{verbatim}
}\end{figure}|; $key = q/includegraphics{advsyncslashReadBarrierNeeded};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/ReadBarrierNeeded}|; $key = q/{figure}{{scriptsize{preform{verbatim327#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 pid = fork();
2 if (pid == 0) ...
... 8 } else {
9 /* parent, pid == child ID */
10 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1627#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}- if ((curr - snap) > 2 \vert\vert...
...f ((curr - snap) > 2 \vert\vert (curr & 0x1) == 0)\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1442#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 dyntick_record_c...
...p)
10 {
11 return rsp->dynticks_completed;
12 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1444#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_process_dynti...
...(&rnp_cur->lock, flags);
38 }
39 return 0;
40 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUrt-MBwaste}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUrt-MBwaste}}|; $key = q/resizebox{3in}{!}{includegraphics{introslashPPGrelation}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{intro/PPGrelation}}|; $key = q/f;MSF=1.6;AAT/; $cached_env_img{$key} = q|$f$|; $key = q/L_1;MSF=1.6;AAT/; $cached_env_img{$key} = q|$L_1$|; $key = q/includegraphics{advsyncslashDataDependencySupplied};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/DataDependencySupplied}|; $key = q/includegraphics{appendixslashwhymbslashcacheSCwrite};AAT/; $cached_env_img{$key} = q|\includegraphics{appendix/whymb/cacheSCwrite}|; $key = q/{figure}{{scriptsize{preform{verbatim1632#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 dyntick_save_prog...
...et)
15 rdp->dynticks_fqs++;
16 return ret;
17 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim329#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int x = 0;
2 int pid;
3
4 p...
...);
15 printf(''Parent process sees x=%d\n'', x);
\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim682#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 int...
...nlock(&p->lock);
13 kfree(p);
14 return 1;
15 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1113#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void *thread_test(void *arg)
2...
...,
6 myarg, smp_thread_id());
7 return NULL;
8 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{StoresReorderedAfterLoads?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Stores Reordered After Loads?}
\end{picture}|; $key = q/{figure}{{scriptsize{preform{verbatim520#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashlockdeqpair}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/lockdeqpair}}|; $key = q/resizebox{2in}{!}{includegraphics{countslashsig-theft}};AAT/; $cached_env_img{$key} = q|\resizebox{2in}{!}{\includegraphics{count/sig-theft}}|; $key = q/resizebox{3in}{!}{includegraphics{cpuslashSystemArch}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cpu/SystemArch}}|; $key = q/{figure*}{preform{verbatim1416#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{
\begin{verbatim}1  ...|; $key = q/{figure}{{scriptsize{preform{verbatim683#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 int...
...spin_unlock(sp);
17 kfree(p);
18 return 1;
19 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrefRCUperfPREEMPT}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/refRCUperfPREEMPT}}|; $key = q/{figure}{{scriptsize{preform{verbatim649#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 spinlock_t hash_lock;
2
3 str...
...}
29 spin_unlock(&hash_lock);
30 return 0;
31 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim511#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int add_count(unsigned long del...
... spin_unlock(&gblcnt_mutex);
49 return sum;
50 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1096#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 /* WARNING: BUGGY CODE. */
2 v...
...j].c - ssc[j - 1].c);
51 consumer_done = 1;
52 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{1520preform{verbatim1540#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1 init {
2 int i;
3
4 atomic...
...: i >= N_QRCU_UPDATERS -> break
21 od
22 }
23 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{countslashGlobalTreeInc}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{count/GlobalTreeInc}}|; $key = q/includegraphics{advsyncslashDataDependencyNeeded};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/DataDependencyNeeded}|; $key = q/{figure}{{scriptsize{preform{verbatim523#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 unsigned long read_count(void)
...
... spin_unlock(&gblcnt_mutex);
12 return sum;
13 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{1501preform{verbatim1532#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...|; $key = q/{figure}{{scriptsize{preform{verbatim1489#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void __rcu_read_unlock(void)
2...
...idx])-;
17 local_irq_restore(flags);
18 }
19 }\end{verbatim}
}\end{figure}|; $key = q/includegraphics{SMPdesignslashParallelFastpath};AAT/; $cached_env_img{$key} = q|\includegraphics{SMPdesign/ParallelFastpath}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashBigTreeClassicRCU}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCU}}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashrwlockRCUperfPREEMPT}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/rwlockRCUperfPREEMPT}}|; $key = q/{figure}{{scriptsize{preform{verbatim1443#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_implicit_offline...
...hed();
11 rdp->resched_ipi++;
12 return 0;
13 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashtrackmeet}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/trackmeet}}|; $key = q/resizebox{3in}{!}{includegraphics{advsyncslashMoreThanOneValue}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{advsync/MoreThanOneValue}}|; $key = q/{figure}{{scriptsize{preform{verbatim651#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 rwlock_t hash_lock;
2
3 struc...
...}
29 read_unlock(&hash_lock);
30 return 0;
31 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1424#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1  ...|; $key = q/{figure}{{scriptsize{preform{verbatim1534#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}(Spin Version 4.2.5 - 2 April 200...
...es)
unreached in proctype :init:
(0 of 22 states)\end{verbatim}
}\end{figure}|; $key = q/2N;MSF=1.6;AAT/; $cached_env_img{$key} = q|$2N$|; $key = q/resizebox{3in}{2in}{includegraphics{cartoonsslashLD,ACQ}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{2in}{\includegraphics{cartoons/LD,ACQ}}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashShavingTheMandelbrotSet}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/ShavingTheMandelbrotSet}}|; $key = q/includegraphics[scale=.7]{SMPdesignslashDiningPhilosopher5PEM};AAT/; $cached_env_img{$key} = q|\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5PEM}|; $key = q/Oleft(1right);MSF=1.6;AAT/; $cached_env_img{$key} = q|$O\left(1\right)$|; $key = q/resizebox{1.5in}{!}{includegraphics{SMPdesignslashlockdeqhashlots}};AAT/; $cached_env_img{$key} = q|\resizebox{1.5in}{!}{\includegraphics{SMPdesign/lockdeqhashlots}}|; $key = q/resizebox{3in}{!}{includegraphics{cpuslash3DI}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cpu/3DI}}|; $key = q/{displaymath}e=frac{frac{mu}{lambda_0}-n}{frac{mu}{lambda_0}-(n-1)}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
e = \frac{\frac{\mu}{\lambda_0} - n}{\frac{\mu}{\lambda_0} - (n - 1)}
\end{displaymath}|; $key = q/2N+1;MSF=1.6;AAT/; $cached_env_img{$key} = q|$2N+1$|; $key = q/resizebox{3in}{!}{includegraphics{SMPdesignslashAllocatorPool}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{SMPdesign/AllocatorPool}}|; $key = q/lambda;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\lambda$|; $key = q/{figure}{{centering{preform{verbatim2910#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \centering
\begin{verbatim}1 idx = srcu_read_lock(&ssa);
2 s...
...ronize_srcu(&ssa);
9 srcu_read_unlock(&ssb, idx);\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim652#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct hash_table
2 {
3 long ...
...spin_unlock(&bp->bucket_lock);
38 return 0;
39 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1429#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void note_new_gpnum(stru...
...23 local_irq_restore(flags);
24 return ret;
25 }\end{verbatim}
}\end{figure}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{StoresReorderedAfterStores?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Stores Reordered After Stores?}
\end{picture}|; $key = q/resizebox{3in}{2in}{includegraphics{cartoonsslashCPU_toon_outoforder_colored}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{2in}{\includegraphics{cartoons/CPU_toon_outoforder_colored}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashBigTreeClassicRCUBH}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBH}}|; $key = q/{figure}{{scriptsize{preform{verbatim567#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct list_head *pdeq_dequeue_...
..._r(e, &d->rdeq);
55 spin_unlock(&d->rlock);
56 }\end{verbatim}
}\end{figure}|; $key = q/m+2sn;MSF=1.6;AAT/; $cached_env_img{$key} = q|$m+2sn$|; $key = q/{figure}{{scriptsize{preform{verbatim925#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...tr = 0;
6 DEFINE_PER_THREAD(long, rcu_reader_gp);\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashref}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/ref}}|; $key = q/includegraphics{appendixslashrcuimplslashsrcuds};AAT/; $cached_env_img{$key} = q|\includegraphics{appendix/rcuimpl/srcuds}|; $key = q/{figure}{{scriptsize{preform{verbatim924#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
... 28 spin_unlock(&rcu_gp_lock);
29 smp_mb();
30 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim565#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct pdeq {
2 spinlock_t llo...
...
5 int ridx;
6 struct deq bkt[DEQ_N_BKTS];
7 };\end{verbatim}
}\end{figure}|; $key = q/{figure}{1500preform{verbatim1531#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{lockingslashDeadlockCycle}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{locking/DeadlockCycle}}|; $key = q/{figure}{{scriptsize{preform{verbatim1439#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_irq_enter(void)
2 {
...
...cu_bh_data).nxtlist)
23 set_need_resched();
24 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1633#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_implicit_dynt...
...8 }
19 return rcu_implicit_offline_qs(rdp);
20 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1233#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int srcu_read_lock(struct srcu_...
...ier();
11 preempt_enable();
12 return idx;
13 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1526#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 proctype incrementer(byte me)
...
...ounter = temp + 1;
8 }
9 progress[me] = 1;
10 }\end{verbatim}
}\end{figure}|; $key = q/nomath_inline}textregisterednomath_inline};MSF=1.6;AAT/; $cached_env_img{$key} = q|\textregistered|; $key = q/N;MSF=1.6;AAT/; $cached_env_img{$key} = q|$N$|; $key = q/includegraphics{appendixslashwhymbslashMESI};AAT/; $cached_env_img{$key} = q|\includegraphics{appendix/whymb/MESI}|; $key = q/resizebox{3in}{!}{includegraphics{easyslashMandel_zoom_00_mandelbrot_set}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{easy/Mandel_zoom_00_mandelbrot_set}}|; $key = q/{figure}{{scriptsize{preform{verbatim508#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_PER_THREAD(atomic_t, cou...
...lag < 3)
48 poll(NULL, 0, 1);
49 smp_mb();
50 }\end{verbatim}
}\end{figure}|; $key = q/{figure*}{{scriptsize{preform{verbatim1112#preform{}{{{figure*};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure*}{ \scriptsize
\begin{verbatim}int smp_thread_id(void)
thread_id...
...read(thread_id_t tid)
void wait_all_threads(void)\end{verbatim}
}\end{figure*}|; $key = q/{figure}{{scriptsize{preform{verbatim915#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...}
27 __get_thread_var(rcu_nesting) = n - 1;
28 }\end{verbatim}
}\end{figure}|; $key = q/dagger;MSF=1.6;AAT/; $cached_env_img{$key} = q|$\dagger$|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashGenericRCUStateMachine}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/GenericRCUStateMachine}}|; $key = q/{figure}{1499preform{verbatim1530#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ % \scriptsize
\begin{verbatim}1 atomic {
2 i = 0;
3 sum = 0...
...RS ->
10 assert(sum == 0);
11 break
12 od
13 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashFlatClassicRCU}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/FlatClassicRCU}}|; $key = q/{picture}(6,185)(0,0){rotatebox{90}{AtomicInstructionsReorderedWithStores?}{{picture};AAT/; $cached_env_img{$key} = q|\begin{picture}(6,185)(0,0)
\rotatebox{90}{Atomic Instructions Reordered With Stores?}
\end{picture}|; $key = q/resizebox{3in}{!}{includegraphics{cartoonsslashwhippersnapper}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{cartoons/whippersnapper}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashTreeRCUStateMachine}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeRCUStateMachine}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptValidation}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptValidation}}|; $key = q/{figure}{{scriptsize{preform{verbatim1235#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_srcu(struct sr...
...onize_sched();
18 mutex_unlock(&sp->mutex);
19 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{lockingslashLockingTheSlob}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{locking/LockingTheSlob}}|; $key = q/{figure}{{scriptsize{preform{verbatim707#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static inline
2 struct dst_ent...
...dec();
15 atomic_dec(&dst->__refcnt);
16 }
17 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim922#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void flip_counter_and_wa...
... 35 spin_unlock(&rcu_gp_lock);
36 smp_mb();
37 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1114#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int main(int argc, char *argv[]...
...threads completed.\n'', nkids);
20 exit(0);
21 }\end{verbatim}
}\end{figure}|; $key = q/includegraphics{appendixslashquestionsslashafter};AAT/; $cached_env_img{$key} = q|\includegraphics{appendix/questions/after}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashLinux_list}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/Linux_list}}|; $key = q/L_N;MSF=1.6;AAT/; $cached_env_img{$key} = q|$L_N$|; $key = q/{figure}{{scriptsize{preform{verbatim1430#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_process_gp_e...
...ed_snap;
18 }
19 local_irq_restore(flags);
20 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim524#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void count_init(void)
2 {
3 s...
...idx] = NULL;
34 spin_unlock(&gblcnt_mutex);
35 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim2901#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 long __thread counter = 0;
2 l...
...nt < nthreadsexpected)
37 poll(NULL, 0, 1);
38 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1115#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}void spin_lock_init(spinlock_t *sp...
...spinlock_t *sp);
void spin_unlock(spinlock_t *sp);\end{verbatim}
}\end{figure}|; $key = q/includegraphics{advsyncslashSpeculativeLoadBarrierCancel};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/SpeculativeLoadBarrierCancel}|; $key = q/{figure}{{scriptsize{preform{verbatim1438#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_nmi_enter(void)
2 {
...
...18 return;
19 smp_mb();
20 rdtp->dynticks_nmi++;\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim788#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct profile_buffer {
2 long...
...ULL);
25 synchronize_sched();
26 kfree(p);
27 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim953#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct countarray {
2 unsigned...
...x);
68 synchronize_rcu();
69 free(capold);
70 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim516#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 atomic_t __thread counterandmax...
...< CM_BITS) \vert cm;
32 return ((int)cami);
33 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{deferslashLinux_list_abbr}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{defer/Linux_list_abbr}}|; $key = q/{figure}{{scriptsize{preform{verbatim1486#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int rcu_try_flip_waitmb(...
...rcupreempt_trace_try_flip_m2);
13 return 1;
14 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{tt{{scriptsize{preform{verbatim1195#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{\tt\scriptsize
\begin{verbatim}1 struct el *insert(long key, l...
...}
23 p = p->next;
24 };
25 return (NULL);
26 }\end{verbatim}
}\end{figure}|; $key = q/includegraphics[scale=.7]{SMPdesignslashDiningPhilosopher5};AAT/; $cached_env_img{$key} = q|\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5}|; $key = q/{figure}{{scriptsize{preform{verbatim1117#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}DEFINE_PER_THREAD(type, name)
DECL...
...d)
__get_thread_var(name)
init_per_thread(name, v)\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1628#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct rcu_dynticks {
2 int dy...
...ks_snap;
10 int dynticks_nmi_snap;
11 ...
12 };\end{verbatim}
}\end{figure}|; $key = q/resizebox{1.5in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptLists}};AAT/; $cached_env_img{$key} = q|\resizebox{1.5in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptLists}}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptTimeline}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptTimeline}}|; $key = q/{figure}{{scriptsize{preform{verbatim1422#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1  ...|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashRCUpreemptCounterFlip}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/RCUpreemptCounterFlip}}|; $key = q/{figure}{{scriptsize{preform{verbatim914#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 DEFINE_SPINLOCK(rcu_gp_lock);
...
...nesting);
5 DEFINE_PER_THREAD(int, rcu_read_idx);\end{verbatim}
}\end{figure}|; $key = q/includegraphics{advsyncslashReadBarrierSupplied2};AAT/; $cached_env_img{$key} = q|\includegraphics{advsync/ReadBarrierSupplied2}|; $key = q/{figure}{{scriptsize{preform{verbatim912#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...n_unlock(&per_thread(rcu_gp_lock, t));
18 }
19 }\end{verbatim}
}\end{figure}|; $key = q/e;MSF=1.6;AAT/; $cached_env_img{$key} = q|$e$|; $key = q/includegraphics[scale=.7]{SMPdesignslashDiningPhilosopher4part-b};AAT/; $cached_env_img{$key} = q|\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher4part-b}|; $key = q/{figure}{{scriptsize{preform{verbatim730#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 struct foo {
2 int a;
3 int b...
... p->a = 1;
12 p->b = 2;
13 p->c = 3;
14 gp = p;\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1231#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 int init_srcu_struct(struct src...
...);
7 return (sp->per_cpu_ref ? 0 : -ENOMEM);
8 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim673#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 void thread1(void)
2 {
3 retr...
...pin_unlock(&lock1);
26 spin_unlock(&lock2);
27 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1441#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_implicit_dynt...
...8 }
19 return rcu_implicit_offline_qs(rdp);
20 }\end{verbatim}
}\end{figure}|; $key = q/{figure}{{scriptsize{preform{verbatim1426#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __cpuinit rcu_onlin...
...softirq(RCU_SOFTIRQ, rcu_process_callbacks);
14 }\end{verbatim}
}\end{figure}|; $key = q/resizebox{3in}{!}{includegraphics{appendixslashrcuimplslashTreeClassicRCUGP}};AAT/; $cached_env_img{$key} = q|\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/TreeClassicRCUGP}}|; $key = q/{figure}{{scriptsize{preform{verbatim336#preform{}{{{figure};FSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{figure}{ \scriptsize
\begin{verbatim}1 printf(''Creating two threads w...
...
18 perror(''pthread_join'');
19 exit(-1);
20 }\end{verbatim}
}\end{figure}|; $key = q/{displaymath}T=frac{1}{mu-lambda}{displaymath};MSF=1.6;AAT/; $cached_env_img{$key} = q|\begin{displaymath}
T = \frac{1}{\mu - \lambda}
\end{displaymath}|; 1; perfbook_html/img172.png0000644000175000017500000002701411672746010015307 0ustar paulmckpaulmckPNG  IHDR^tRNSىH IDATx]$uzG.24t,H$ E#ES D@3 hцkb dځ=a4؀Až!!ڐ%*_\!-e*4 YW-9g5yU]]=ӳ;U۷8{$,4=mF^dGa=?:)XC@I&F՛. >-&fT YT 03ٯC{=Q \ \o}U>Zz>p'GGcT-M}Ŀ_i~6 p!pkZNf 5jCG^5W_O5OVVEmKkȴxu`ֳtK/pFQׂ<J~CaN)Cq#S?38E_[ ^tj^CTCx~fsc 6M`{g'+4pctb |w.Ǵ<>kְP*:{}3虐fTif*`9Ժ y5 '̊ە*nuo p&5-GϘ`}f|x?SZI#>9:('Lӆ?*`99|'!{(jQ0D4bX͚QiWhF0A5`[ìSm] gV\XhԱ;#LNS ~g'l6i=P"weBTƤĀ re ZcT0h E1DʶCƪPgAAWVafɲ{=}"?_`q 1Pd86.x+M¿wM ]/S~:4qA鄛G. &)a~ s|+7~8RN pB`kU zA^n1{HnhЧP ׀[ʹk1Pd 0ܹ0(<\x w9ǀp{ε@K`Z@ iw`;i7xȝ =g7+:i2Nt۪8jz sBYߵ `k۶#|Jk_Q3چۯx +M# įa -%vC)lѩ)01 XDG6& Dbإi?bw8f{J[\P3J(;jbp|_fgqIlT%]Rv".Ap4(տT°tˠCBq,g%O3cbl}C~^y&)y±l, `{gÅ]'('! 4ҽ! WJh.P̪0|JC,U#OLyb/zw& r,le/*LN8_f9`[``6B2,pULwՎ$m{MBbE5Vt_~/<* 0m's :R%.h;Do -_5_ {dzֈ |qj"![)E,Z!%!unÛӪE׸4<{@HOE6{*V?v}v$Z2njU;>}b$%'h"O~y+7w\AA MAUW"|±;v'H(^m7oo7G] .f=~x9H:#HZ a*䯴'?^lWC=P8!Xl C]GMa҅ѦMSլ0!0n;FѹZ}8a䛫/, lHs+8-V/հ/z+ط,%+?A؀h=۾נ M6E/EzI.Zt"\ ʦuiz6]!bMqXteͦ_`DDcօm;.fZNؑh ]>j&b;Z )lzg @`as:8 zN`j됥`2?XT"֫U{;8XZEzPǺ2 V#hOR/`A5F@tjtm@2& P_vV-vǔB[;HOlhι{Mܿ _f뚆i_Fmh3{뫏]FsX~lܯ_5-=A ͮ%w38QlOP` wڝYTaala8juQk`Z=x~̩WP\yn9` _ýG@wp< ǃrֽ )gAh J__?,ﬢ}8fRPz% nabF&SkO Vk&o h^pű/a $ǯ#̱XIFoX}c!{r' yV[ H%VsqŭFB0JpHUPR{_E\ņ$7n*h^֪Bc*K,GoB%?FW|/{)҇%-e N6\ctZ6*6Fm 0-a* lÒĭ^2Hn[aD4+ Ua7Fr4&n@׹lLk_$ Q{]eX,Ʋb?jeJk"N?Z-~_\~}zGx&g/k|MAM~vLrң88r*pyᙳApXiY8xxb"ʤ./s"Hnd<~ S+"  $n6a"4u#;s (t@@RwxvU3QpAXݥ\I|揖MDh_^8[Q tn6cNökuۮՃ{mUl~۷߾}El饯o޾}/HMI7/'_j,{];z ΌgA-{"4kqP#K˜-[{\~WJ8jO'3J%ﯯ)G @5hTV 0F|oZ0{džj%S!4M MebjY뷊Z WvU*ҊtkKMvZT*ALYET+T? N6_( ă_8:J/e ) ׫\n&:gS>7h6=KT|Sj/o J( Uzc m/k8C kh =zڷuXoxӈh(o0T(8V)e/JY{g#OtaQ?(:xpT@?½8,ƬOUk4k4k4L6]D M>X Vm/FG+T[7}%ۮ9v֐ ']JΉncrk\' 7A6m Nï#\ aaYg{ůC[D<:~֌?7]h`5&?nta]4}%owt~"ftdJ7䡃EC=`N_s^ea|ǣ J⯀GnX;T0Gwx,]D.\vϳ7o7t}{1Z r2Gp;!qc1.=o l]G0Z]~L*vVGhA`ymo؞b4+Qca;^:P+ Syd|"']%-jۭ-0s50tWF\Al.-(j8͍D[£cGcii/6Տ~>[gū}'gAT>k+oZݦ4tӨW7r]d>00[TlcacWd^ڳǪ7۷o\W߼j+isVm',V3 Ko#o .l ۪hT~W{o`~ܳ_RF/5[MrZȗ{%c4rX'_IYI- ?YFZg=q>ɓ Xa"`B)FG˃fA:/5JU*[Ԝ*gAݮXJŕh>SO2e`(P"ARd0$J@@2՚+5Yo0NXp`+ңQpY"Eh\~(ހM`ۋWHX+ߦUYINY)Y2y0Q|^{s=Z9j  :* nG045Yvs*Z"N;g>&iX/5"P#l3AZ*L_I9^\?d2 _'򭴓R([IJ,EYqpWA5Ui_TjkݮVTz&hi" G!u~;R>BW9Khx6Nwͧ q@ x[eO  ltp!uP-є ʮc4Pn)0]j ꮶEKꝫMGĄB}iЗf1$,m¬b~Nr1dF=vr b8(]?=%fD>z ϸ嬿N'h+îIϏB WO&TTq9s# +Z:Phxmdi0YeN̏-4UgۨrC$r/ aA>Z;(W1@ puXt1-iڶ'D"vf jȏkoBآFӶPn&1mqB?JD}Ť&z6-n>uei/}htI/_ώ]YƤlE{-84Y~tR!A%~>[Z8 ]LRČ` Nk׫a^a^a^a^a^a^a^a^akY1c6j \/%{z R[Vtbn],ڡN|MkDvҥG}Rӷ0]]4}ǐ5(j2a'2R`Yow芘<F74#ߤ`5o[Ft?m&&Z^2ip-,4T Nj'ԅܐz1=jn֬:Pl-f/Z7H-|]I X ke5\WFݾ)TBtx"XNsJ.}SմPID曆q9~{JY{w<:j\qwKƯvӞLk)K;F vv;2XQj*$QX-U JyˌQ14MUF_'h*Ux`n.gFX&fh2p}Q ,FI^ P)<~E`4DYOsqRߓDXx.,?Fk^~s7^ dIީTI+Vfs~]?~S )МFüFCeNq0GÙRKNWwg΄;[$uLG=s0DXX,z"Ѝ*1({ 5>2G)qꥯ^P/)ܴϪY8Nz}uzɃ_8A)5%mL@#̎S[ײ5F,l IKTKb_wUx[Ssmn#c5g5Fїva)U6l{[URMj:^ j~U8LK2m >Y1Q5^qvWЈڈqjj̺(+/x4ؙVMT:MݮnЬW{nSjqzW -huÐIԌr:1'E6llԥ*i,־Xn7*-'bkȤYO WìKo]~'胼m1j0j.%kpjOJ!@b' RIYɛVf&\zћ/x{ҝ({0 ʓ6ՌǮ %S)-k&*tpՔ݁yC<:ȷA IDATյJu(1ˠ_j_~%hZtkTq*j:' t*XyK4Dkj+Dx}cJnU:jfGuk4RzKUԺd(mwQ D$yӱu+_{P c"kfwUܕޗfir,G)q,O49V9Jă;9q 6{ͬ8a'.}rp,k*Z~byySqO(ʥTw핼uZ'ƄsSoE^\q}2DŽ~|,wzT^o y}"h1=[-ڭ[]$^<ϻx)੧{*4H_^zFggѱoGovr xs(deW&pq)^D+k'c{3cr+0ep5sСkwjZ,~$+W}^eU$2w:\2dkjva982ӌ0-kkv׬geGW_k_b#At߭'lK׬G3DQL Ǵ1Q xoo]\{WykxGxߺ{ڣG ӿv}/x~}]i¶G柶ד1Gp.T~L}nA> >;M Q/iFؓno6E7|$JY"Q9IJk2 ע7 ?UbS$Hu|UmC'Is̐DZdP򑄚%3D2o%Srڟ<Ŧ |I3DKKY%Œ "+ed0J$MU:*~ HxԻKu,GeM**/mg͇[Ϛy̿Tz *ݱ01x?#˙5_^yXl@<s0 xAvMmߊc#=eaܠA 1aj<dJT-$[4f\rܷ.^>zCood7R`!^*v$X}6O_!"}3 rOzi/ g,gB|?c ;+9C>r *g{r,˛C3kKWb(:XSR`#ejLHR IVKnGI#Jw%28B#vՊ4+Oˋ^:K9IckqfZ=ҩXUp C]f@T#n{(h0QGhԻ+*6n E9n'3];bõ̒q̼x᧴zEػY_Rf:BEWChnj?8emJ^ȋZo5,km%{zyb<_`g]c}8µ{v;Y=IJ=zҒc#Vi/i/Uy &8UL^N~i~ .x_*;m#>l[bee 31a yDۻ*8*s /I^ys3<Ǥ8iG/zDduh;(f՗(U9`f^ +`Ft;ecY0fhz(O>ǣO>9*<9Y;Ubc`F/Z{wZru@ck_^͙yp1Cc7D&} 翣>*1"fMs礞cp:@ 8NkscSĜ"51g99{1Ek)t#m\a;311 9id/TCOǖ&CN||I{L,4[p!x'ל}4{nA1@&$5FZv#Lj|dE>LU<_KXJיYD- kD>6؊/dξ6,8ڮV*f⡯嚈XW՞E_kqU l0Z#qLڭ\JY]O f9 ,uskD>a>_Ȝ}J~O՚T! %*iV4_.~x׿zx'Ggcm[FmǖwF1_?V>jv-gHXoΞ]SQLwVU뜆ח34I-{|ߵ~ IC8k;FIKXk_#(+DVgb2iTޘfj4lq'|LvoQ\˻= i\'ĥ^K8s?y-#?TGժeSXN7N#{I))ؔq W1YNMc! UTۛ+JQJI,$ŦK0:IT&c$٬0hvՔYLֵֺ(@^cU}m39`=jTt1Vq-WZ `4wnGr& v?{$1cb%G+0} `tcY4uc\nisfIENDB`perfbook_html/node143.html0000644000175000017500000001171011672746162015642 0ustar paulmckpaulmck 10.3.2.3 RCU is a Bulk Reference-Counting Mechanism


10.3.2.3 RCU is a Bulk Reference-Counting Mechanism

As noted in the preceding section, traditional reference counters are usually associated with a specific data structure, or perhaps a specific group of data structures. However, maintaining a single global reference counter for a large variety of data structures typically results in bouncing the cache line containing the reference count. Such cache-line bouncing can severely degrade performance.

In contrast, RCU's light-weight read-side primitives permit extremely frequent read-side usage with negligible performance degradation, permitting RCU to be used as a "bulk reference-counting" mechanism with little or no performance penalty. Situations where a reference must be held by a single task across a section of code that blocks may be accommodated with Sleepable RCU (SRCU) [McK06]. This fails to cover the not-uncommon situation where a reference is "passed" from one task to another, for example, when a reference is acquired when starting an I/O and released in the corresponding completion interrupt handler. (In principle, this could be handled by the SRCU implementation, but in practice, it is not yet clear whether this is a good tradeoff.)

Of course, SRCU brings restrictions of its own, namely that the return value from srcu_read_lock() be passed into the corresponding srcu_read_unlock(), and that no SRCU primitives be invoked from hardware irq handlers or from NMI/SMI handlers. The jury is still out as to how much of a problem is presented by these restrictions, and as to how they can best be handled.

Paul E. McKenney 2011-12-16
perfbook_html/node204.html0000644000175000017500000000665411672746162015653 0ustar paulmckpaulmck 14.2.4.6 Pair-Wise Memory Barriers: Non-Portable Combinations

14.2.4.6 Pair-Wise Memory Barriers: Non-Portable Combinations

In the following pairings from Table [*], the memory barriers have no effect that portable code can safely depend on.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node179.html0000644000175000017500000000472611672746162015664 0ustar paulmckpaulmck 12.7 Performance Estimation


12.7 Performance Estimation

@@@ pull in concepts and methods from http://www.rdrop.com/users/paulmck/scalability/paper/lockperf_J_DS.2002.05.22b.pdf.



Paul E. McKenney 2011-12-16
perfbook_html/img158.png0000644000175000017500000002377711672746045015337 0ustar paulmckpaulmckPNG  IHDR TPLTEb``MJKPMMFCC<99# hffvstommmkkXUV856iffC@@A>>wuv.*+tRNS@f IDATx]rERV[gF݉/QCY B'F\xQȥK̚Xy,ۦOM1wQO(/uvq:)|@ҩ[~RQ= JC |Eux60Jrz3-Z$QmMP>,\sGH7,=q-Nt|kJw4{5PPѳMSB#bq +l']WNt>Z(`.=)*5RjL78yޞFtzlw̷"9.E~U@"ZH;o ĥu i@q2ʞvohIg;TLa8p0~d[WMAxv&GvyE`2sC^} 69E-^=Tc?T~ 6\ha6SXp6,܆Zk8 G'w|$eZ(RN nWm+ KVR]"r ׈ ^硱Ufljj*9bR]Lmz&,/4^۾~t}݅kdjHMen=0hg:z|2g-up'rfl)jpfYm W ޘu= GqN(8}E"el_gȰ琇cu, XrcvG-ߚ1XRJI/PfJMaz#$`1I'Q`Y{J7hY9= ˪TuZ#BWS]cUvVzf}V`BuQHQ+3,)2Ft7Sӓ)\`hcl[Hc%&/L^PoyZ*h{^ZZ:6ޫa /Mڵ%.-))N JFXo./wkvjܛ>uƯk)\*|Lh9qzܺGX?xբd:MHuo*= X̛HXH$ )`wh˻ Β Y'1B.)]k.32ҲF&\EEg2P:-WP3tM'_(dh>Ir_'Z >Ja6:[l'Sh3=[!U>s< E[΁6hL0Ml|<2%Eɚqbx^8רi J\RF栄6mc{: \lw{j|BSQ>VQ'a^VcEV(Dp?H [R#EgY|?SQ 9xiN<`)Z*ӯi=;$Nv(YZU7KtfN7M pE\הB)U،TTqX- %*ܟۏ$(#}<"hyO1T=<ikgd&QJ Ͷc?ۈ3P&v#)IlL-!ܙЖK8gX lc,F4TRE_&yWf)2wGl4Vmidk-ueJZ){ &M:)*aГmR.: tXOVKHFYyy" g:l.i 7Hf:4\4(u}J-7FX#!}#M- wݐ*j'GYVZe>Bn'%2`]S1 HQN%8!4z}1͝8Dr:AMoߥ,{ \OYPszR%iP۹#@H%Ѳ\Py8GR^>eG@`~N7TsV7&gwq=NONU\7dhmɵ)ݑXU̙7eM9jidꬊtC,dsR[AH6|q smF:!_y);h1>I]|7uhs^q-R3K[^Jeh-ء7!~yFUb>NTZB'ᵛNk`*{owasaď7ر_Ҧ>qY0Qb"sg HIGwEdVUҸ8Mz^g{.r9C(gE o"A {ABhigI*L%.e;CeqУmD:¦0o>>ii<-GR.\oimxDEFwiG G]8B >OX`qV P7N=3 )*GcQ[{IsXV %nN7a6Çskب" |,rXyT@"sL~idSq qNQQ>{=b諸GqǗS/~tox9wD:Y 8Ȭ9k!%fFP@)BN8Zi!:$,V$Y4oǩ| 2"̭quZ"Ґ),)# W n$.Cӷez2Pa{- ׺4Vr:Z,"̜:=1O=0n˜MDfckOj@hk K@C-qL ?-&} >y*׉-#_Ĺ4V$b16嶃 J6]>NSǷ9ZOW Sm IZ|\ +U)zUGGɣdш4ToXrJ"3ۙms!MRDrEj#2}4&ڑKȎfg/ϏL XlpS='Kc&ʶ+G#֑ۂ X=V\Nd{ h,h7<\S;JN#, h콒pۥ_kң$roҕ}4Ex!W 89(_~޿v2H@g|wΫE*$)0߼9Ls&0oH<_g[Nkhh ]xܿnx9QOP/Te7T߉&JUp&LrX]gO? `?. "3(ar޸* GFRN\Jk"br^JUt5{',>L2@U ~`'*\~W2{) &[D>^aMa J$Uo{- 18V%CIT)42V:i aH, ̌mqv-YN,xD PJ̄W_ш~D:p48'*]2v$ZWXF)ښ}F5;J`4vH!?*9p]HU|ZbK֏!u4}͎_5{Y t*c5x^Ť2{oE=m Lė ><#nnz5[W5Eߕ\ᲁ> .i'UZVϽmxl?z]K(4 # u?:{Z^"pOơ*"DhTț^ DK,CƍP9IYH *&iTn*Yu u)8 }%QI%{hBd='zSl;nHLڝ~$eG^$H=#3V6oqaw|,cI; ٲ4A5ڡu,bi6HC!bdI:\r GT.]WU+, ɭawAHT#z)] lױ6m' ~m+};LXCﺶck&\cq7 +kHv-X>sVzaZ@wN=&`(/سYwG&$,6t Ag \mbso (O90i),qlmA$sB|sS (K+fO$_ `hKӿNQo/oƒA fsha^DT5^"_9[\qsRσ!kѱޑ)q !H)l!y1ÌUS0>«OIh~q@)fLQ?d os C dǏ Y>o7H=EWD~<Jg!sƍM`P^5@twܸq%bȂ9'}ޓq'Ŧ3ӕ P{ ̩wk7C%GN˞<5=]I (E֐^;kBgBd܅Cn 17(;=d> qwR&w*hmŘ_Lti;܉Ǹ q!oA^U7CYA!f67nx+ ͊Ph)N NYnS׏鬚ÚJ"U|׮ҹ| A̐9,uY>C52訇H2;Tnͷ_{Ytz,n .2 _1B}NG]:3SsO00Ԭl]gಹ!(9v6(B~KGr,zMk0J?fTS#|ޓKG>| c'ITԌB!o {[޿L?8d]KÑ`Q64Óq)S09vXzTY.h]|_a2,ae\L6LF8dEC|ha}iC" 'pM2Hцȱ!fެ :f]?C̼YwY!f7ñ̜U t[äOs .K57NRMn&8 p~ E Qeuw/0Vz! ?aoܸq<*Č!3 I3C%!f1=ȏ(_$eAL,x~@ڨQR&k!)I@'2Ve%\2 nEm6d-5rs0, LBRKNd 9 PX!RRɘNBܜ+ ׵dg̤.u[n>)F;-7oӨUO: 7Td'e^̐ecaƕtW:$FW5xɪ[@ ٦bG\{w 5AƆ)-ӵKU8t'_ݥ1OJf) 2ML31ƣ}(6?y7G'a7Hח)AP D!j|\q:Lk09 2ݵ.%{$C"7^ӕG_$/a _E!VNr4Z~)hspbE :$n 1m*8lVD!f`ͧx5 (#[0Bj .e! $l&dALIڪ8oU_(K)|QQ`RU=ˆT";A8,2s=㈯d 6! C,xU=0]EcwExd3K= &:όPjLμPG ^fi"|ޑE,S(Jva!y@ D]c=Hia4/ʬף@R}i30>z⋊A4o:<#FHǰ;ΤZn{@!Dt3$ ^5ΠJ;Y s_Z 6ms1+kk*HX]|M Jd^p 3&s_T%h!ڐ/gC^DCe&A{&22c@rCfL4G5` ܾZ2-(OgxSyq$NM'⣜t=#Pt'?| h:LLz+.C|F`iȩN~ gLn!ؙ&l P_/a5!(?~9usCf@6[ȯX' GQ&8~ uCflJp4D" e^9gya?aZ% m* 0!pd)ӸY_]'u x$e*ycbq B416Eu0oNw,d^m⌭Cƍ3RqbcyٟK䣩DB|) D.3.2.4 rcu_process_callbacks()


D.3.2.4 rcu_process_callbacks()

Figure: rcu_process_callbacks() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __rcu_process_ca...
... &__get_cpu_var(rcu_bh_data));
29 smp_mb();
30 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_process_callbacks(), which is a wrapper around __rcu_process_callbacks(). These functions are invoked as a result of a call to raise_softirq(RCU_SOFTIRQ), for example, line 47 of Figure [*], which is normally done if there is reason to believe that the RCU core needs this CPU to do something.

Lines 7-10 check to see if it has been awhile since the current grace period started, and, if so, line 11 invokes force_quiescent_state() in order to try to convince holdout CPUs to pass through a quiescent state for this grace period.

Quick Quiz D.31: But don't we also need to check that a grace period is actually in progress in __rcu_process_callbacks in Figure [*]? End Quick Quiz

In any case, line 12 invokes rcu_process_gp_end(), which checks to see if some other CPU ended the last grace period that this CPU was aware of, and, if so, notes the end of the grace period and advances this CPU's RCU callbacks accordingly. Line 13 invokes rcu_check_quiescent_state(), which checks to see if some other CPU has started a new grace period, and also whether the current CPU has passed through a quiescent state for the current grace period, updating state appropriately if so. Line 14 checks to see if there is no grace period in progress and whether the current CPU has callbacks that need another grace period. If so, line 15 acquires the root rcu_node structure's lock, and line 17 invokes rcu_start_gp(), which starts a new grace period (and also releases the root rcu_node structure's lock). In either case, line 18 invokes rcu_do_batch(), which invokes any of this CPU's callbacks whose grace period has completed.

Quick Quiz D.32: What happens if two CPUs attempt to start a new grace period concurrently in Figure [*]? End Quick Quiz

Lines 21-30 are rcu_process_callbacks(), which is again a wrapper for __rcu_process_callbacks(). Line 24 executes a memory barrier to ensure that any prior RCU read-side critical sections are seen to have ended before any subsequent RCU processing. Lines 25-26 and 27-28 invoke __rcu_process_callbacks() for ``rcu'' and ``rcu_bh'', respectively, and, finally, line 29 executes a memory barrier to ensure that any RCU processing carried out by __rcu_process_callbacks() is seen prior to any subsequent RCU read-side critical sections.

Paul E. McKenney 2011-12-16
perfbook_html/img319.png0000644000175000017500000001472311672746025015323 0ustar paulmckpaulmckPNG  IHDR>6tRNSىHIDATx]?n9A ; YL|o>} lFBOl`t97 ]${_7bHPIFQh (w^ IB_4M^Gxmn%Ղ'_:H~kw{ӄ$IThIiAp دkM]}.7IɈ"J)&NQ+4 T>eA53IB:NUD/+fOj#hj5 /M4iko[h1)'458Ew@Dی@0A2޾<&~ciVޫ5SBb;]ȪA ݾ9ۏn?&S4SO?+O̓lזMoz~ *׹εoM>I{(Rzij"|>`%= nGw0>͍eTkJc§c>: 9.BCK..l VI™Y, :fo4 SFSǿnb,pKҿlOm+y/IkBƈ)?Iľ8* LM°p*G/&Ke7|Mt.)&&#6n&ę 3jz(!&|4ˍBEAYiwY>uIj y>-gcK Swo;| */B'G,=qO(#gC1b7JdX־eD3;/>+aY}pea%uN0|a 09{8> zΒH-AGxsF#ߟh|T-:mKN׵2ߟV{_%]4MF/Erq{dϳ.l4i3`';-̷Dx]F@ i@pFhˊGf.:hN LZ;wnN <FZx Xw͖QGa>Nȟ!ʷ'F }@a{ZWÉD.x~sGm]qq{J$$D>&[mԬ)5t.}D '1wb]"0˄V)xzR5Qt8%T삉"0Իc.4ēuըZ' (E˝.Yɠ%-&/m^e8$8wZ/=.w5>]?_J M빱=Q7?j5F1NLs}}wQ\ -ܮU.j)!*c!<,8t:\[ij[ N6#q^u# ~9. 0 h );8C4G2ngr)GlF|zW% T'߮B޺Z&j]> &X@v@jOVDMx$?@\|/ iBP^Baa4y! Ѹ`b D FTG!%B=)^Q 2fFԵa)@)*&Ebۯd@v\4%<ʿ1 xd6ֻʀxeLAjFBYL(:,lYPOtBkuOEJRQPOE<洽(Uiϣ%SZ@y+ (a7 RX_>_k{zg-_ʧeU7s oQ> g#&zܪ T<77hVj6f`D.]p~9i(XϨD/|tbc(;K 08}V mi5ZC፿S^a"l]xK*e34Ͼ/Fy/d…9ضq@>¶3*d̳\Dх2\.9Ifnxr؟8Y{^`3Կֺ #\toyӀɵY<]I7Ѭ`Sz+!8DuG]hH:JǺ2gp|!˄Fx,", 7kky^DZD9zKҽ׆NW=|<;sH>9)r}H?B8d@qH>98yxd ~ ?PPm'Q<- sW&EV!ģx>Fa~qulat.MT^UGha%&TZuZlNdYcQ{ke}|~1t~lM)Lj|)YT!( ݹ'MJW~efTdtHGIi4^"3;> # 6 ym-A+f>ڋUVt 3%' rpv kœ~G1&idkzYYe-qpŭ|k+Lsq=Naj;K}})Sg_Egu_≯()LuW_MjţϸR>s;(P{dᘋb:y~ M2Ќ³>RL=WWo߾?8e:_?\)*Lܿ=T{E&Ol%4Mz!G{r4jO*T#v1hطS >C)-/x9;LN?|ćw %Oۀ<3b%锫=Jo< Tmߟ̶4?WQ=ߣ]k-KjXˡir 'G[XgbX 25nrg'+T"wnV|r#vٴa32I״1k'%q@Ź[w;f`e){O}Yڰ ԞIa3q Zm{ p`Ekт}HffSݶh'@ R0яUt *S㋧K:ݻ2؋uj,v(^i,38nwOT)8HTg%6T-gT׳9ɴOj^qFRmYD>v牉}݇ל>I[}N V{vo|N:~1G7N`{tO戫4'119:tXţ`|+~:ўw'Hpɶ5*JΤ=qKNI%屨6$<=w#V:%yd}>rF V{,0Q'ꝆRFnQߙ$VK>)ʅn'-ߋ|r\߉|kV>䓩ZYQϹJ'[jsfЀ\egmOma)HQU$~KVqȂjNxȒv<\{œ_!򠀎ۮc<$IBFrVlטc;2aIJ5l~R8< uY B/bQ. !J8M@;VQ E|>l8>0```2_6Uz TucT`` KŢ c@2EQJGIENDB`perfbook_html/node201.html0000644000175000017500000000653511672746162015646 0ustar paulmckpaulmck 14.2.4.5 Pair-Wise Memory Barriers: Semi-Portable Combinations

14.2.4.5 Pair-Wise Memory Barriers: Semi-Portable Combinations

The following pairings from Table [*] can be used on modern hardware, but might fail on some systems that were produced in the 1990s. However, these can safely be used on all mainstream hardware introduced since the year 2000.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img99.png0000644000175000017500000001736311672746105015252 0ustar paulmckpaulmckPNG  IHDR&KPLTETRRMJKPMM# b``mkkXUVNKLMKKJGH856KHHC@@wuv.*+|zztRNS@fVIDATx]riZ#_T(`svbz0`L2V1ΘbG ]NݹҼa`({j5μUoߵ?R-kDZQu=r;Fm[/)S u֬Qj}[ㇱ]hޟ}]b{UK욕\?Xi%WUT{Y~W<E{d(rvPaPGT%3!<ˁ92-H׮f*~3lb{`~gxm7pvzL@+VmirZ{IVT>Ț +N xB7P _=6k†YmTϭħ(U:cKq&8Ӵ0ء$cdoKSe}0-hm!#]J%U+-R8EkjwV{*V[/XKџDYU:WZ%Z-}>N7< ?W=a0h^//gYVbk_jH$lՑ~dc֯Lޚ 3EL;o*\c]u~4fdGf/`l)i|O&1Q8!x!쟑Qm!I% bO283%9¸BK:X60`% Xh,c^ȷ;y3g >PժІG: X=J[:Myt8i[vh4yu0*ھdYMnbo[w_w9LӞ Q(d tC4Ł<:b׈7x *:ٳ:M}T9WVk <`^"땕ReǴQXR pt+r7veKU %G.kvd4/tUۧ}(+]d05~(⥐tpN*.8Fy%}/W;2V6 \RagfIcMfuQ7q_JsHJӋŨELQ9' \ _$S^\t5S7 Xp 3'R>!Tc&x"B87njQYE;ӧOݨnJȭ֭f%PlVs쭒U_?45C]:{IJ)V|>SQb^-ֆK`NӈE-autA^@#_@Xóq;Ղ %>3D*/Vjy-WQcS<pG~m"WtOw([)zYY$8kbP8Hׁn q\n݁> +/eU }4=ݴ*D |` y :" {"e IJk^L3(.9Qvb9j>k'J2Ek)㶨5bӳh(*$#1o9b\a>GX(# XF; <>,lf`jBIՉ^8h~~֫>qW u->W^̆юO|ų<Alg8aU0qhjԊg0]t5;E݀'pn!Rw) 8H"unp<:/JN7$Lh %/oJp2ANqWh7Cg3+-R'*]kH kk`  \W)ŜKcM@[`!?C@ 8N„VaZ?Lگj /lEXPs*hDgГM<¹WS|6!"i7TƗݦHum@?\ЙLKe͢qO3 q[|tJu!1`|'QSe6< i6C`i;O\b ޴NOY!aLb>A{S$|'ŸҞAԠˈw 6}I(]w|RV;/$<-7`h%.SPJ}Ay;+t璙g܉5&"X> &ٱ{d˛0fd7OC\ њ''uv>eL`ǝ R>g3 !/?eסNCyHMψgqMjZFV5%hp^s؅r$h^sIi~tjɔkSSDGG4<.iX`Ji1E$@&Eޭm* ?VFஷ6V{)j0d QE5Rĉ+Ŵ)N|# gs'x;:Ofiq####(agvYt$(w ̓ô9d*jnMQn'IƋ*N_ h߹SȲ>n,2gsQhׂB3u5MUƾto^B`ᒛB>㈲к;7]DG\9x"jn`J)}^?L/j̀*#F !WT&Mҋku#,{S9Z妵-ڵ4kCsh: YZ]p~IY`y,e2okNMgv}p9C:֏hg?=r)k3'lVպyfFQm8 V3z(K9s쪆n-QQst(52oCgnc*mH nXsN^HnWd̂ dx^淸 X시,O ,¹)l32^7eDhx$oVgdd!܀U%1'>K 41E{ #nLi:JH U45^Ds.d!խqR,ЕBY0WsVUm=ܢDMsLJyw* VR(+rAoZl~nɪRΙ 0Qٛ9muS8~7]U$9 HEec$W = t)OD tI{%&ܛPh" 7d3xRT`1b'h9WZ {|Nz[JQfn3M H(WL~?\k/W-̔t&K  9x{h]cڅc]d~7Kt8߄eYuWr= |(SЛ~Y:fW-mx~)Q\32J::o [|m{@S(T2,5K7`a L5&{7ޝq;⼘\ 0Ƚq郲2G6ㆉ gy rS'Tݙpf7JW Ä9(Z޶XT^!Uks?.%#u Rvgoq"ĕ6SD(ѥ.;y_k\A>o_4 |a& }ɠC=e)Mjם7 dnƯܶYOeUXtFOgtg2ToD ]hMȘn1{eE 5,ύ=Z*'U9œ 1E"KF޷4.QÊ*0)N i]$嬲r\L78CYv28㗡9qsvDՏ (u=-ĄX ;[) }r*:g[^acs]日Pk6?}-xA{Ul)v̙rj3wrLi ] r3Z'"שi]"YOG3#y )G7-9kɆ\G̋}Ih Е** ,lXL]qR1=O_7MWM?+65m3oرMMFF點Yى3vDD6NމM[)$2!I ;z's$2VNY:X!?]7}H5bY&RIׯwNNUA#8޽c-DZO% KPժ1mX̫PvK;;"\5L`s0q{Xgb1.V 'zүeh8BVmN&N%3D!\^+xg'?a>)t3~%!v MְvG€41~Rv4+DiA/]!231v6#Ÿ1F~Y\ _ W2i>|U2iIENDB`perfbook_html/node60.html0000644000175000017500000001455211672746161015566 0ustar paulmckpaulmck 6.3.1 Design

6.3.1 Design

One possible design for limit counters is to divide the limit of 10,000 by the number of threads, and give each thread a fixed pool of structures. For example, given 100 threads, each thread would manage its own pool of 100 structures. This approach is simple, and in some cases works well, but it does not handle the common case where a given structure is allocated by one thread and freed by another [MS93]. On the one hand, if a given thread takes credit for any structures it frees, then the thread doing most of the allocating runs out of structures, while the threads doing most of the freeing have lots of credits that they cannot use. On the other hand, if freed structures are credited to the CPU that allocated them, it will be necessary for CPUs to manipulate each others' counters, which will require lots of expensive atomic instructions. Furthermore, because structures come in different sizes, rather than supporting inc_count() and dec_count() interfaces, we implement add_count() and sub_count() to allow variable-sized structures to be properly accounted for.

In short, for many important workloads, we cannot fully partition the counter. However, we can partially partition the counter, so that in the common case, each thread need only manipulate its own private state, while still allowing counts to flow between threads as needed. The statistical counting scheme discussed in Section [*] provides an interesting starting point, in that it maintains a global counter as well as per-thread counters, with the aggregate value being the sum of all of these counters, global along with per-thread. The key change is to pull each thread's counter into the global sum while that thread is still running, rather than waiting for thread exit. Clearly, we want threads to pull in their own counts, as cross-thread accesses are expensive and scale poorly.

This leaves open the question of exactly when a given thread's counter should be pulled into the global counter. In the initial implementation, we will start by maintaining a limit on the value of the per-thread counter. When this limit would be exceeded, the thread pulls its counter into the global counter. Of course, we cannot simply add to the counter when a structure is allocated: we must also subtract from the counter when a structure is freed. We must therefore make use of the global counter when a subtraction would otherwise reduce the value of the per-thread counter below zero. However, if the limit is reasonably large, almost all of the addition and subtraction operations should be handled by the per-thread counter, which should give us good performance and scalability.

This design is an example of ``parallel fastpath'', which is an important design pattern in which the common case executes with no expensive instructions and no interactions between threads, but where occasional use is also made of a more conservatively designed global algorithm.

Paul E. McKenney 2011-12-16
perfbook_html/node397.html0000644000175000017500000001705211672746163015663 0ustar paulmckpaulmck D.3.8.3 Scanning for Holdout CPUs


D.3.8.3 Scanning for Holdout CPUs

Figure: Scanning for Holdout CPUs
\begin{figure}{ \scriptsize
\begin{verbatim}1 static int
2 rcu_process_dynti...
...(&rnp_cur->lock, flags);
38 }
39 return 0;
40 }\end{verbatim}
}\end{figure}

Figure: Scanning Leaf rcu_node Structures
\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeLeafScan}}

Figure [*] shows the code for rcu_process_dyntick(), which scans the leaf rcu_node structures in search of holdout CPUs, as illustrated by the blue arrow in Figure [*]. It invokes the function passed in through argument f on each such CPU's rcu_data structure, and returns non-zero if the grace period specified by the lastcomp argument has ended.

Lines 13 and 14 acquire references to the first and the last leaf rcu_node structures, respectively. Each pass through the loop spanning lines 15-38 processes one of the leaf rcu_node structures.

Line 16 sets the local variable mask to zero. This variable will be used to accumulate the CPUs within the current leaf rcu_node structure that are in extended quiescent states, and can thus be reported as such. Line 17 acquires the current leaf rcu_node structure's lock, and line 18 checks to see if the current grace period has completed, and, if so, line 19 releases the lock and line 20 returns non-zero. Otherwise, line 22 checks for holdout CPUs associated with this rcu_node structure, and, if there are none, line 23 releases the lock and line 24 restarts the loop from the beginning on the next lead rcu_node structure.

Execution reaches line 26 if there is at least one holdout CPU associated with this rcu_node structure. Lines 26 and 27 set local variables cpu and bit to reference the lowest-numbered CPU associated with this rcu_node structure. Each pass through the loop spanning lines 28-32 checks one of the CPUs associated with the current rcu_node structure. Line 29 checks to see if the this CPU is still holding out or if it has already passed through a quiescent state. If it is still a holdout, line 30 invokes the specified function (either dyntick_save_progress_counter() or rcu_implicit_dynticks_qs(), as specified by the caller), and if that function returns non-zero (indicating that the current CPU is in an extended quiescent state), then line 31 sets the current CPU's bit in mask.

Line 33 then checks to see if any CPUs were identified as being in extended quiescent states and if the current grace period is still in force, and, if so, line 34 invokes cpu_quiet_msk() to report that the grace period need no longer wait for those CPUs and then line 35 restarts the loop with the next rcu_node structure. (Note that cpu_quiet_msk() releases the current rcu_node structure's lock, and might well end the current grace period.) Otherwise, if all holdout CPUs really are still holding out, line 37 releases the current rcu_node structure's lock.

Once all of the leaf rcu_node structures have been processed, the loop exits, and line 39 returns zero to indicate that the current grace period is still in full force. (Recall that line 20 returns non-zero should the current grace period come to an end.)

Paul E. McKenney 2011-12-16
perfbook_html/img78.png0000644000175000017500000011450611672746044015246 0ustar paulmckpaulmckPNG  IHDRXMPLTE8㿪 /pad7.,7@CNOS4<@fYZ89:D557ݨC;=>khBNRz2:?ceDGJ}e?AE=?Cᶢ)n\\CGLЙ>@GIsfd?CH,ѳ49=ZSU/ӏv5$ 88:=EL244~`a4-,)5&#^]ؓmNMOݝȑq977BHMC߼70.:DH~h;??3ym֪bTT91/8AEa٪ҡaVV1 932WSVYFJO369ʟrd+{lNMP4(&ELQKKMDLPtl28;." ttRNS@f IDATxԽw#u/P&ފGVWm gҶz5=M3~&ʇ )|P156g'y,llzd䵥}y3'}% _ߺu֭hAh(6|v_Bs(g;# h1\ iG/ Y_dۇ*^ߖ(kHs U^Z= \`ZxmzŲ|x:9~=NC6vǯ,gWT׵I-kC~Zů(U*n_ڙ=G)):}O뎄q#Ҵ> W{gI"ִ0@jG@Q2^WbFQ<<>йūϖC γnP43  CB}dZ_ka뱓svC6ok~g8kw͝ Emz|vQ153[mF.n;x# qmh;]6ӰI9m->mY3 XxڈgD4~Σ&rq-KCxz xbϛŷܼOud*p ^09{]eGn司p-N*~)|ק-,9d |{n4MA(pY'/J' 6opQ!8ͧ#ZxY6p%D}2LkE08dR /k˛$Yq~3 !Qqoiࠅ"" (JL8 .NFv/W\j{ =5-u!]6֫0f%ڐ똜,[Z]X=6d%'N5\hxE]A9ӛ\>[cS SUaa(QTC׆ wIHy& Y,?~5M@-iLo0\ן{PSh$^M䄰Vl }L0R%0rP"]aXmD apMg:`plr_ͧjb Tlh+uzФ1!;x-NM`QW^+ua8F MWGY!0 x^) $<9!.I:8h@V Z *TP/nV[^I5 K3H՛zU>,dip.[0l¥8S‚7`AooA<'5C X8h8/uyaOh4VUq Ǫ_0Şi+z̛pՄ>zӢ1:ץ V \S-,F} [(jQv9Q!3]7WpvȤ?X_1Y'>1s#C:W>uwE'r?e1#)Щ\=~V>Oh:LRMs:wõʹKpY_&`à95G(W39.3mEn_L)m~5صP~ d3KݿdϚ^ HER A[m|6 5ډLJ /kwSӷuT֘5rDas9 Kԧ4Wf>H 7AB;HgRC 6hV&nf`<~J$FhRU@C13zE$_%Ro2ye/Z4'qVbfR 2-b ]Sk4'1tW7sK,^옟$;-: ʡ8UԶ#[ gH!ⲕ15+4Ԝg"F6~8ͤ^z_+C ]m35xCkhN-5 $D t$xr(5bii:up}8[W*_ >Lha"xꕢ?pQ&M5,K֠":|WGQH KAҷ04TU6Q1սJOQNx{Qx, ˀmyi p0.xʗ~xGL#40 Z)byBKC(Σ?ڛ'O~y#\"(X!*qx܃{ԎT>iS\'9]vPet"> HP]۫}րs-Bfvjth[-ur\ZiAH%s\) WoZ8 kT[6 AsgcjӯY x}vrӀT=vw^?^us?ނ^w|=]@S2gwf.0L^gm܋v^y4Eo~ ;߇|( 6>߹B1hwY5 Dpj(c_L܇jn~xfl%4e4uq[`D7v7<aX2wӇF{yӧ59U5nidsQIIMAiSߚ[68g ߈?pIpT,+|~2dv ۢ$:MTj?6wN+E]uekIiZ;ݲ%Bdxqf)p;hϺ HB 1&R\\:ZC"Me;Dna2W7JKuTt܏BB>vSؚA (r!R_PQHjwe䱣u'z㌠ ^d)P'@FJODv$FAjAr&t[J"7Zbf[q+|T,p(s<ݢ='!A#-veWnY8m Q_Y)􉮴&LPtFxd"\yjGHUtvu0nt5k#DDE<9[7.`띵*XUg٧u+z8Ck  (%ȍxq/-^]GׄX9pkE$W1+a6 D߷`62n Id QV霉pQKCJGn'4Gn`~$hA;s}+ێjC)72 n[}D ׆h.6J+e#4H:paxDsSh'ZV6`"6 0, `df$og ɷ^壷 Cwfvk+<VpOhԪ<{苹O}Ե0T' &Uձ3͹"x;J[!jD$KSQ #KiBF`c{ ^Ȓ['ҕ$$lbH5N,Jq ,TH #r)&:3BM5$bnl e-lP s"K}Sߗ&V`2Ձm[hKPGx0ek_-k"7p,[ji UjU2$ا$D[Aغ`nA:UzjXj0ԀVNMvkɬ ]d0s 4"?VkTv%i Dּm6;`wF ݲ8X3} Rz'YHq3Jb2CND7ޚN3$@Mwpp%A_WNjPN{4Ȣ*)KE8ȷ,fWe>|UNN%.zΊ 5ؖ?F n2/IVY<,hmb6dqJ,ul0yZ_#% 6aGf@":#>Js}B߹C9 cT m#Ppwfvİv걶M*?Uؖj̹o0 qnk~NĢt{r {Ba"8ʡ.`äW2}~` ~:u? ϝ<ݜ2X' F@2*!RI{>]2\eGPoN?fl+Mj :^7K|' ]!DtQa&h7u!<4 Ӵj5M GR1O,${9jpA! S{!H;^0Vt3 qȖ8Y0PrT:Ktj<68J)1Mz)A2 R?X^ q%ƜW>J9 [* ίt}Z! BGVk;Y#:SjS2F604`Bi>?Zh'}߷ί߫IF\Ƭ_MQ22/D^%k t]SZKs`n5U]u//bSH~ $e6uuWj6(u"ۜOeM8gve蠬=jٶ'O?jtf6⢟AL޴̩=bQ;\ S] pA?[ E&[_]?yu7͝`T6&:; ' 3"W;p~X^æ Nկnݫ^9s/Z,` x 3VQMl>608h,<%o=Y_Wwz[?q5c=HYKl~vb!V$cX+dO~q}`gu*o5c%06$}d?Iֳp׆ɻaT1LMuڔy=[-̾t٫M1}WЙg7pIRm.naȬQ7[f9c~TDΛywlm:wش 4.@nZ r6h1W3cS&;R7gAB/F?r|NmO"ji /@ᒎӾ6F4ҭ0%V>nˋ1;LvĦ@#Q3itWV-kv%vEHAkxZ[b_*W|FeL-uI&[' ėpr*5+o=yd@g̼in3)w[˃ Iklvl-L6wd,~<&Y -@;O۬[ 31H ݫWѹrŜaak]{ҭpd!iu]vK|AAx8bBU`q9u{ˠ *Q16p Hw˿Y mdR]pw1%\/ 1(5 KJZݤQ'Ɯ6p}p!q[ arlj3s=~Up2\t k׷M< ܲplf33ܑYXsx({S1KrS66KRkܪIƀڶ\\E^GBv隡\4~v<]+db-RphҔ𤓬)vXT E͗b+ѼHj7J$(3[@2Zqq:o-5C`ũOUqxVbub2o9IX8-c5H=ڱnm9k'e^&|M7o [Bi*Pv]x,X-w%Yy+JUU֚ ~Gw8΢orN'`}WT#<dN#=cMk4M o|bhb?̰m殒FU^ȍM;2H#Wnj5[{GnRԄ1c>V`Ir!LsıeZ%i]׫67( EWFvr1 !$(]0c2r/zzU(uZNu8=R 0=L6; GNlq<8:kWuצ=WPD 3Z^*^K姦(\@c/EUBz4nz=]N)zYGU%aāku,X-l뗟_9fߚc+KYV$iS`#,J|5-$HblN />۳fLC1+6؇ 24Kq.'evukUZAKt͝y|{5!dG7~`7:^sjԂqpi5\^dl3<%q͙YJ5 ՛?MS ^X GͣNml/Š~;\N#:\O($R|$3} \,[6i*'Oz׎zcѓ5B)L4Ǚ547Hd< R0pyבq =Z9oTqպEϥQ2:B IDATĈd}#T QNRU-w:}jc{啓 ƀ?vʼ uUжS q9a$4 6r2NHHal "lɛ<)S=ʪJDRvP#`1p9өn6nErmuʊH%okp"X-'8|G~X2 f+nb3qȉ΍z0h!(G GHFF1-efilLc JwADBeFԩ_ [c`[ M呁ȅei &Ōq>& 3A`%gIA#DoUٶcNbb^SЀ0עŧYGEN4*,>/'-N9,dX{XLf| B6}Dk dkv9 S&Yi`a hs!fnXAQh[f`\΀m&_ mӆ6NUb |XF옑m(h E6!d I `EONpye#O$Nk 'Iu4#$f`%mbkL0Y/HXP 1M5fw q:=1qjJ刁3;ۤ6ruk ێZ| }LZBz=b!nx8Q=Oj%!uGQA9m8&OA +\ߔ|@ēo*8V vŒ Ff1ic^(K["9%zue6MUPi;:<Ωdos*X~XGIju*S:;B3LqmBO^Xxݠ{ɜTQF#Oݽ3=bam;٤m4#5' Q} !//u^_9~엷,Ux} Xfs`U ;eR\&F'EMN͡ڣekQeM\}1ST޻!l-΀^ckuB}--b2M*"مt-q_^v|Jڝ;;A3DVPYƠ&s4w 0 P-^jUΕ&Vi#`<y4'븙g;6IHYŖ}wyy˟0(}مT9X,X+$}7S'IK'&e@/U0>MkZֻh3r!%]qh M^?zDŽՁaTt[| kZ:ߒ3?z樺ʂ;=OEZxܸ>J <$AF:!t1r r ]awAKhIV?ՉM7)[@<;=9,nuqIxekq?" ҏ*o s{JzLDXX0Ϟqz>%OB% 7o>w6_9Q;Dł9A `6~L1kvΉfG{mU *`eZ ReS5?ھիlN~ë?ARНxtΝ~s?,1]s'gtYL?Xt7ffdiZ\VTJ2." 0+0 5ŻvY^V][+Ο9ZvvdN+CPL?F2 Z=t,j;?`n_Ԋ)}QFTȗpY-?:h+@pLyqhO?Bw2P;R6{ʼ?쐇_OKENYVfhw]?>sKޚÚ<}+fw{BBڝ+~ͿsROjˌKsG|u"+y8Qv7TfG~yqw~'Pw^P~4fḡ̍nۄ/aZX;k_Q+MkC',{߱7\ܙ5]crfM&BiRu"~.1e.6+mGtwTpk8+tq3`L%$ R̨=^sPAYx4R`HtrmĽ (?H@ZXI/KuQEscdxɽmĢ.}Nh\+'iH;َ@̰͞I |!em@P6}uqk%ECSykѐ6[8nmWC`NJ/ 9=O ִ2sŁ1^ZGLG%Ns2l LfH,i3vZ>`bql@IWu i"5 䶓'"/S#i>ji2n< $SK_rIy KEhm. b5{.g{7  "]xV$4|Iͤ~W>-l,,,>c!ьa{k Ae gy:lv'ޤMR(?`nHE;:ѥ2``r{I`tVl"Gforo/ iIHK(:J 4tJ2!m962$3abخ6}$!&DSK7UICjlꕳkǔŨTI*ʎ&[@KBrHmzac($ies ǾĚpȄAl LKD YGq-iO)ȟX%#47F 9|cӁ~4`UF{fv?דTbGulFm9W@9p"K.{$J1(p7U2$[ʀU'1S'L)r{?Knb6P J:uNb Nt+~6# *oft_x iF2F^/.)mͱlۭw; X(Hݖ)X۾)5`Ơ8M̟l/6շ >1#>UpF; /…buꅂ€%QjȠkl45?+nzӛx!- AJlVlwS`8#mt‚ ?"G.rq^+vtp^Вf'ǷgJHv(xuĆf]H7 VQ7 6ӻ&<|eN_d[=T[,}+ ŸI>cvO ٠WH׎UɶwlINZERdPY5 Tk/zI<`B,"f'#'(+%`>$X(n'<¶k}J&X~Q4R`CJꌰVqKjb{;H<.ǚ5MB׼a(T,_,n0Gś ?#RJ9{2 C. eY!6UdM |MB<$`34U0lOHK-kqSD$ڳ`J1@b*#2<H9/"D^}86-]Ÿ+X4%7֟}7%ncg,0 ,4.nm5qf}tb >f!X)iaMi$ϛˢŒ`5vzW+ Q 儼QVŒ-qemk4#Ru/*5YYU8͕Ay2`vkol~(b$]kYw:x_gv,E1-^tY,|ZQ'kb#-QJ`G# 2 Ofu04 v%ǚ~`G(/T$ߐ ݉aXn sMy%4,S%2w4EfkBM%{8,7גBhbbJ(b" KhৣsBs7VDMla[V; Z+-4JUI3$m-B ~J7tbs&J9XgL!4xZEBq IO:u&ѐ F7悵F:^!^i( w,s $ @Ɍ,DlsźW LEf>M~2ɔI]R:#5朴h$sÀeP)qkZr7= 6QoLխ5YW +y X\{oajlNnI9 Vd}pznmM.'HױzDEDckEWNe},(V앋Rg2unJ0Z@h@%5y&~65k3~ \krJ밌Ve9I(rx_QgG .d V,EY )UJc.XE EˋIz(9ز ٧zRipSq^(q/ku]ҠAJaTΔl0P)`'&3:]pI> .Z:Ɋ7 V $\lr6ڤ0x0c|ɵugMyņnԓ"*ITWQ?IA{O;4 at"jAW-Yiӯ VZ5 AzJZd)z4Vx%5e JS--{YhaP~PTuvh`MYC dT.xR7Z&uYXiMHCa`Fm2L48XIY K-硤ũF'T8,gluLQqzEd4%DԤ0 Pl ZN%l(O&Ȥl?d &Lb {qNM^`)FOVNYX2ʂrBIF { oor"+а;E5t횔eHl";H+F;q^"F@ ^3"R0<͑ EhgVv&of| <1)X ^=YWEQ=:{wYrv{.%lEg$c5NS:*wEZy(8Xf}}_T;8X 2Ң#`ɺ&֫k͚9z gD߯MOI.߬2oZ 3^v/qy"*([a Td\: IDAT)ܕHoP xB~cPnIsr1oXyI+oY A JEe-ll[O(b1M’o"z qeG ,YĐ&%6y0CٙZ%77z[r{[Nj4U3vyٝqk*xb34m4m}ta㌃ ~/" $:+V تz(REj<|Rf}# VLvl~_hmYi,C@AfY|l {~ZM@]gJ;?`%ZF~D:*nt|Og\33Y!@P|tql[1H eS s9Z8i8 T0(}|ޯ`eJ2\0]x eKHeZnr;W&yo4kr1(VWiG Obj3UVesvggr'#3 ^h~ssE(!ӝzQbKϣɖLaSaQ&4}ƃv`55ggg-zNf](1>^ybo(Kn84S󫆒{O*DK es?oZ33;ҵd;)~֍ ?S< 6vg:+CPT,D tMﶬ|6L=s>#n\w Ba^W3M %"خm<mna̹0rsUq `m5_UrӽU!mqV6jq$Y;JfEA&5O.t7G](9>F}+Jo>`hks5/$FcFmbԸ, `ֺ=uزlѩ3 *>êoaX%~<{"sU2]T%#zu.bĈ~S\OyϺ(ӷ{{z߸`.X1,&iQ^圔Czaԉ1yqٖ9h&vYj*sKWj CΉ\^&Ȅ/STfR;Ǒa]c. KYjPm@->̂/cxK f``W^OQB6+=I{dy5SyRUc`9 L}T>`Yܫߤ"ZŨ{݈D?Wi  ٰiΚfaSTOPp޲@wZE"KM>=H,Ovp9jU:\+ᝀEg0 mBZX?2FӮ.]jX%X-ճeLixҖ(d$i?ӆ{WjbW^06U;tZG Ac~HNʸu,kӕ߫qexc0a2r5G[58p:<[ q._EVּWo>kI{2'Nt}z..'] N̘][)T{o%Biz`4t}ׯ O}_9p_|Rڪ=kqI>hЈ_Idw|x>m/2-Vlx"0mg8HW-)֠P]n٪{<>w 2{~w.-3^A>K_}snXmz ͼy^i#;ylf1kllnT׏ >XZ)~Bxnv{ex[~3m\ty- bC ?1;YOQ4>2` 6V./?p&'O >/}biȻ=o??|XEomʟ+ Xk;SG`Sݮe. Z3 HTX|aZ*Z9bPo6|i>zvkyɿ+]TOeu,o3GZz>8L{ ˷Ң'<+֝Υ 90;N`'*,e'u% bTUxF?C lDBZ]P]Mmv)7p8uDDb^n7I陏|§wF+ȝc`_vwsR09  ؍UYTDV# nyi;  ?(:N>$og5?5*clWjِhZؘyͯ\ ּ(6clV"/(kG`=^٬`3'1s/˓ܒݭ͞?0MG7VpKռ"]!ju2O9r{qQ+;}*v>sƼI?!!{I)J.@Tή|cJ.;'E錌h 4v -D01 ։޼(!%3o4m]'a=i?t%oQW\TJl 7k?pBڷL;RGA+ɬm;̺p}֟LXt=PJґW{5\]:jANW#{ŜNEv~d_:e~iucc59SR7!56#Kn!MeY=֥ *Q Λ@~Yяzsҍ/HPv(PdV;(mۤkm}W>?eg2ЂXQ vo³ٳ?XwYSȂu`^ei)b{W¼-w/G.5q]ї8'%'L u)3P_ש S,v,_}Q1* X{X7p?2hgY=z7nonclWLWWpk4,Jw/^|jrAL|lKFj=*j]:S>{4F2ũeQX> %96[4+䌉9RI!Z3YNO/ԬCr;#"jpCY;?Rˠ "EU'XO\nAr&?eׯM-. 2`ѐtu&&8F']cKLܑiK>Ma=%.uPȽNJ jqu}сܰq;qqtv_q`7V`$`CQj >2oY~Llõ.NYS GiB!; ^ z`!~kpwi/1σ ]Ôؐ Y]`O8NA?=5!p~n l*r`P<̬S쪵 zԀ.'s_`U΂s2avz$R*FX/>9WI.*^ף U@$k\/skUz;?3 nc7 1%``cZbױ0K|">~l`Dk6zJ)HΈ-}0MEFjZؒ.;g5x:`O.mn _+m-%BL`XF00MX\_{rPqȝN#1;""=ˀUP^,|]0qj3iiK0IRpP=>IZ$l98vvjRue {Kmhlcy =JAV22ɥ˒ytֆ O3Za`m㿭k̑ӏfJrSVclC(,,3G :ҎB`G^ ;lv3sgg˨z`C ODTB:ܐߖ|b~9zĞ<ĭAjN@aXɖiI`S*Y(&^~7. `Y!b`pVKS TK(X{Q!{]v¦[UJO5[ ()}CEA#6~'v(Alvϥ`Dsx~RC-N9=fq'_D9[ v~w1G4T:8aqwm*rvY Z\tLX{ܯxt3 ˤJQu8VOQؔh]QUۏ U.?a\,a'5AX9m;ҷOOm"J]/?ݝs}YݺHm&A)<ԅ.h"cͻި! [T=°VTVLHUp#+ + R9Lj:VQ{.@P-?g}_ֱ ؘnUejbj+3D6?C|!&.Wx*LƣdQV=ٶٵ0Vi:Jӳ0/CS׾0.o2 ĘMj0+40 +dWeKza /LXu;oCzBFE3 7 `~.T5-@ޠ}hiՏ}[ݿ Lgl Z) bzq e[^Ⓓ+}t;i%c.S͸:l=t6#+$?$wMwnq=9=2G)uPN" f^VP;9s%Y׹2Wó6WG+vA34t'$}KwOzx4CfxphOS3zٔ.=%WY1BjW%9ꆹP$2yNUocXk^tU,eaMBZ2Yٟ%@?Fi,': 𞧦UuzMͲ_ 8n*ɇÚJ&]lFv 8 $6a59`{T/utR." m z"  WʩҘ6r#+<3?k>r&y/|L.-dklN. S(a[TS,;@%v -?+^sc\ IDAT_4#<Z5#~`ci`;q\@|6%}.ʶvD|oIX|'hn 6I~*vDf.g·aKb\t88IZ j5`fkKμзzeUlAhcϓVtMj:z75&{A˿1`}>甡͡mCfrK*ೠckm暘L>$~}aGy,Glu,p k:Vj:H_ҥ іj \ U\k3'NM_-ǒG}x껿8vʕ1ql3IlawL`VZj`Msf1xS4o V҅XboNwo_~ȼ8vk֟e{\3)X ~ mԌP)lh:Zb郿*5؈ 3C:w>|g>lwמi%OM- '3 b,&b |٭ hVc]gXM( yd whkR_xǘWrc/CD0J%}9f1XyC'U^Xko/ V/"4_Li}>W?|KG>}`$HFh5E#85UgiAGPm$BuXbqwQï~OG7 _~f~L0\mԍe4`%,l |8ubAC6Lu+cag)_z{|y'O$MU_(d- Nެ phӱ`v=pqy b-KˑàrK>\?̃Y.If\@cI%XcA^O`a]k9jRBP(å{+B6 x`#gbk/X/PcSF1d` Wbo`P#+VCiriQK(,-l ^1[ lz05mKvR%xƳTs@B+=$mCfI2ZPk6:7QV`XS<?!v*- dlrVMp`㇑kllY4caܞ ,[ Я kR^xB`JI& Ns^5  *me" lftea-r<[blX`X.ny< "ֲ;h9jGfu-z,3 =MrdSg*j&Y%{\ZW:vvwi!>t#zeB3_[b5-5rzi&5WB9MI}6}KFN`ݕe'嚶Qi1i*ep!BF (ع,ٍ n 8pAs"B3eXv mz}t ![XM\k 6%Y&tx7 U^-`CTd)eN FB#Zv( :jDВ*n<̆\:5X3'*I0%YV1b .ҩ:bj22a[V+3najgF{j$#5a(W ʮP&cAZ6Pr3x3yv|f- ℁v9fyֳVHwUW}! rN+%K?!LzZF#KZ;*Zuk qVejCM|M{ɚ5Q]RY!{cQ_![rTEf:Y1?X-nl5MA]7TǪ&ja:HV3PB av:Ƴ.Pw&kcU8)YtB0 k1TB#.Z{U=k5fcG!e&{reDyyvbΩ`ke:X/% Ki<yz8} sys<1e,542j<ʺDZJ6rJCڷ٪CGKN`{e Ŧ/!j9֤(VU:] *R.e. Kw Xu`;"vxX\+,KL_ Xc';l6izȒL r 9oQwfFy1X0ߤs (5N3@uyb٬+Wd,{my7 Dm_9=AX{&o]XȺנT3\ 0Kl[^^S\{;7+5@Գ~@:m'jXǠM\u$OiLb)XHX#'AȪ^hd8E|Y4dNs`C l=]5*]2\UZqeќfs&B2b0*x"@C9ԓb.#zi閑/ "lwú5?ggf;: YRbuye`$5Upr/U0ƜN:gz<#RI2fS,SQ]X O V2<%d1jnbc8p(ouC9& ALXO^9-Y25BD0pQ+rj6tTP_ !!'HP@5sk2 I8|̀gg\m w}NC=3Ul'gK6i.vy]T g$/Vk<8֛60E XX9lJ3鞙p;k`n?1͛ؕjP:63 l$͂p _X#X_NcM 2+Z#%zqiAQ:744䞑[J>SXAH5Jrx(P9p~3hX,O+{ckDjxaŶ__nE~H+TRYI9;ܘ)*ʺXҰtcZzR=".乕ʗ9|:4fr%}w0<ٺ6惤TP[|]pR6C$s@MѬWԪ2AP F"DXȁ[r!uaYqEEI*]ybs؃J(ĥ7FLogk0tұ+rջ%lyЇj"FBNa oIIǭa%8!T/T̹wF՚㺁u+|zCB8D`]5^yZgBMcQ:L`k[y6s9 ; x&Ba kv!1b UAX-I]G-2 2Yc}p&{C\VtKhS\>X#%.)+̓pp.D,fH 1* l en-B }J,)o~],Uh~KRd"sǣHIJmWi0U9Gt(UW%ɍ>S*r)}0m`}dK#b (B5u&l6} ZsA@DX7-^Hf@ֱ9ANrMX}{d66GS؅9RvDZrAʥ@-"l"<&aa$I˟{;MV"q*+05AbB! n2qy - 5 B2 ,خ}ӻ;p.S.)_ۧx~/e+XUJqiSՀq}pQL/c}Z*0_ #]@"A 5BRۭ2Eɦ@ +[e̙̍* eҒWYzw(W!I2jV(RTTxw#obU]عw=|3.~7EWBd٥|D]jt%,+75(iQ;X(\ [*E* )Ҧ[hrXˀZ<vTa&9Q5ROG.%j$lkU,Z9ykqdaЌs!b,a,I}rҥG!%]#%NҚ3GelhHfeQUv@ T]Bs {BpB\y¾PLj?wLZb7}e6^`(,C^f*szO @XJ x$T03iln`hen+X ai%<.ǟFx\׳Rx *Y\7X"c֩CK!01<%ɩ' ˶ Yc4"̌WAle,K+Z1rFF7H8SG]%3M< ` ~,T#i0D:@ //-e6 MA_ l(D J+qUVڗDl|D;i"9̂; A=q[6G7mywklK[H)R)YR)J,0#2ěsZΓ0q8>Ni(QUSxQ֫6n7`}6#RG\!|kMAJDBvipyZ B_&kآb7cfZvJRsI+ѻ:6\"@yRH:Jlt}8^D%A >R:6Ѓ#hX@9!|3`f0FG/DjCJWh!p皉Fcy,LMb+0t:ī\|5_w7/a͐OVFx\}HU4 "B3)ae;ؚ w&[JE6ē;XC"3D+/q%皘RB63] Ǐ=ظfz}@34DdZ5z?y"Z=^]ܟx/?/87wlk ;4\.H%َ*~eC3C3X(b[XfKV5SvN l-x?:o;"jjjS2|9Qwsksf{w>?lui`l?ge2Yb8 V|ӷ前5A~S\)=@GA b|^B֟rKJ,O :) |nMZa@t$8RP-ITPU7c@,q/_sF۞|㨁/~?~~C|_ыо7DWnUIDATlp ,,CS)Ҡr-f`ZD..UGS̥񙱧<1ʕ c*m_֑J3lǚs~Y|ewa9,o4^ +OR9DɬT_?'xVƮBO[>]iTץEGXi)#NO()py} s9V 7KbQu5QcnN''+Z#=D`G;侅EZ}dYZ 'vom9lL<1I7? ,\gJ3|~6%4LD#- yl`@`͋قij[G&u԰)̰ 9=/uk~Ho t]+eYMj6}0R?]B0[o[_-\P)X(Ij*gϞ 6&@.Zrsɷ5 Ϫ氘NNQ,<38 e򳻫bX㨃;%q'_k={G=մ9ʴ9K7:k?zSw9*~*9Na\Ow~<9E93>MœWd"bJKEfY+h ( @Arv$Ip1c{y *kczC'Vn3v5opxqhT466yq{ ]ZZ:U6ޓؿkmXx*=_Gf]T*bUe~ 9x u)G7ۦ/a2[!U]8cuuiw)B"O)^}&&Rzߵ햧/y!Ƴ zb"b:X~g@۹[W|G9&1RIBQ]7QJI`DUAl5X/SUo,qM_^Xu Ap}˞XHj4ADEXے)sA<;a7oFŒ{$nwCKT=;s`Bh׿HՀ(YGbO߈9>dZwGz)KGrU{X}byB]U-ѿ'%y9qUGxUJԩXͺw*@.KYE0X릉sbuE˲u1;tkN7׮][H$oLӁ{{çNZקD7M+HbJ)ze .,*mb3x@DtſyYL6'T@,z_l.`O[#-ۓU򣾌,]x㍟^( l}W/{?]ZzwaM-qЯ&=-z~} "X="e~#tcUsB-u.I-րh}<p]q9_mw86ЉE$Nb(BC;o@ػl^Mf-8KD?RQ>a0ʬll:+j VTqKѮ}::VTcp vssBl3sl͚LlCqgXS1Sg.ӒvWO vHQfܪBu&6t;`m]$5n+w-Dxu|T-lJFix Wܪ8 _y54,vr7vcCR +є&Hdu6xNN(.N6V0iu|,gg\?)Y_Fظ*!gqR>{)B'n=]ި:]2e fcb)`lDdb$6nP}9S_Ha %%1⊵S XvU:%!WJѡGfkieůcg;te`IKœA@RRT܄waVgɬ՞%?e"?CZҊ"PÖbo Y$q>i'.U'TR΋B&q2Z@V ŞՇ5Dov̼J*w2͐%R,-tfpWaCO]*Vy|rHnxB2 &" HyO!×ݫsh4ZGv4@|!lTdVa|YxJ0q?d:l`O6gq<ủ8ɏ=tcū [柴ZBNi̶ B&J-.@R}Nu䬴koxTDiHzTqH7 Eц F.ĶYVZbôo˦.`tCXW@$'lc@,H1ߣXb]*Ti,AF(Z5[{X>iD8v\[Ƌ4Zm6羅.#%XI N.3wcJwQYX|:f ឈ?֗Do,^A4P2.0[1wNYLNѣ'O}={}%>%^UynOC]#QEtO?W*о.;3skwGU]RQAIʚBKNG- eY=`Q<JW&$51UkRVxRHw(V`9/vsKa%VҰy"!>M[vӇ)b:|~';`}~Qei{3۞y MD:L2ɦGrql_ M~=yw|-kGo W⮃湷b.,y޳XU^C/Ks.:=x(R宁eRv)/jb0w S/{77T47>֑{Eeq8-_++8|lc0 ̾3[i۞%bL [-nuGg)i+ Ҹ)J"4 "Bt""cSŚlH] lTwi`&,%j~R^WKJ'rI/4/_nkc_dҶQd' =O$i!8L,2 ۝'LC3j XOm:2<.X[-BlNZs`# c`M GLk2W4Az:[3ò.[0N`5XiQ:H$Ɯd5 SmWd؜Lq94Io{6iO^#6̆/ V/QЋ녪9dj{uj'"j&$=c[_˂EE` U,+}+k 6ZD"JyФ 74iJRWywưT4Ә[j9m.ש`֤c?:\=`nD܁>BN22IIENDB`perfbook_html/node1.html0000644000175000017500000001216211672746161015474 0ustar paulmckpaulmck Legal Statement

Legal Statement

This work represents the views of the authors and does not necessarily represent the view of their employers.
IBM, zSeries, and Power PC are trademarks or registered trademarks of International Business Machines Corporation in the United States, other countries, or both.
Linux is a registered trademark of Linus Torvalds.
i386 is a trademarks of Intel Corporation or its subsidiaries in the United States, other countries, or both.
Other company, product, and service names may be trademarks or service marks of such companies.

The non-source-code text and images in this document are provided under the terms of the Creative Commons Attribution-Share Alike 3.0 United States license (http://creativecommons.org/licenses/by-sa/3.0/us/). In brief, you may use the contents of this document for any purpose, personal, commercial, or otherwise, so long as attribution to the authors is maintained. Likewise, the document may be modified, and derivative works and translations made available, so long as such modifications and derivations are offered to the public on equal terms as the non-source-code text and images in the original document.

Source code is covered by various versions of the GPL (http://www.gnu.org/licenses/gpl-2.0.html). Some of this code is GPLv2-only, as it derives from the Linux kernel, while other code is GPLv2-or-later. See the CodeSamples directory in the git archive (git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git) for the exact licenses, which are included in comment headers in each file. If you are unsure of the license for a given code fragment, you should assume GPLv2-only.

Combined work (c) 2005-2011 by Paul E. McKenney.

Paul E. McKenney 2011-12-16
perfbook_html/img127.png0000644000175000017500000001224711672746144015321 0ustar paulmckpaulmckPNG  IHDRWB=PLTE""DDff^^w<<3gggMMMw'''Uww3UU f33"33UUooMMwwU++ tttZZZ@@@444fDffDD"D""R(UtRNS@fIDATx] c6וu4^Db28^JJ녍]$0KBdsOk,ޣc!d!.Q"C&Oi7>X*vB {ڏ9YNζbZW7mUm;#Dv%9Ӭ p螃xpQi \L$ߟH+j$ӥȮ$CcF͹?Mߋ[-g ry]>{8e ~,]ɼ&yjۿԦr xɢ+Kmgǜp;sv*vmn^Q} ֣cL8(}m=y 3ע'YnxP-ɋtN'tU!MNnڏ8}M7SVs\(/Ҿ Y$5o.qZ@+=U-z=[30%  Y 1١ ӆe?F<d/%;z! +R";dQH&t/4LépRBwڨuw>(5`1d`d7I-fhSHv%cƜc&˦^ߔ37?/t?}9v#Q\",%{!t~GT|!T(]3"xDv6iw{؝}~So)MBZOEvӏ{i Fax$/)C)C!E>}a}sE:acIa[,8ԂI'"}`GYdȊNVݡP-~mdʣ׫YW:bc`5^,,HNv匏*W,a5r"j^5ڎT?.׊4..%\pMb+ⵘVWtS6{|L(ʣv"REra- ;Oh}yU*ڶ~].Jp)6}/]UJCů!Ssw带Z_jK G, \B)c^b-WBXYd]q Q-[f"*`x5 㮶 \GU~c-BޝvOc!פk(xos~Kȵi[X?P-]BY̵4}'u)Rl>t={90Aa}˘cs<{GtE찁HJ`YuG&3/@) d\)RU\ףN)3{)E:~5H#D9pt9KQKϫdOG;wtSl RQb,9oz0"cL+'Ԅ80p]?e^[^?p#檼H ݾc!#Roc)&vDy\Q-mBAcRKu2Rlt_Ϳ{m\u'J߿-Wk='RBk?pUcu0G-]WA"(6WϏpF+W)bSy=p("iUT^8\1FQD_M,rW9bSl=+yIGPn yglVJ3hg&3A"u+p1W5$rOאU=\!i]Ksw I]QYqM\+pux\[eSO^C?z T5!O=UB>K^LnEC m;Θ^߳Ŋ|hz\ 6*Pt0qF^CCR/ZͿE$u >NS;c\/!I?T~3BZWj﬉LN5#r?%74O)~BڍJzt_oEĔNnz(N' WW̶&Y J濢Mqy~2/~O M7x~xJ_:Ǎ]ICeno_|~99/;n$S]jڿ kt? M??ˡ5]dBF1|orFx .d"Q7%#HW<9bѻxN.]R,t ⥳EK3V퉹A:>y4 iKFsY2Izj+ v6g]hKC0~+MfxFtǩqN8n:z{; \!{YW(&En/%垹F1N̳RT$eR6$.js3ɪ_STQ(ym@n`pppp `ç0`49 u"U 'n8p~ixw....Ǯɺ,﷧O_?~uN~"UMGy]'y>Jぴo5@Ҕ߄ӿ;@o f'̶&L,&]GQ$>?;#'v|]A!ԭk K>tbtctc't?Lп Ckh W/a BEigi]x45 C-bB4 g4Vk쒏3 >eY>+I9 >G'á^4B=C,De캈I4Kw859D^bɒ +7O Ye A2Yd71 hmnD;S":=Ť=4`oYK:Dg''6ih0g3M5 DOZ>XSWYR R-qBzmԍPֹY,9sg%{&_H1[aZ3B/#(n:k*bh0777w&steQ uBG0x ,誧z?誧wyy3پ?_w忷[뚟>"]o.KQ/zYi(|E]=g8 ^:[abRcncLP,jc \[؃}Tk뺥!H{ֿ>;:ѐҙj5q'B,6Rp`2ш(*sZ"J@$ IƎZUT/z!1 dhjqqH@.cC2? O5>8$C ƯzzhUu@S-IENDB`perfbook_html/node252.html0000644000175000017500000001327411672746162015652 0ustar paulmckpaulmck 17.1.3 Memory-Mapping Operations


17.1.3 Memory-Mapping Operations

It is perfectly legal to execute memory-mapping operations (including mmap(), shmat(), and munmap() [Gro01]) within a lock-based critical section, and, at least in principle, from within an RCU read-side critical section. What happens when you attempt to execute such an operation from within a transaction? More to the point, what happens if the memory region being remapped contains some variables participating in the current thread's transaction? And what if this memory region contains variables participating in some other thread's transaction?

It should not be necessary to consider cases where the TM system's metadata is remapped, given that most locking primitives do not define the outcome of remapping their lock variables.

Here are some memory-mapping options available to TM:

  1. Memory remapping is illegal within a transaction, and will result in all enclosing transactions being aborted. This does simplify things somewhat, but also requires that TM interoperate with synchronization primitives that do tolerate remapping from within their critical sections.
  2. Memory remapping is illegal within a transaction, and the compiler is enlisted to enforce this prohibition.
  3. Memory mapping is legal within a transaction, but aborts all other transactions having variables in the region mapped over.
  4. Memory mapping is legal within a transaction, but the mapping operation will fail if the region being mapped overlaps with the current transaction's footprint.
  5. All memory-mapping operations, whether within or outside a transaction, check the region being mapped against the memory footprint of all transactions in the system. If there is overlap, then the memory-mapping operation fails.
  6. The effect of memory-mapping operations that overlap the memory footprint of any transaction in the system is determined by the TM conflict manager, which might dynamically determine whether to fail the memory-mapping operation or abort any conflicting transactions.

In is interesting to note that munmap() leaves the relevant region of memory unmapped, which could have additional interesting implications.17.2

Paul E. McKenney 2011-12-16
perfbook_html/img37.png0000644000175000017500000001135711672746121015235 0ustar paulmckpaulmckPNG  IHDR<'=0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fmIDATx]}޻޻8-R mZǶJD5GBDD 2_eSօ:#"\DQ?L"8E)QJ^([|!(G:3;vggvgvwTv޼|滳Ώ}.@o?m8,qR$HTڰ=4' 9 ٦HR8CqjN +@5]bXY7؅Ҙ(qrKoUBeD_  N0J#^(Բ&qm"{9mFP$ꢧC'܁k+ |>|gr[>xx&baLq.N*1B0#Jd#^$l$@{ZsDmFr ZɓS{{IlGPăb хm#l#U=T^HHAj "zӤzZgKqgQ[$8.;ݔTw<1%iMl yE[2aQ( l5Z"Fa+c/d:'B[ErTi!r:UQ'I??>~33j%몺eAG1zHou˭3z*8$FUUd:TA訴ZPj-MFɘ+y`O»`EF؊nJ<'Uy922ȪeD#& Gpy+z^UG5sL;I|.Rr1>ܖzӂjW=/{UA $]=#sӴ:{"&(T=_1ikstu.rOU03?*j!xh!&ij9\"zzP&ECkF!0r&GS=332l39tp#. DFgV>y5^%.}\1%WoMDEvv)ok™(LE䈵E  0ͧ>=ImQ4^!g^s$Eϊ̌hԟ1: v#嫴( i/Ʒ'YKU+^Df=o,n]v/yï/l}irZR⃗||stoI@VGᇒM-OO>•޿{e5} xi@&֯avQݾ[vMV-͊Vw'QIrgsR|^i/-_o M5]*H1-X![Uxb/*$g5rK :ʷ 1/i/|FIڋ&'݌RT&[X]mR.~?z:Ees ^wo_#H-ΧVXTD/۾hճ6/>&ةG5R#^c4Ez&m[ug]d}~QW[b1:z{#lMA!2grN=3L._QWlp|b3KJ I1V>Kߘb_Xd*EEU4r hߨ_6]x}QzGy*=f׃Qܛ:TK{6&ITQS/K 230{5r^y5O<#D7XO '*)(ŧ 콦z&ȳSf_R 99|OmfU_}B'|E8[զ/kؗ0 /!/=B65^07fj}+KQbO(C#ޣm.ٗv\zm)+&b.^zCtt*#e>j_Zв,v2Jced9o'Z.tڧMM"iÖwqsb;j}gnv1ʷs39w~_WqrO,A`E[\uo{:^7ILJǧIHa"@u׳w/`{x@z.~s"7"fIШ\#zGLR.7x`%\KɁ䰮}$\#]U{bi٘2|V|cz7>={,8X+kɤΦ3=iY1>F28wmxXQ=3TfhтFj/۞@j 1\a(BQYr(@R \R[ÐwdCLj8%itjm8fHjԮx,ɍk~0E`{?sa8D͖t—OM'l=Ȱ<@qQA27RKO55ғ#5ǠNHnRk( TNDCLpjCn.i(0=@AkdOؽ@ArFAx,779RswSc1W[RQj s,*{DAx,*/tu,IAmfk闥4>8a)M~~Rz:FەJ eY]*q 8x21J ^~k5W﯁zW>6:PdсD-&=}v T@w6Vſ򑕕s^/vonh`X=4 _h;<Tr (8IdDQˣUr f+_[-S@jΧ(ASxT€z4HJ_ ޿[O"ȺKu z,E#L%.ߘRDڶc)dfG4 =ze8~ie4EY(aU"ab~U#yU!,KL|0Czv\,ZLCR53Q +#r߰O*WFlSkkkr YY3] _ ҀH>[xkIz&[?y,r Pp ~~Oq++ ȦH~C'o'):gjc:|ڇ_+sd&>ٟr ێq$=!M'?I # H`bxj\J sxzOs ?z=1Lin D#1wy@zS* ėp ||k; =ڽM5:\LZ~?ԛ=GCžCw]k>׽S=Yw{4/Y7#G~2P;aNߞuu5ܨX]9{;Fצ"5wttʸzD 6#tk'$!PWė:zHᩔ.^"z&To7}sW'7߀Wޮ}pCWzO/ +|  ׿ IENDB`perfbook_html/node303.html0000644000175000017500000002401011672746163015636 0ustar paulmckpaulmck C.3.3 Store Buffers and Memory Barriers


C.3.3 Store Buffers and Memory Barriers

To see the second complication, a violation of global memory ordering, consider the following code sequences with variables ``a'' and ``b'' initially zero:



  1 void foo(void)
  2 {
  3   a = 1;
  4   b = 1;
  5 }
  6
  7 void bar(void)
  8 {
  9   while (b == 0) continue;
 10   assert(a == 1);
 11 }


Suppose CPU 0 executes foo() and CPU 1 executes bar(). Suppose further that the cache line containing ``a'' resides only in CPU 1's cache, and that the cache line containing ``b'' is owned by CPU 0. Then the sequence of operations might be as follows:

  1. CPU 0 executes a = 1. The cache line is not in CPU 0's cache, so CPU 0 places the new value of ``a'' in its store buffer and transmits a ``read invalidate'' message.
  2. CPU 1 executes while (b == 0) continue, but the cache line containing ``b'' is not in its cache. It therefore transmits a ``read'' message.
  3. CPU 0 executes b = 1. It already owns this cache line (in other words, the cache line is already in either the ``modified'' or the ``exclusive'' state), so it stores the new value of ``b'' in its cache line.
  4. CPU 0 receives the ``read'' message, and transmits the cache line containing the now-updated value of ``b'' to CPU 1, also marking the line as ``shared'' in its own cache.
  5. CPU 1 receives the cache line containing ``b'' and installs it in its cache.
  6. CPU 1 can now finish executing while (b == 0) continue, and since it finds that the value of ``b'' is 1, it proceeds to the next statement.
  7. CPU 1 executes the assert(a == 1), and, since CPU 1 is working with the old value of ``a'', this assertion fails.
  8. CPU 1 receives the ``read invalidate'' message, and transmits the cache line containing ``a'' to CPU 0 and invalidates this cache line from its own cache. But it is too late.
  9. CPU 0 receives the cache line containing ``a'' and applies the buffered store just in time to fall victim to CPU 1's failed assertion.

Quick Quiz C.6: In step 1 above, why does CPU 0 need to issue a ``read invalidate'' rather than a simple ``invalidate''? End Quick Quiz

The hardware designers cannot help directly here, since the CPUs have no idea which variables are related, let alone how they might be related. Therefore, the hardware designers provide memory-barrier instructions to allow the software to tell the CPU about such relations. The program fragment must be updated to contain the memory barrier:



  1 void foo(void)
  2 {
  3   a = 1;
  4   smp_mb();
  5   b = 1;
  6 }
  7
  8 void bar(void)
  9 {
 10   while (b == 0) continue;
 11   assert(a == 1);
 12 }


The memory barrier smp_mb() will cause the CPU to flush its store buffer before applying each subsequent store to its variable's cache line. The CPU could either simply stall until the store buffer was empty before proceeding, or it could use the store buffer to hold subsequent stores until all of the prior entries in the store buffer had been applied.

With this latter approach the sequence of operations might be as follows:

  1. CPU 0 executes a = 1. The cache line is not in CPU 0's cache, so CPU 0 places the new value of ``a'' in its store buffer and transmits a ``read invalidate'' message.
  2. CPU 1 executes while (b == 0) continue, but the cache line containing ``b'' is not in its cache. It therefore transmits a ``read'' message.
  3. CPU 0 executes smp_mb(), and marks all current store-buffer entries (namely, the a = 1).
  4. CPU 0 executes b = 1. It already owns this cache line (in other words, the cache line is already in either the ``modified'' or the ``exclusive'' state), but there is a marked entry in the store buffer. Therefore, rather than store the new value of ``b'' in the cache line, it instead places it in the store buffer (but in an unmarked entry).
  5. CPU 0 receives the ``read'' message, and transmits the cache line containing the original value of ``b'' to CPU 1. It also marks its own copy of this cache line as ``shared''.
  6. CPU 1 receives the cache line containing ``b'' and installs it in its cache.
  7. CPU 1 can now load the value of ``b'', but since it finds that the value of ``b'' is still 0, it repeats the while statement. The new value of ``b'' is safely hidden in CPU 0's store buffer.
  8. CPU 1 receives the ``read invalidate'' message, and transmits the cache line containing ``a'' to CPU 0 and invalidates this cache line from its own cache.
  9. CPU 0 receives the cache line containing ``a'' and applies the buffered store, placing this line into the ``modified'' state.
  10. Since the store to ``a'' was the only entry in the store buffer that was marked by the smp_mb(), CPU 0 can also store the new value of ``b'' -- except for the fact that the cache line containing ``b'' is now in ``shared'' state.
  11. CPU 0 therefore sends an ``invalidate'' message to CPU 1.
  12. CPU 1 receives the ``invalidate'' message, invalidates the cache line containing ``b'' from its cache, and sends an ``acknowledgement'' message to CPU 0.
  13. CPU 1 executes while (b == 0) continue, but the cache line containing ``b'' is not in its cache. It therefore transmits a ``read'' message to CPU 0.
  14. CPU 0 receives the ``acknowledgement'' message, and puts the cache line containing ``b'' into the ``exclusive'' state. CPU 0 now stores the new value of ``b'' into the cache line.
  15. CPU 0 receives the ``read'' message, and transmits the cache line containing the new value of ``b'' to CPU 1. It also marks its own copy of this cache line as ``shared''.
  16. CPU 1 receives the cache line containing ``b'' and installs it in its cache.
  17. CPU 1 can now load the value of ``b'', and since it finds that the value of ``b'' is 1, it exits the while loop and proceeds to the next statement.
  18. CPU 1 executes the assert(a == 1), but the cache line containing ``a'' is no longer in its cache. Once it gets this cache from CPU 0, it will be working with the up-to-date value of ``a'', and the assertion therefore passes.

As you can see, this process involves no small amount of bookkeeping. Even something intuitively simple, like ``load the value of a'' can involve lots of complex steps in silicon.

Paul E. McKenney 2011-12-16
perfbook_html/node382.html0000644000175000017500000002327011672746163015654 0ustar paulmckpaulmck D.3.4.3 rcu_offline_cpu()


D.3.4.3 rcu_offline_cpu()

Figure: rcu_offline_cpu() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __rcu_offline_cp...
...;
46 __rcu_offline_cpu(cpu, &rcu_bh_state);
47 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for __rcu_offline_cpu() and its wrapper function, rcu_offline_cpu(). The purpose of this wrapper function (shown in lines 43-47 of the figure) is simply to invoke __rcu_offline_cpu() twice, once for ``rcu'' and again for ``rcu_bh''. The purpose of the __rcu_offline_cpu() function is to prevent future grace periods from waiting on the CPU being offlined, to note the extended quiescent state, and to find a new home for any RCU callbacks in process on this CPU.

Turning to __rcu_offline_cpu(), shown on lines 1-41 of the figure, line 12 acquires the specified rcu_state structure's ->onofflock, excluding grace-period initialization for multi-rcu_node hierarchies.

Quick Quiz D.37: But what if the rcu_node hierarchy has only a single structure, as it would on a small system? What prevents concurrent grace-period initialization in that case, given the code in Figure [*]? End Quick Quiz

Line 13 picks up a pointer to the leaf rcu_node structure corresponding to this CPU, using the ->mynode pointer in this CPU's rcu_data structure (see Figure [*]). Line 14 picks up a mask with this CPU's bit set for use on the leaf rcu_node structure's qsmask field.

The loop spanning lines 15-25 then clears this CPU's bits up the rcu_node hierarchy, starting with this CPU's leaf rcu_node structure. Line 16 acquires the current rcu_node structure's ->lock field, and line 17 clears the bit corresponding to this CPU (or group, higher up in the hierarchy) from the ->qsmaskinit field, so that future grace periods will not wait on quiescent states from this CPU. If the resulting ->qsmaskinit value is non-zero, as checked by line 18, then the current rcu_node structure has other online CPUs that it must track, so line 19 releases the current rcu_node structure's ->lock and line 20 exits the loop. Otherwise, we need to continue walking up the rcu_node hierarchy. In this case, line 22 picks up the mask to apply to the next level up, line 23 releases the current rcu_node structure's ->lock, and line 24 advances up to the next level of the hierarchy. Line 25 exits the loop should we exit out the top of the hierarchy.

Quick Quiz D.38: But does line 25 of Figure [*] ever really exit the loop? Why or why not? End Quick Quiz

Line 26 picks up the specified rcu_state structure's ->completed field into the local variable lastcomp, line 27 releases ->onofflock (but leaves irqs disabled), and line 28 invokes cpu_quiet() in order to note that the CPU being offlined is now in an extended quiescent state, passing in lastcomp to avoid reporting this quiescent state against a different grace period than it occurred in.

Quick Quiz D.39: Suppose that line 26 got executed seriously out of order in Figure [*], so that lastcomp is set to some prior grace period, but so that the current grace period is still waiting on the now-offline CPU? In this case, won't the call to cpu_quiet() fail to report the quiescent state, thus causing the grace period to wait forever for this now-offline CPU? End Quick Quiz

Quick Quiz D.40: Given that an offline CPU is in an extended quiescent state, why does line 28 of Figure [*] need to care which grace period it is dealing with? End Quick Quiz

Lines 29-39 move any RCU callbacks from the CPU going offline to the currently running CPU. This operation must avoid reordering the callbacks being moved, as otherwise rcu_barrier() will not work correctly. Line 29 puts a pointer to the currently running CPU's rcu_data structure into local variable rdp_me. Line 30 then checks to see if the CPU going offline has any RCU callbacks. If so, lines 31-38 move them. Line 31 splices the list of callbacks onto the end of the running CPU's list. Lines 32-33 sets the running CPU's callback tail pointer to that of the CPU going offline, and then lines 34-36 initialize the going-offline CPU's list to be empty. Line 37 adds the length of the going-offline CPU's callback list to that of the currently running CPU, and, finally, line 38 zeroes the going-offline CPU's list length.

Quick Quiz D.41: But this list movement in Figure [*] makes all of the going-offline CPU's callbacks go through another grace period, even if they were ready to invoke. Isn't that inefficient? Furthermore, couldn't an unfortunate pattern of CPUs going offline then coming back online prevent a given callback from ever being invoked? End Quick Quiz

Finally, line 40 re-enables irqs.

Paul E. McKenney 2011-12-16
perfbook_html/img320.png0000644000175000017500000000067111672746066015315 0ustar paulmckpaulmckPNG  IHDR@ҘY0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@f7IDAT(͑1K@_\* 87b D#B̂ 89t'8q*^.:]6Z3="h>%C@|qj)Y{&@v}|øOTA .'@Pxli `of9t}2S+yp%54 $Tr3ʬ1O=q/r v,b+8xvZ-xZ`O8+#]CxI B/KF = !E34ӱ;h| O9]Lz|3IENDB`perfbook_html/node7.html0000644000175000017500000001554111672746161015506 0ustar paulmckpaulmck 3.2.1 Performance


3.2.1 Performance

Performance is the primary goal behind most parallel-programming effort. After all, if performance is not a concern, why not do yourself a favor, just write sequential code, and be happy? It will very likely be easier, and you will probably get done much more quickly.

Quick Quiz 3.7: Are there no cases where parallel programming is about something other than performance? End Quick Quiz

Note that ``performance'' is interpreted quite broadly here, including scalability (performance per CPU) and efficiency (for example, performance per watt).

Figure: MIPS/Clock-Frequency Trend for Intel CPUs
\resizebox{3in}{!}{\includegraphics{SMPdesign/clockfreq}}

That said, the focus of performance has shifted from hardware to parallel software. This change in focus is due to the fact that although Moore's Law continues to deliver increases in transistor density, it has ceased to provide the traditional single-threaded performance increases, as can be seen in Figure [*].3.1This means that writing single-threaded code and simply waiting a year or two for the CPUs to catch up may no longer be an option. Given the recent trends on the part of all major manufacturers towards multicore/multithreaded systems, parallelism is the way to go for those wanting the avail themselves of the full performance of their systems.

Even so, the first goal is performance rather than scalability, especially given that the easiest way to attain linear scalability is to reduce the performance of each CPU [Tor01]. Given a four-CPU system, which would you prefer? A program that provides 100 transactions per second on a single CPU, but does not scale at all? Or a program that provides 10 transactions per second on a single CPU, but scales perfectly? The first program seems like a better bet, though the answer might change if you happened to be one of the lucky few with access to a 32-CPU system.

That said, just because you have multiple CPUs is not necessarily in and of itself a reason to use them all, especially given the recent decreases in price of multi-CPU systems. The key point to understand is that parallel programming is primarily a performance optimization, and, as such, it is one potential optimization of many. If your program is fast enough as currently written, there is no reason to optimize, either by parallelizing it or by applying any of a number of potential sequential optimizations.3.2By the same token, if you are looking to apply parallelism as an optimization to a sequential program, then you will need to compare parallel algorithms to the best sequential algorithms. This may require some care, as far too many publications ignore the sequential case when analyzing the performance of parallel algorithms.

Paul E. McKenney 2011-12-16
perfbook_html/img264.png0000644000175000017500000001060011672745775015323 0ustar paulmckpaulmckPNG  IHDRZƪyu`E 1S,dvia-(;=c&8f*T0x){ecwe† B+l/ ),4d{਩I wDpb-32/Gi1se+(WRF" QBC+ǹM3y0WJ[w٨P;hcLpq@~vfh<Gv/׻tb L*;VqJ׽ ^Z9]j|qt?ukt7 Lݮ|)ۺ*|fe@+&nWy=pAX^YR٪ }Dmɭ:ݕumk[`:hpM$.8 kpHl&K uZg9~r'Ӿ{ 5CWtEg? OLTTIA'T~ku*5`ͽw;k->q!].{.1d2q_ ~R/eT2Nj± mR~ *VeYŌh\r|aT ]G}B|Y,W6u;Qh;b0{G/sDK *- mKk ,9Wcy#s#dI?(AX3Y9[&h^ƬkCW)![GQϞO6(T@釴LնQh't-r,1 k?A zASj4$WM?BL#<ĎBGIPQkSe$-#+R Z 6QI|V&<*XA14- '[㨵/tp-+Bjem42n6j\Yq5ph(efndbJc$Opxaxxr0osLН}Eh9ӻg F5RC$t&Ǝe]9aT`Mxd)}|&Ǝ"5-pSy]9棱G:Z)\ߦoyG5pHP~|ѡI{t.ڷ).uo.-gѺW1UENb(7`Z+ z}LMx^ kzY;\*Cqu)x 2R;-ZQ,Z>)Zӱ,@N[)[k [! Q7=6Z{[4˶D[4>Zwퟤ9>k--:No§<OA > Y =FBߴ"@fQt궭|((7 rXBS0SC)~ᒄ\rb)Qtwo GnnxV^(7v4Zz+%{JE#k>eNT2^~bw,R1^.wo)5Ff^BV 4]-FmYk֎KHIȗU\f t>D!y^QukB֤Ip bڊRAikb5%pN(;O$W 1[E"R=H8nF+FN"O1dn&$/CsѧZmY2+wFf%9Ѹ׋!;.2< 0c[DDRlъnc#PcvEqMq?9༐9xEL<3v\/zv^Ҧ1炪 ˚[8G4qb =pϮuI;Uƒ^RaEm[6s9=4.:UHh@*sz@!ߪڶbu.+r!#(r_Zvȋ#ʵ%<[[kQ[{И{ͪVbzʹK~ nT.zqxI}GKrvQw161j.y8S=ePu+68X*r eS蔢1iHqW.QF[{8"IA; {8rMrlqSE h{i[6j&80Zx[/'풿qkڣؤ7y|03$[[iQ;\X/BqQN|#Pb7(xt:W֓HǥBk0WڷJ [>uoXg;v!Р^k1_!C)N㿘wuh9qZk$ϩbr zju |ڪz|[WZm7\⮐u>0]X[8o eNQO1c%{JG H$XC!kN2"~^*''JWkCQ/|V:|4d1ar1 k g,t0 U@n0ʠ6{( kèBhxC2n_/r*]!{ErF5!UyoGWډNu|-?qv(aԞĉ/mپn7+$O2ExsW~Y Ȥ|18{Fb<2Raф8HHn<@_V6uA1z'/bB7T:BZ̻pI w-. zMis^Ivky2 M0jUKУv;0&ܬyYkɼKMWáhC^տ' j7i [vj/uF.)!qZYbw ǟ@tn8.)].ZY.:5oaHA^ZY8cnm a?#Ŋ&?'~wҶM|n.iN.EJp:kZRN?&D_5:,RJbfSMO`>`TAp_(? eўx'N9¹zIimQ-793tp#jcaƈ.:ϐ%E0PSpØA,PrBkbFtp2ŋa(=|_ckDcLj\X rx!y՘c5M219j,[5F {FN*8~+oBKD`T cpDFD9_ C1,,@\(Z}:#Z[Fm0y+Ɯ{m<2rPnP߅[Tk_dy[Bn׬φ}\Ez4''Nɳ6yF\}q{ѪMӣadYia959^Uk*Ʌ5*3=Y؊]paݛ.ʞx%8z޵%"۰A/I!®Q!"7#9q! Lw۷[F֖m֮pCw5RumEZ^Sճ#ص=v!HbnEnQgϬ-?<"202A<1O԰--FZ9q3x[Q3[' orS>gx|K;m_In>fɌ3JC| J=ds Wvqh>jɌ3X _>6 3cj5_ksy;INkˉ=^JNΟgkGH da6m_;DΏUvf +Y4.w~ρ3#v%daӣ;^e8*'E^;!T{{!i1|/N "sq_IENDB`perfbook_html/node93.html0000644000175000017500000001023011672746162015562 0ustar paulmckpaulmck 7.4.3 Resource Allocator Caches


7.4.3 Resource Allocator Caches

This section presents a simplified schematic of a parallel fixed-block-size memory allocator. More detailed descriptions may be found in the literature [MG92,MS93,BA01,MSK01] or in the Linux kernel [Tor03].



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img107.png0000644000175000017500000021602511672746114015314 0ustar paulmckpaulmckPNG  IHDRY.d PLTEȿû 鬣OKI'%$񏈆snm=S;tRNS@f IDATxt[SW/!uBLP9UKsǞ>8owO:\`c8llA1=REn*S:pGm؞\چIܠJ?kﻶΜ粇ѓA|!7P(y t'o&g0oTQ- ؜fq*}jjkB[Xp3j6adI5cbW`&TetNA_CUǦPbd1y*TLZU*Wvy3(3XPQkԤl! 41Aa#<) yFapV㨸@"0YZ쟔o=j='#Gq7HB&%5 ԃy޴٭]ނ'{E"+Oc 6 )kԫt[o^9.0U4z3~jfcB&zh`(ۉ /n7}[~L3~_nVl(zUs`?ĽmAlTT;Πt}Kƺ b{hh굿S.eÍHğvT~wz$#F[G3 :TϱcR$b5J:Q9#BiU0(?SmH<ӈ缏kUmxI,4Wn]qyq)6k6M*zRq+_䨭˪/߮cftΰS&ҡj E:von'+f[$dAw_-r:] u?|9Bhqw%bd :JeTX S5VR11ԫw&aA\ }D~qM$[D{Ň /6c:l#Ȣ}.+Q-?dUIU1}~UH|b2H|Ԍ祏&NA?TV`0%r<8XkRy#1]DT zdc( g.fzxu00⵸K8yn>?ėlưKڤukܠ3qݹU _*` ujF`JmE`j6]&G<]|\ ĨV噷]wlWNc{@{-ltTƆnv"S&փQv5Q[9I|݂'Ԩs⚒!a+~^E8JeSFdJu?Cø#tdѠ͸om[r9'd 8{׹KꉃAb˳gȶ#s(]%nJyDRBX-gcK !WhW4r5(r qj2g$arx#(v 9Xdc{9X(,N[ܠ 5nGz|r2o#)#e/rj|2>$~gwրjv ׺I,*e9^V\ٌ4.`M\͑2yYRWW4rmU:IGS߯٥DY#`܍Ē{DTt304؛$u&E c/k+.7JOxn#Ɇ/.g둇D%pE9L6Nk=ح& o-yxN8LЦXdUEa9!֞eQkv0R̻`J7o̜W,Kq,@S1"]w<{3s-4zd k!,!5g :_- PN_x$tp"ǭUw L*dH&xs{j{\aRJsQyĘLwG<4 DT#n?G04jI.888 dn'KUݮ1EΌqҚx}DCD.ZD`'< ~0pH^>Wb3K"D0*"ț%\ÀlhvcDGhԁd:dwte2-A.9iu]KdW"J~rM\R?(2+ٲ\jX3ś#=Lb ǔoD]ؼpNE#xn/T7Ăcs/JuK~dž?u==I>Oj\:Pm d06<`i2l43&jN݊AewzV6@',Q% ? _ 5 ga/ (SEU=l6n `^Iec4j}^ tjt3!љu+*VFHYG1)s9̛aBv_pSnklApAh T4Sd?u68١31!3zy^A$vV>Zs76ro'V _z6Rr%azpV7"m|{{5!O qPoM,s XDʯ{F5Æ:2p.D9  6a ;ڀ̼貒ɝ%xg*YuD>` JɠQn樫cbYiBd_\lwpL[/,Cc~AmX\L ?,H-sR!$"؂T=JVíZgǝlrdx݃qxjdIX6a[2E c|`MdaB-p9,Cl6[C<l_EdY0lQ_-3cWGzMUS|D}Ś&"Bfm - do{[B>wؼ{\- os#W:,k=0QSSbXnO|A0n36Ye_Bo_9 cZTٲdHis:oGs;1梀R3/#Շ}/I{_cG6 6\mk fHl`T XDE@47?.#֪Usnza.%^2vBnnB?qm:B\Wl6xykY̢nQ5SB(nAB]RuςōPS ʳRI_wW.XZqL&jFJYfW6U\5nvᐗFXBV'GHaT&.u.igҀ)fEXKNH jGu.20 MTmQGwn$Dc]tG ^0[XxXl;p(̓t\*SUybtyLa j7ngh& #48I;^cɨz~0KlNm)=*]*3!y$jE&>E'>67o,fҩ5lJN:nvo9 ƶ͹ٷ"\ċ+S1X. kmS$A@ZdMr(<$Go$>p;j 掛 GƺLc*>p-Ka~ܢP-=Mx9S%JS^-)f3|&Ԅz3-A324t-^0`InjY3F3;5(55 ~Hcz=)>%*V׳o&Up"B fN( ̦4-=XޚGhBaaAIeDc!iL _1yJG J-k^K1fN9xc#]ŸҙIL9 lt @+5c{zQ:SJ/ %gu.&[ěYU쏫8`nXoR0s0*o _ԅ`ؘZmMP=w0} g`إNdH+ .==Ah-q2n4<oЙ})۟dLs8dI^Q v7/6 a_c&`BpsA )VU'5 C,0à`|)=mNJI+3丠Y_ OZuqB>99^} ƷOoPh75[q/9gtԕPW389C@6flʶD;,p* =!+V,{~\a񤛲l2kp3]sx"Gz3=0+M@CYP_Mi@Y/cLH* $ms`esx8=I*MBA񘸐R Zֲ?F)?jJ{3Jo!=[rJGMAt z 0M}/rNV=<|/)ݡ!l?ڬ}xZn:ISr1?Xu|.1syf%CBK#䍫ܪoR潼҃=7͂޶vtlEy>Kɶչ>1df2!;0tKh:H9_y1 j:Lvq(H{).U&GO5tx`twa=%\sB XаcsC_T\.TʈxާzpIA]EWS҈͕2Jee }ߧM~iz`8)Q,p!ɍZ ny nI 3w2!Lc(0\払wugP&S::C~ h~{\ٺZшryh$TVЇp7{jso:A&:똥4N Q?(6/]˙#~T';;̶Oz&A=\a#_:" Ү)79"afHY{?!?N߬TvX=:?liwml<*;x|ﴸ#0ϓGHLL-ow@%vnr>Y0\il.Ɣ9#^a9c* / xO&*YEf۹Bˬ9"M[[S:ʶW)C{r+V_b(nr? y6ews lۚ(xTi뇌aUs94@@Ug zvq%=vS* (+pBaS8ydEdVֺٞkI6Jbw}է$N0"jS1JGFdy4yG􆂾et+טVG!'rWGWܰA>רcV{aL=HvBԡnV![.pl՚lmlӲ<{;Z${ĸYQ-(/Ī{F쨬"dsb*7ȝ8adD.`-z@>U[V}0!_zύbl_`%E89bXue!{n4"VowͼrrCW?vh-RRs"2{"eHb;_:7mz=E\k+ +V9~Y,5h-Jڨ#%9r/FƲsە1缄|>p3HS/-_h)2U۫چfmƣJlVG)uVBNL]c/h;]-\`tj.tSmDe1QM89i띩NcY':gkeq:(e~`fFY뽹eF!XIZ#ߺlЛx'@q)fA0VE[A܍ +w52y*։VHUI."# x*4IJǔJ*P=yK\/"Q֙$ Fz[ ORdEP n853́lq3⍧GrĪm!iR[*tŲ]=95:B1qAlZnYwߠVg{ꩉQYkY9JxGE$.SkF\/d&Sn$2qG^`unU}!R+b3! {8q>VL-$N IDAT۞4jgܣ m \, [ qݭB+=mY[Rm1cS2 ؙݡ/8lm#Wm^_t *o-h6, &Qi`ẁ+>YMy #]:e; +vɕJB"Ͼ^v;GɁM9v!5 5OTNz\;G°ӿ~AH j"mX Μ_K޲MLq!LQ 0y[9/'iar'U3lK^eKc"8茺 ڶ3Z.1^֌ c;?NHӶ*2s6չC-Tۇ+Y._7yՂu9m݈|yuiZkwsliSnZBNQPi dFRJ>9vq_`5nu2.ˈݑJh`u2ŞNhrRi惊y<ڻ5͵_Dϟ"r}fr@]RϭEw&/['(}C~A`X~_ $!^؄iY==d0ufC=ibs_W\oD_g_-umN?>ІK5n9`i ` $ʖT(iX6][nx;yWPY@V"B!u 4.2=mo,XDƢB,\IuOsb/ms?gh3ߤhNfރ4av}1͐fϧdb7nT!Vi%Қ9-֕OnȾQj/G<(L@J ^Wi E,::n0SVd7m匽&hՓ.KZ}@A=|Ȱr_cIi-#{'۬RGtB-=~kDt*\TUe lQqP!Y;{6/ج4$ݙz XReʹ2&cO[ 78T['zDq.\v?ukn2N>4jL=L^0cKD$>w9Ԅ9vG?)i6X <{p[lX\zؿ^4!"0 ]h,#ԉ & ^Ai Ih=v%W,fzx}K FͶ4N'Sh?ڋ[FJS,qգyWlŢuWku3Mp c m/%-f52fA&ڼ0R *Vif\} ̦£4uͨgRtt}b%Y1񣴈3iM03K::l6sˎ_v<kBY].c!WߤQ \ģt^//is7O,Z(0-0ěb1d8 HɤqntłzҴk-b QU.Tgd"c@9,/Ax2!w{C'CQm"<0 F.= &C Ia~ TƴoiIJNyQ%K : [?t_}ou8l  l BPq5D}n&xm`KŞ X@ǎav&Igh-Ik* \qMm 6fՂN`p5O}>Vv` nta| kg)`@xsnVDI;RS:'c\M!r8D Hуb!=@/<4O'~aQ[M.tk/rlޟ-ƇkaaL:"u3D+S|^-r)e)Pk^ 4r0N/3Xr^vO{f4Yk>Ylv{ТY<щA%pJؠq^w jMM=(p& M܉M+FZsl quboeQ $qôndM=Qi1a4:]4(Q=\5a v^v\5uk mf,P( G 2tR;$Tu*ʒ~?Zpٻ6k:21t38=0/.TW4}r~h~A}Yq6 f2B67i?5u/ʬząsclUiñ4ɲlzBB?'˂!nkjjF3hyѓ%􀾉41::0[>;M!z`P7ТfX/Oڈ~B8J+rЪ>%~͜g*{m6cЄCA oਗ਼$v@y޽aCءa%:]i PӦOM`ȴQ\R1A`\Θ(Jܝw(Tě~;SW]sTj|dtoT O5g^ pi h/3OH롇~(#CՔ Pt\7Q@:mn)r&Hn9:zVEJvo*{_l웱F]W{ܵyaMۃœaOTFa^j=zҴsMZKE$z઼ q=~w#^߁:b/gf[{qN S676/t0Uu1 hL/ g~Oi~4S(7=ӅغF"+'L] ʲCYBܶ{^'qFQkcdI[) `P0†I,&q~iF f-j!e64E8RK17пv1Q-Ǟ#ck*NLbrHCzƖZS`c06Y¨BW;{T sxޔ=5v w<{C%QizAg )+l=KFc*!x2Gt̽VHSuaoO/.oGԀW8eOƸA{,Ze~> kk`~uO ẚ;ڝ[4rF|<\ET~UEܽWH SZ>(sgtAnߺ1pwo=CS^4:2x23\@_5 \8ԉx ^Bjv]q~;ɷ..zjϞ\.=.pe!/9=gACBv9Hȳ7, -F /)Ӥ x,K&׸ܿm5"AyJD3xy2 2E~1fx݁QӏޏЬveOeo>߾Rww偬oӻ_DI.V3[I7H oRIpn\<})l2B^tF6a$,ZFJܑ+{38NߩOG[9=_Eb{3}+MU[ {:ga !A:GF*Y4j8r%i tORm.AlNg;މu"XeB/UhLA8]CAKLQr bx*o mҁY!(O|:fgQk'~#N߯U"B.89ek3SրnRD؜⒒wG풬ޣ)gSCu@ƙR8[fޝ< dHfS*)⳽K1l߇4➰E.KѨdK}e]e*g YDzB><.&FwыZ5c\~`V\Zڰ p!%9/x1G/|E=v6gTo?&k;*A-^hN}+gwb=4@^zLKXÓf;7xzr?]cc2Xseѵ9*tg싻ƋZoI>)9 u\qyltANa#r譋E0J4^uy\ln ʙ1HZLfx9t-ut;:~ydž;z#U4?^c/ԾqڈP)cA3}kȚ3[Xkaw%{q8|CEVXkD|u;U8h sl!^b=M=k?1/Z^ǥm.\<Ϥ{$CTN9b%qGY w'ftpm۬la3׻uQ Ws&в k3( r>ҭ7ER;bdOr^#ӿHKG>ק.ۼ7#mI5iZ=lEp\wIcl6m;[LQi9u7 ')8]x=u2۵DTf9j7l7,d0S2&>E b q4?4[e9 6&&SdV~sxBd gb GDtآV٫9Bxtvu\c7k"vF r(޸vgMa8فTz]sF-sλҬD:Əa- +{o7n }~WDCp\AP _p5jUw)h(}[AcY@/ngwɏȧ6y@_I,Fp3Ŗ++īs$ vd}ok ?Ϲڥ)oo cj~*He`&c;#u,E,PؐqT_?\ިKݵw;7@^8.7L۪_lEJ&J+ڬ6g1FlkxJqOQ +<hKЛs4Ժ8i]֭~^)D*N% AݓE_\}љ'1I\‹3[w:fOfZR DmLU9%&G*Tnc G1|ОˍNw}V3$|VvK:qBz{m3^Mzׄnm[6oy#6vRIV~!ƗNrXu+6R:#gs>mp1߷ t({)_g\.Cܛ~ߍ'H,|~[Xofm˹ͩ9ȎyG FةWERBU6.İIqT=y2"f$R ,\ׯ̥^^R8.~<жVQicnѯ򁿟Βi7Jr6gڇR W"hZV/ov!+MZ0x[R1xw=4]IV;T]=Y#l|c"*&m^G>6Ml_ZWBRs܀э'?o7E=8[a`ӹa36[&rv 03s2bҦ@'Ѵ`O|Mn;;Az+62K a+g5-=*D;șG%s_$:l™4tݪܗq_Y,ʹ qZ$dFZޒWvuu}_QH+9I=O{I54CƧ>GF[AW8к=Q 4@Sbac>> gdb[vN(dѬ|ʝn;lO|[e62ջqyBbBJut .W0*UP7{6 q_㴑~5zj :{tjjcdg _EeY-}*խn$ u_|W$":QlNt~;F:dYd^Ozr7fA/),e5\)i Ô Imtn]`a*9XVз|>7GΡ['2`yF܌}[D^SlHNhe$;^)_h!|F}E4dxKQnLE]I7_o9ƧF6SoIZn*W{ee#hI:ϑ}0)p\_< )a7"бRUz%|wEX9wr..dq݃&\SN3P-eO!"^bO wPpnF*Y WI׆+d k&=նro.d&qoeOAH` jg+|<{ClG$ ;-6i`K U >y܅ۗWZʕv7$MT 'MȀ?L A.GŝvodpDGyQU.i_+ )`ˋ8Tch_EbS/?:@8 <tVP2&[˔}g.şu_u_<\U*}l!_:TlL,vb_M8 Ρr1ZOiH0q-(bclx,rҙ&5uw덗W}PeTb{}lBojg6JZQ uD*zul 35V&[(Lv?">қq94nju'Q{HJk S_-~9T>n\,Pc q.fs\eġt O"kw eF[m4yޖΡv4dqX!מ?`2WzֻӳOպxG06<ݭm+ܷߌ: qHN#,8A]gVHS^G IDATBo\3]j@Y?k,4revoU=bxX;\C\N=V?Ce[!Ow A#>uh'#ݳ>f(D iǬ?JZm ]I$JQVs?:֒pJ\yP!t ~9rg7jOPn2uB}[Ft1e/3\n;֭zbZ[IN#!n"ҡn rz`tpcqk1Kȍ^k rɄ+7P&#s.e9{s ZAzzh<|Ix<s|uGY,Q[w]1CB8sm" ?RnMLp!ܻlvwވmM$XõBee6zGۻ9**zz`8+_]qu{DNc?{=xb|p1YM]D41jy4Uaź{4qs#h'{l;:_h-˙ͳ0m7d˭I,hSJ`?ADO'5r{gW8g2_"ZgbIZS;ϵ*XkD]Qӑ#vBׁ>aEm^I+MDQlQ!c}'ńqZ&H<[/e(1}۴E8N<=4iֲ6bs ?Tb5_v&ZͻB* /OuT [m< eY^~BHӇ>&jH}܃Q`׈D=kW]=”F.h/}vq휻[*T5!\o' 7N]t|&=vRNpoa璮D~xWHHjs9Ǎǻ_E4qdyqoREޟ 13b0xL_!8$"IδO6!\7ߡ5MH{4Mm`nh pP Q "mS ^ =-\,.Oԗ \;Ye^!]iv[39jN1":6{{Kh|&u(W]ujW7\(|-ReɄn(Dx2q0V:'0vqIT:U/)jGAxl6`&؀U֋uXqs>cܖGf[y&̿r(Ekvm>KƳz}W2 3^>#>2B;pOYhύ' [R7M K-wOʂ*,Z~\f۵xx[/1t$VnMY0%lhƈ5Oe]Ƀnwn_6] ql jVhIGUo͆l7!Vh6hEig' `\-Bə{}&kPթᵵfa)qYJ6 Pz@N7&Cٗ^|E2:>@+k|4R7DHZ,Xĕrwdkfzr3{8p:sj8D[}'^ (q@Dp8m%O^PF!yO8#WNh(j.ɋGa>8-4)· '`6*ÇH)$;Zv,v;^86Vx_VfǛ7W Sf6 o%wdΊ'֊(2^;|f VԜhPىR"b[V];2vtS.:#[ wRu VG`BE)ʢCۮ(U{ffW|٩rhI4 TxNI[#q8¦*-6^)ʽA \E*UwfCL+ң5!dfl6 5+:7Ӓ~QҒEtJnQ}ydoLX,PLV:~~5؜ :e['Ν}*uoѹ-zV@j9W j>8h)EWI f@Y1RQԍX(AcjKR)uyNGLY!dtN쿠P|BXvU-؄cueQ8qH:.xpcD*~[Ӣ tyl)6FTs..R뇒gz8ĤNO@/ 5{DR(~ x7(L>fK8_-Kc8 J%4>; X~`K١zd֩F +Q5x5aqvb V^0z:~gi4#*]sh gHqa( Y8V)~R+5x'΀o90AJaiL$Xtqytm_j}@SI'܃ZfDAPVESu\znuafqa̙ǁ՗5 uk).Na- v `I47m(^'VF=HPkzq5~J;ENS ҤvSN)SnAu˴g^JHSq}S]}^s%5WǍ!?Glە: +,9i{'&F8^')Rw4Vr x0譯]B)I?fkeòܨ7SV^=NW.HmcC /Ju-5bhZ-Cw)8-8Śݖ^f@."LuS)mi8h63ʶjvS*f?*#/lkld}F9j/{mAnĪ`n -4: KÁTg7Uy!RNTar2{İǢ'oPRZH *$6t'CmLe5jU|ݾjA&FX8QX&*z0ݨJ6L Ƈ찭~p/9 4xΠM-SH0*Gl^:/s͖셺5Zm%I=` X" l0L:yĝH"w|*]"d `8ti {B'b[uRD{iFH(ĢהTnaTPQשָz-~Tx8ډҥ8` i!Oc%~=x,qGm6~MGy0ƱvQZqv+rdEihƿA󚃼V_\=8Nwl;ZUX*m23j}',=68Q݃EQ+?Hk^oҴpeAl;~X)=6BR:(p^ [6V>geWm4i^c (}[2k\P`/b, `~;l^VNF.2Ϡ~] 蛏zCA%pFznPzF Q;d M1}G৭OI[u@/b(cr W?Q ]pK-thhR|{"Lah\0L[{g_VroZow7q&׼b*f&Rk9ZG` 3zn ~ ɐJivm=:6.^T_΄_;Gj95Ugw6e윊_-L~^wrMVZtpq`,QګsJ0n.$C,C ]lBi Z/_5dcC3ʘ-G41?qsE۬Q*1k{B;$!MY"K^g: vhлQc+G ƸB2dyu5^n㴪ҜlMv dd/-=*ul9psKÐ.B)sJ}{` yP}Eʦp얢ng EPw@4LԤ8"JQԦ$*|7?ԨFmo8 Cƕm[G+>zJ-XͲs=pV53I^N^ɄL^욀=vk$w:} 4EV86. KNe,=q;ksQyuH0&6GJ-B#EFDgu ՜R0ʨhnX-^rHA!ZhNp,GgfyRXY`z:iCpùtOiɀ$Mحvqaj9-/* |958yOÑugب=Шݱxq^v  N˰y(g[ؼ7 N(+52K 3g7ek/lN96԰O6ɮsj480eש^ԨV֘ Bgf( yqbNcR.XZsX+oWXR}K,#'",X9ddfeVr4|<ƦWv玀1TێDEE *[ĪX7;>Յ\XMRK[~I~ɭOsgHu o[5_|B9mo@@w>ͅ-.*H1VД_9)=u0jQsEYۻ4T}-4[iGޣ>6d&RId*K  ;[<B(`4!mU6^Tx5%iʜeRycr涌ꉂ{źi\-=Wlj:LG<ݔgP,mB"؅5Z#y6Ks:<6@{4Ǫ HԢwP}HjYUS3s*A^,M.$b/ ܎WfBz/p) )+`AT-&۪f 3|3 x;>j侩j\[8@i Dl6/OO23ϲ4y&L\a={`V,R[L\i`,>I\20%x;Mz襧74dW3PmM;g1Bj֓T*?VLh1u ɋorozF|ާ2ROFoMNs|W,^ŎltMȵN_ ]CԻ΅n FSXyrkE{X'f7bqױ%p!hjglPmkFEQ L)'fO뼞x}uo6:⸆Q)+=G!(@/i[v 5.XWzC~ XY>Њm[%3@(}ĨUb*]:nͷ CQ-x]WWD_=@@4pk 1EqS-9+d3mBzG秩eAZAZJ> 1lfI`rZoz67u*m5ѭ~7hf$SֆQdGo9VӔ6)Ñ(& 6>ܞ``fF9N d*ŬßW&Qng1Q<z|&~un:m7ᬑ՟KGo[a~u62hΤb_pSbUoƁ=^i G^͊.'W~յ}]7Y}|>a)s,hԴZX:4Ą8__l#hvJo~} e{&(hKF?Z_P }n-Y:a #Ru=㗼f#^2tIhWXY3C_>nXFs쀵D5 g骠B&t3 zMlVotdqxo䷑t ^Ʀzn~h[@NF WmG;l2pP_\іGwErBz%qŸo ?K=Cz-Vwy+iש7CZӃ%)+5X PO)#7k0Vî;~h Ij^F_r9։뮿ڱfcy9ӂ=OfJA2l<6aӧP B{}>s93 2N [E~N hn)-]Ȭs,:BjKuBݗK]ˉAmB\zy$l  桼VY#E@?C~ei}.޲|+G|FGfLl>"'n ÏtjV 4P9潐A۪^C?io8zW^ֈ=&޶H_ḙ!YVf3)H%5?tHSF%h$B|)h _ڴ)R]6xݣdN ǭwTH'.pd}v1x4>}"B?m,hpJڔ1QT0=1V436Lv;&#"CHg)!XauJ(ԍS~y" t/ qXH:e9`աj8e>ӣ+rh;BT6 έqgxK*ߝ Z$Yg>GBc0`JaF`d)y9Qq4dz/VЛF5^S&:fa!hA+["UW~͍2+-[A7z!޼U[COwl\5)k沤hU}tTe|]P nUwzyW?]\߶(5ngY΁>g W)@P=tnlL̝rMW=r_, wO˿mX (-+@{NFvA5HBCF%MMNOh) =f:`r􏩌U_,O$V{# f$BTn9mk8{uatuE3,]I9.Tp;")tBG*Thv}#q];f0̓j#fC.=FmNJbmɰ*Դ>*6Q {=ͮViuH$vp<Jv:wMAi-_^;Fr3 ޳ K /fUrQޜ1fw޸BR_d~ 5e0?cjUre_"G|{?҇ ѸE{yE= dtuA4FgV#!L >_U2q rܦeT̕szS0`*P|Z+$PL62Q۳3Ul<{%{h} Ş> +B0kRi9hi ?˨ʊhÐ 55og*73vϺ5t;GI&"K׾q}l.Z}-$縹NOm,x='=3FE\ mhIe%Md!ۡQQk(0** oʋV{Qkw3 c\|o(c֜&6 6Yr.G' iڭr:s[ա> IzƸ<}7U4w/j[O^cedErJ#LO),=i!)`~܎>4;6#f*J3fVfG`K*P?*Z 9!$M 8‘Z ԞK> Dů rfH޳+{&#T aai*b20KWo We4jWozCN3}}֠3yw jY˥1*jɿjòQ\tf@$s{h>[Ji{ stw[67VfQJ'++b Tj؋=BK>)cX3ٌ1Y _TW˴3-qި 9!!d  寧Q{oCS{qH9YKB`V1`h F\V  ~Iԯ%؇/^߶ivEqHlNz? EW|_\3O(O#;Bx 8?sOCI߹ofX؋f(сX-/tr5W:Kh)Y@8f/C bðn=а1XlD!t5Xck%T?t"H :c4 :ɛ$zܯޜt?ݛRoиuwwާapp=uZݝuׄW zOq^yHФj ,/@z˩CGqHSiU4Ĩw&KC JI ӘK2<6v`k\\߻_d33hquf3HGW>6agVی UOwEd@ 3:omx=v]QSK~Y s-}+_]699_LDPyn`]:w o~ q91BJJ.Tz@37:,᳖+m0E*9 K@xC@hv(øcLx,+ yW{2B\@7W):2/6h`yy+5\9@zOb'\'W+n\Eӣr G% 8>*Zx2-AiKh,M7u2,b:)e WRXSRP 1|# 8v (ܾU4g:֠ȮtӠ?($ì̘ m6׹Ƀ[ώ l|f\8K\^bA9Nqet0ps(M&irn7N%?c~[{e뱨BZ'f%A vy&ȏp$TC ;U=b|ym6N9dGQ뼂AsldZ@iϚb97O|[YɌMAӲQ%S&Y6?cc^F?^}Ơ>ظ_35_^pv7Az8k=̾ ^eWAXNQ7h9n=I!>o Zc/P-K'=hvルYw:HFwYڧSܫqVfS}d*+ ?yZxz$1?bݬp+W'+D 9!fnYHjc>Q0i}rN5$2& :NB e}n3=*g͵Txto\ ^К͌=JX*)Ѐ9T $UdNU7RTފ2aa<?H 'r r}5/ n[\J=WuE"J!劗5^-w lss}>`cm?s†;lF&jҬ$ow"V.1^gF? fji1T!R;W/pܖ' SYջyǷlћ!p;)#*Maְ*;Z(Y7#R ݢ۸M+3-lL3UM˶Y E}SMɝQUC Ɯ9ʠ7` [[UJJl(l,OA@owQZuޛYhkNV 5;QM+ư ~܎aԟH%r|%ܸMFLq[­iNcvp6Xw!Rm28N'M-iNG8jKPxZխd'/gQ܅ՎR Yazʶ!cϏZ-#_ᆑ2/6ɽ6k{G48res]5ϩU-Vq*Lأs4'MSФxIou0? xyVlRj#3/-(X8hQW* @YohqW G`P3_7% r+ݴC 6 %V&&g٨eCgrص yu&jg? o5JLިro8fo SSI 㕕Ó~[ ~u t]f=.<+6Sg4oKz`/3FW=v3f?{쯒zSTǮkp-~Vxa_dDr*$9ZspN+'FsM]oV4`$ !=ŕT]ⲨSwg CU~Mװm_UjwR̟[}¥+Ւ Oj1VnCD q3-J} }ri jJ75GԃC*Oor-Nt<4Ivln2=?d?d(7[d~k[+)$Oh Kab"ʁBZ OhpS2Ý;L]JN/qJV3m\"ϻYao 0yv^؟l>a&ɰ] cc޴LQllB(֑‚96Vp mf^Nn iݍblØ=*zAYMTױ4ڏ.P.4L%UeZ]?;UeMyUBHl3?GCLVi0*1#̊$N)!+6&gkzݾ,\!a$rl|B.%%Bn<=RFͳ9l{78x3 +#t Qnrgϸw4?&NټQI̍̋4JtG[(V[wwYH`[y54%S?K~4vq[p_BeHu1\Y: H PpYbY VcX5Nr,F;V̬ ;X5z4lsOku@1nͰoERUjuv cͰ}Hb2-y^H  O@8fq6]61P9=CTq)ۥ0Zlwײ Ƥ9p3B?p'4J;S꺼J\3=po@4Yoݑqv1Miy!yu2aXUb-K6;K0嫰0 SXPw?uѽf>+igF5O'i24{&C:F$lʮVh۞VڲU.tX7ӭr[!՘ :kDYq8I 7P==`6*Ck\V􋡀sf)d :oP:-,:cΒnrk* [jy4ڿI1B/ E > <@R#l=W)&.t!tYϏBaʳ2ʼsK#N2EV޹KY|Db#;(&۔l<&/pY]S[)kܲ^(\|Ƶb}\G9WIyPky7̓V);;oe;B1zՃ<-P".cAs+u&.Xf]xq+щ\r䚩 H&cJR.(-y(cݳu4s=޾'njl~6DK[ =pXr9Ut=L/ֽw97~GT3GwÖRpgۣ%-+>Y+ME+;Ǘ/Lhhn;W"0^w17zŋO}{/]vY2Ϝ n|gKyL'y< łR܋pf1ɭ5Du{ZX 5}s6U`ł[v!Wd;@S<[me3_H4EgͿ{O 78oelv__.djYu~(+Z#(+sC谀!xfP-q] MJg=?rzϰ5a.L~Q%Y*l-x}7!rZ\g H RԜDȳG(R ``@׮iSBZ/E5(٪~F Ha>P+\a^QgS{k0#O|c=+"(i]s*|Έu|&ͅi!5aH+p׻YZZ<?jIl+tG "Jx h{zXe/Ir a~Ae¢8H+`X;xivG+.έ,TL{3h> O*vb J$w ĺ,?K.KYE8kir,b NS:.Kik9_2?f\`X\{)wHzZkf+7H- +9wy9%P+5jn٩={2{/s[ى+9.- g^北C2rɆķlͲ7e.Eq2{tsčE* GQ8ȉ +[VO4JPOM!%@0 J1lR8^˩%ncMy`KM`<8i6zD Z6:2Mn7C~Uh|M/buH C"lR6})ΛxJWMp!w%h*Kv&~lϳ4ǍwҌRb 7DS#VF]m㫨*8%Н!g<ᙤ8$2W c`Vaܪ\G֣ҰV(Wi?zdJ5g) q7ﳡ`iUa@H\q!(HV=Pb/|;O؆[qyghiPqQ l!lTxBsQeE&g48r~6ij=MXɮ8l=cZt(O\$,f^:޵8JUQPծ.X ]t[3 cqļ^\8@yfx$ʮe 4NNcƽy0ãtp!x,/cSɏu< C|B[G!#P^]%`uAL$cVTXhȎQh%-yWQ{h/3E6Bx6 6O `|gzW/{rX3INRctJVT H ))&wwvw{eJ˹'U}L<Bci1a  [&z69[/h_-.RxnWBGlzHNan]v6G¸/wƃ҆*/4}Ov _ar 26=AS3XċM6P$%ɞ1>:KE {ۏUی8]JpJ,<>#@) LF,HdC<5=%D(6v:'cۼh џS/#6嶁e\Ghu'=No-NEv/#(^zQPS| Sh5C,Ff"Aq ¢^,I\jB6 >v dBx0`TzK^:U|W n)y6}4rae\,dbI5f" /"mh^G숩Jmb~~Xw;],Ϡ(ٕtn@F{!⪉<ϱf/6dtc4(Ir=y;DhYl`q;ƫd!F}} p/Gnv4MХK 慨\ttX܍S3 /u[~db$H[ӆ 66{g{VZp++݂ec$jJΞ'>9 Jh"L^ ,ZtݻJtUM08YcV"cn #/|d7^/..3UdLQC|U[Kɩ񍱻hc8@]Q̋yjjv.AlcGɞƭ(J0 '=Wu7\6CuZt|Yy&8VءX"t]k1z~|sV@ym_ȜWQ4 K%KcDf]>2\Y3OR\!wqw}Q!Ħ\Ŧf(!S|-†cb`9 Z\ij!_ԑi568xӗe?6nUy۳?xVkktY) A쀭[VPO;3|u'o'SDm/rfGs؍n-2MwhHS `-nA^Cą׎&< WВh<X<%g“2K425gk#+Jb=\!4\ދpE{Ůtftܶ TP_E01m^/% udSLʎ߾X'3`0ض)V::+.T *knI梷Q66cyʀʆ OQ #;Kq}$gZF8 5P=:Aܟx vy104|5[RS5aA0{[[G&BzDž)Zַ gq>n>*En?:ho A!;E8C>E$#8x]ؐw̑s7E^Wb뮞X_Ү2fIuй9]_p)SMLf6PT/l8 (܆fb#uI aU5 4"c6b߄]" x1Ad5ӰX3_eR^x{-݀beJШ˽w7 rs=aL.H-o wm0PS;vP:hpMGF\&xl§]T^JRTL abN41Ho3OL8T6%tό@ IDAT㢿cbx%͆jM=[FHNv sqlGH=8_\ߌsQI0jgϿ~!dg?Z!nFqLEL,΢%˗R{XǎZod G,VHKRrF[Gl4ttĺF1BW:H2?2#i/̀cXuw8۲h bn  A ؜ G 7hu1UmNJnHqy6 o(`+t9LI21iRy=ܼ]Ys-Ƭ`&/σ?Cꅨjuvh уknjRh )H(8v塰)db/x(%yRr[UNsEf|_7;u0m#ˈĀ»Xh7bÃ>J6WG$(7NJIB [ VUUW+.疯$υ ô5NJPÝ{A־oSրdUx>*lHJԧBw!H`GKFxR>R[at ASC߸vbi&$z4;u=l3v:#G> %n;j$s m"[t``ɘ?Fkx7T4Eɂ|L46/RHp8b"a8;B¾/]ؑ~Zժ6 z ୱ#wG+^aRFlqTGF;YGJˁW1}6qT$y!<Ft5^q]uBsKa?GϒUrH>B0^o jv62X0 b.FM]h``( (MsvgdO]2ǤԽڷԱ8bp;S_슺Us3 {>CHVY7cUјΛ--{\s^N+Qt_FUեpG6Q_m~چ%2 Ph;@o,ܾ_(h<,Q eziEЂ8't՘'C6}1G~ޖ'pm6t2Mt֚v%=MkRq|Ƿ[O_xMsgpP qj߯G7$ ̨21UUR z@v/P]6Âky7^KvHH4d)uH" AkOz~*At+`IrR@Ob)8k5}")zI70:QS-n3gx_h.HRT?:F̯ >6f_o6Qlw_|PW< W$ , XZJX+œc 8fIE7h /RY.0!)>C-#(x BEq% 9BpŘwFz>.G):H@ Mmm>c7&*q8i(߸s+KptoABoL˜|ʛ^S'ޜU UMTwl*|[Їv7vg 6>tm>5&]$%@rVF 7|as{]O$D҂bd:DMRR ׉d-nXg^vA#K1A 6v⋂Ex>jL^OSGZH7 yb+OaaoK7i/<Օ]s}dDdRHLD"]NE0Zrɔpem;GDA|YKizr&&&dM@[T,_[Xi뽜k [BP6nĥId/0;:T8KYåd}:⤶]m"Oݎ=ISs \4Mb\05m5iN&Eބ XNwEn[z.x H5[v$"dX?M !q^;9D7O:_?T"K2D$QGf<{[ݽ>i (n|4F$į` 34&1gV0gY TD&]10PiqB|) %@1ݔ1?@^N`n6jFPDVھ~3PGׯsƏ] Ν|h~mڝJOd w'%>r9#9C3Is݆L0 |mO N><~cW@ʫ^9qSLr4 88Y{r5d|7A?@࿛hde|~by3 Qyg|`aMi^5o10_mOn `A\iZ4%78agdcl{Ҥ§`q.WJuǽGzVL{|t{'@%܂).S.%bS= lV+ҊUۧ; {ZLD![\[5e7aʦmޚbgiZO)#ѿCHՈ+}[=z@<5mH,gx rP.]6#} &mbd@6.]sd !Y; !-O6UɊĿSʅw;@<`y(1E&e Dq0EJ `o iY>,󷶳<(&8_u_ ΟM&K5%cINRMٹ<݅/zb1b}|]2zIB!]edK&ƑEܦ܋6|(~ڝ3pʻ}H\z./aK!e4$ LF"k2%;nF9 eSCnɍ>ig+ɮd|ܒ۴}`ޢlD*#2)w!fgZ`K-E/oP:Lz'PrQzfoj-$5cYk钱 hȮ{g~o+Dz퓟Q?W7S .QXVΟ>!=$[ UeO⎥"_'y?DKIAR#j1U9-~$P뢓3༨&x1蔪CMd7URrVCQ,aCc^]zvmd$H}}7CULKZ9(4[۾mYղDC=`P&wlWwN-J,rlHmX w&|ryPy^*1sĨC %:&[tB.Px b{ -put2enX*f>\{] ׇ dY`XzHٷ3ޣ Sn<ή=q(8\$]tU+^XolR)8u\BpXNP{b );;kZz7`zuRJ{,'ևK.RVDlo)~׌})^Ɓߎw{$3nW˒2t9wK |yd́Ga$58 Yrk"c^o,yaa RX5n~+3W;Ą$26ZZz?:{{扥 b^.iƔIQ$)a^kCX )d+7P`07^5/$&E<}Iq@߮6tqrᑎ<z0kqZ{oPbbCC,Uc\_]*QB yU_ɞga,&kq}DjLtE"],  7yp6\{[Wr`MF8rMk$V߶sd%kBvM&&.\iys=q)Iל~J6wxZbL4={1RMa $HׯfY-:h|?M>n*K6[FHkB`Rp&aM~,)C^e)ɗAK9{ـկB+lt:P_/9"o积-NjîHxWfdNr~.qC׀z~/'L05=QN0ffMB,SB5}+ 6ܹ]{{vOmqrKr179n~BicbaQ3PQ?A9 Vp&ioh{!jNH2LID|1SaQ >=q?J+Hx:xRY~`[]'mn:u19ڷv7B$1)W1uݤ:Mkϟ_CAm) <ԴJ f ոh 49% Ô&R /uM] -_5{,Rxi]( %rGSpc!zj)azoIVȓCVTmiѹZgkDθTlRrI>UG]~&ĴblaЭׅNS?7~p޽>lsG+y΄٪P;*(d\zķ)yfb@Y&lllrST`\weϩSKؑĒ un9ZJ1izvot+ٛǝ|n̷/dG91;&E29;ϟ] zZWԉKO-%tEw bXtwc\ Qm,4k(lط|s}2*sOCEkr{gb+(i3xw04݋5e}"44Rv۸&DK8T8g9֮Ps3dzn)]Si \fNE,&՟t-%CުYz=$Q 7 ]m,OUM򧠻4+8/IMV:V:qV }7ӬN |/DJh]XylT}=(6OHQ^ |X+IxsDž *?tB>m7m :L3(}xZo}o/WaA*9-pېʔ @ˌ > s -K ?'>pe&>{?t|Zqڮ.)wi P"433'4iC>vdQSGW_Jz?;{be\ߕս25S&_՘>)ݓiDGvA5|l(qr:0֓r*SH{UU άߖ]{Y'8cg3Yj~k:n,6V74]),)U2QUeiYu b |[خ]67@a)7X9`,ȡ`__]tvj~+ZY54je-SvCԙĆP0[}_]8 <+K5÷P6sITy2ih,'Ta]OųsE.Jqs)鬝Lf.R,cmܲeƝPcHC_[F"l5@M>5U& #< 8N7̟R_$dVDbIP:_ƌ[h YjfAUUc׷?nuvag?0k yBB5_w[;g/W-Oa=ہp%6q8eOZ:=x'Xi)kH$#+ ]f*EѕC% O_rĶ\s}Edo{`bF^ xc|ҵ/,UUӿ: #/g\8]kˬ}Zs˪o TsPT \e+'\ی{99_1՜?!L8 lMNY6E'5mb[ggU0Gu8/BusI;k*5qn<,i!5r=3Uo ?%@fGx$a;ΧaN3o1ή%/8 Us3i AGw[f{ }C L dUDN8JY3pLPxKR#ZJg9Gx޾z'zZ076pSU;x x8 ɘ2/@UOivhUpKӗ? C4%Z*VyƟ͔dBp$ sS: `D˻78?c?JB+Bs06.hl|s5Z;L)%3xHF=CÁұg$%$:y&&f' ~^M8POcq:ϟ'G.LYn\1P~d[Psj.cxY ON$&j]Ή3te| 7:n Zră?djT&^BH,dgk),aub2y6wbSv,GUu/C= խwNGƃ˂5kO+Kzj q{(Mmҋ3 ڢ EG;7z1 \+4<%܄sbH=pߍ\QsW[bp_Wz*L*ߒ9YrXSS  ߧL:aTկ0ͷvj:'TAb7_Q},$WʇXA=)DJ8Qt˂֣Ujګ4Duqkn8_lAUq@;wB֓'1(k0 9IVnwk0kIf0lVXjY$[gRyP wJjEIeMvSCV;:> Kr&(43eQsv7m_}zھ}_ߒPVgƯT+iA\zIC,G>=t<%LĖVlcSʕ<ż60'+@N][NZh]*A n9S Q<%t$=7aŰËLr:V7Κ-Q-bVLKJ?ёaA]MD 6O[+)vy[p`\~EP2x7sW9y0طcMXl`fi~ g Dnk.1ziv"z2),**Td(Tݹ>9􏣇-u o 73׳4\G}&=ʖ={}F.Vz `vnfEAơ(+ϕGcCw3?=WU@ -~gaLpD}.!r+nyM Row[!J+ `~ßW7W@gue3C3/7nkPW U;W~`:>dZM|ƌ¬5tL%%>ٓt fbݴj lZUuK-|.dDMJ`GNƫxp age(A4eO |#b; k#٭(ҝLӤ}oQѭ~p8NɓHC^K r*aذ]x[#1t9ˡۇ$A6i!N8p@ŗ6blnm͔vRUů܌4vM Sff(J0L8r|YO 1VX$oۀc喬sv {cS;_d}J#2`GlG MoV({FvXSRN`8@8LQKe$dVYbZh3o_is+`&:Ɓ>5N~3)7wM*/E#H}ugݓLp MXoKnZ~g ߝco 襬GT*S 8eCo Gk⋩lpH?6`%4z530=~>X;w:&+cI:_v ͸tLtRںyd{#|4/HN5[}.?ysAu+f*UcǼu.+Jd&k^kBsxz.+QVdx;{ KfH8Cӭ,d4~R 7MVP.]ʳvW([.̈́f x$VSjx4G`͋[܆>37l,/.L)uН=Y4 j;~:k%=¼/zNcO5{ݟ<:m>~`JI"l`y2Mrkkk~߰=uPa^[3Y'j%ttAtܳ3UV6q(H=ѻEgXjoR,ffo]]RbRE~ 4Z-Ijr>wf7Y`vso{+4Y?Ć(y  LņʻY]3A6`}}owukT$Ai+-o.~RTj@k9BJ k#Έꑜn954 kb|Mː^PaD)@v<ҁSn qgyɐϢ2Lx̪~֩&EIJ 𞱻BW1Wc\f .w/26~hmݰnna[L&5/0|W^SNY%sy[1ep}h,65ylzi eO/0Zxd< ~($4 + aҺwk(f0U3]N<,ŢMid'4BÅoy>|q|B|U\}Gs<:N:zɷ kbÑ41cNLLg-iKLQѡͨ F # ؼ$dJZ57;ʞֽqkVϺ֔p9F8AЄCܡ$S@WNTuof+ڕm}Ϊ鬬,lb֡ǒ$99)SHq|nXyr㕪E7 &3ׯ"/g99{>&Sp{KW"i.Ds1Ī2 ,Ǔң\://s໤+^sM\TIKUP=n5d+@.4MKqɃ`Xp|/B->t; p:St:' Gg_$CZkr2d]ѳ2p51OϽTO??oqVJpwl@ɺ_k2L^ׇw/ 4K3yyQ򛎎V\Gb%$J5e7cnQ&ZDlE?*ӝY9ApԆe I3嫯=v@<xfOK Uזgx9ms cL>sOvefم,UWfw}S;,*Xϗ, ^v J٥ήi8~M<g͟7xW8+}j=T+)?ۄc"MC_khgOfҮN[-V1);[i_ 2>`mg8a}owچpobeKȹ$;ve4 Z/3򐁅t0nt=nݗ g$#G9l]1kbW>%X3K1@^]Mv/kܚ8ӽi@`!jN{.fvl{*m}D\BKz@-6#4U ۏj6$kۼ:W¦AV&nv L{G^K}$Vu6-.rG-,םWΥóPh)ҽZmx IDAT1E/ь}XPv:i&-XWTCDXQ_ R@>YW DӛWpգRIO%Ӛٟ&}Σ(C, }}}zu .K8Zb5ǝ@2w.-XnjuuZX³ךxg`_"s8[_9r]ikLh)BO"LW[(縢'WǿD@s7C"a5;<Qn3nAaSJ܏ddmt|~,3Hk_4܇QA<9No[[{Β/_VY@)Wu-Υx,16Q,DbOh]٪r,WrȻ NUw{vj%:t*AjZ:꼁/ϪrA+D5*ta;c 3*feaʇAM(ra?%B$^+˚&G,iAs]ϿԁgqRBLMy*OI?҈J,*s\EY̖؍`p.nw,yթ3ȸxZb)Xĩ{;'b>ت=ȒmpMST(1td$rzPr9{oR4/k8p00bX@d1hxzQ$sj1]0lRqK }~UNpz__AoE0\Ng˙d' nHB>ԅB*ͬ㖺yo$+@̫f)P5 0_lMsZMm+bb8J9U\vf "+b!A v(b%+CH,>r"%L;>OR U-Wʕ݊`l8匿YrQjGOh<%˩B՘\d? .TGIDį ͝ULnm. »vfs#q2WNRe PфʭR!դVK'3p -;18J@gNZ#%Hi|%1@蹕* `1"COuDq:x`}c37w9zlG/X9%++M޶ μvBY{enҚ(,ݻks{pP>FzFSj"]:ڰ`KVZjukߪ9M~V+DY0ͿcԳD0@1H(Ȃ ?SR;!'B'fz;u 0"aX{ja]0%5R*p\N%LSВ/:~RH2)1?m؛'n@zxX#5IdN1QK/Rn׈ƥָ&tP$,4%𬥨/-pN c36|}| 36#@[a3@b&zC̚kUwJW>p&ԯ[lyWD4۫_W\jDV!fTV(vp߻Ż2]Jd?Y:LJ1 fQYcٓ^ U #m<KՒpj4P\~E#+tp0YDx3$sG|Amsɗc~1aBY{azf &ovc ޥVKn$kU*&± yyKm;ĥʜjeNhx'pS{_v z'O=R r&/Ӫ ̆4w!ilD{L3C/ƭrRZc|{V' CMݵOkJ^k#ǂ^80'ǀx G#kx1?'6)4YiB Ŀcu.gw!E[Nȟ⎎/^XnqP᜾2Mܬ.ixn^^nL'h:W0J[̻ 5fZl X+v8omXr 2t>yi6,Q6>8V]jyO=[ތ@A ¹޽̪@61]DOAQ_p g2) ȹ6HWSL$?`f[Şuݶp_uߴܟ t-f]jvLvNjV$SDgJJ޾X|}D Z8dz#݅.U`<`w|`WWMނnYiko+1Е}T5iUZ19`ڽoUWNj?VKprWSBR-}OB&Xi3#&YkVFl V3F3}'nxc6w/.T<[3S4uM,[ǃ+o*!4n Ѝ1)ιK=SBLK蒄Dpn]%idx/ݮ~dVWۘ?K4֣e72Ѽ58IcLMD~wO¾09VdZ^^Wm:5T9>%/Y%;_' O-ܖX@7Si`B%G>:[RvC%VƹD|S2)#~Q.*bNkT&/J%n8|ٵlxqV0uh`O$;Mpm+ pǰ ukAN=a`$¹D7? z֤wýWe|wS̖XjDž `nQI@T0R?*Kdש63-zK嫎S_jKmNSjI6jo"RT6.T/ݭʫn*8K%evs_tRFQ{e}~ѱXΝ.t[}}\v8%NеW>U(K++L)@ea;l!6W{ 9wTr÷9Ax-xk^6/X'OAތnf˻~eF&ںT7+pg2%ԩ&N[NZyeuH78߲r?tjt74Ql-*87Ic<:eZsRwWT?{lNtܪc 6Yizq+sFa)PQLĤIOaC\xڒd}$ <7fCk4,;+N}P>:b9S;oCwdOՀt$ Nk@f!FC$b7, w"L-M=o)%R Saf$LHs4 cm!2"!fɤ DBrLtd(|ڈ-|X0?u} CG '.n;EgWaӪ8F6+`'E ߌ/]&&s|ɅPһ[u[x}@nvzO ZޭuQ 1(M/)x\e4-'e {2iinDv{oVW*::ƾYhh@[n nK +E5;8,7U `03b (F҂zAhmg_x 80٬rdS>arj¦MbNywGc7Bb x|dØAZ*浧cj>ڍwOy*cmKΕLN_8{`ܮ3SVz -4"ֲvyrݚ'K!ÀAg]ov)6>@7v9]MV(e|!& H^reA`4 <)Q$(niX3( Ol<ͭ~&?]WJ6"B2l<yE cܐMڙ,-hR(-ABq#6[ՊQDx{Mid Csm+Dgu%CӄoĶ`l>o4${vv˳өv4[My*7q_+u|XW7혮&"= BnHgD:#Ќ԰ bnF.#se"B$2NÅWNK c&} ~Q Op|yd)l7'ҷs qma$a̚SMk aIV  GBu;㫅q3_N¼BFliG~2w.ZbwsԹs%XN"{ȇ1 7$ Ղ`tUẒwjp&M,߾uQM͕-T,4㝺/غp EXPrvִ^'qTF{bZvh$M (rCANFbR/ḱ=N?|o=uNgIK,FiTP'a,0aX,Oi!a7/pv/8Xf=' /]TU ߀H"xڼW.*x]#MOeVԏER;+}%+f`|mZ/">=¬ zU"KAk>ܑۯiJ\fz & f<6}*H:2%|5@UP 0%~i|.ȋ?,.< Kl"Uft6[ҦS)~Rfu=g{O#]qmӎS2ZH7dH4:d;Ea#~|#5&>JIҿ$-#`i|6<Yˏ2]PfJD3q Ԛ>lkdAHTv( Mq}_8N[Z;\w3׸򩩱=xh5i*o\&pPLHFL_B\tU!%P*II˗Rakyd0<A27"ԑ2 00?m-p y5,FLT2pSIz14=ŗsnjb_ jjs_8BR(Ag;M+eiuLyy*t9",M,}(0H;r3YIe^tW=)tRR'q,aFk% vU~%B7xլ"ec 2h^, _:A/ I(O)&H2R iˆJ`B?eoalR?U'\aJcI9w u#ƨ!-;_Xʽӗ&lLjM=2[pVA R1crʏJVu*aܶ',ဴ  "ݭ)-J4u[&/>"_a| ) QQq^-:vj\!*F?}B v4гmS^/# sb>|U(22w X߂-#q4Yhd2Z`K:㈌g !SnAiAON?t3mtGVhz@ 4t-zҗ"h#3սx(raӾ6L.㕎J=xRV(d`ngԪ97d\*:6W  j1v07W8qwz+SoH. QR=?m&m«P]1 R)?@~)r(l<1O ҽԔ&nwiiV>MxSj[ݒW5FfkB LZ>2^T>Lx(gH lÜ1=\:Q#ƩrPJk%|bl0MXTl>Z|j$pX9zvI<~`$;qug띭VuuZ֬?#S#(_$\n4,_TC|E[qmחO-XY`w!eJe Tjm5F %h0If5Dx~DQk W>S::W ȭ"\:uj)+ a;Z~l)TA~_DR~8}YXzY f Ob" 6oeYS{8o^}=&6lz[-%A` ox:ٷl0C&l%-pꟁ+0QG_d/G·{?w{,yЎb3Q\H R2osC! ?0xp5mjhI4ޟ3Yk;SĒg\:RBpZ6r)>gGjnݛ<Ǖ{XOHJQqzYF6RCLD*mⵐN`1YAa z NZ.L%xh׭~2NjIdUL&B:y Hʱ*Iǭ̵wK6ՔG_-U V^Oծ՛u7_h_)?OG:q<aӅEҬX`F,Q"2,z5-! A7=/;0t/Ded~ΆeK~fYiΦM6jjၡ0$M38 |p(H,Ϻ> mHa-I|FbLz ^X$m˝ >yYs}rh}p}a=t0c &qn<4 MD@3CFz b$Y2/O8jNl)= o?mS~mu^~]O0a ch +AZIrHRf ADBH&x_|x\59؊ ފ=ul<2Xl13d憐JNE~VaԣNd3R 3F$%d/!‡K! /a$Yw?ot5e5۶Qh((ɿ ɉ W$kp LLi0e=CҚO3}:N@lN@C&^+ߺuHsYQB5zf;_j~2tș, Ƞ%u(y).F{82⎈#PܷIB%XHlXJpVũTzu!SJXid?<>) $t'~_u: kJvy~$SćnXؗ")glCZF(gp8lz'`rD.LC8}5ѿ;L\6+B@p 6 )C&d?uZhًg=+ret&0 )e=w"@Do9>1޽5B L[ӱyM 31 ) `AJx'~%EK٩R9 ,< #{WP{m%lin2=ҘLf]ր/IP8PԂ>$c 2F1/3K&niaMb (T*6c:|GhR eZ"1ORȽ(/-d"ʰX*@Ŭeg?΅K*`зf.F!LRK3AP-Q/R*%KGrูGSDt8Jo@Д` 4XL*pb-ڀ/~I%mKߑ=*< 6H25>WjKeWB3J:2p%"r"GZAE*2@l#,fNMǔGG)x218|yjO3[njA? ntOE\te'#/57Z6Gɂk1R"` zX(~ r%)&$HaK8gi2DWqğoX#-ҟ`}(KV1'e:ǘgpE@I^3kHqŸIz%Gg p0bʲRb@ jT 8%4(=T t(!PIENDB`perfbook_html/img55.png0000644000175000017500000001607711672746043015244 0ustar paulmckpaulmckPNG  IHDR7YNPLTE\ZZMJKPMM# b``mkkiggcaaXUVFCD856412iffKHHC@@A>>@<=wuv.*+qtRNS@fIDATx] Hi)$f9fnBYfyTVWR66'}KV:**W?KKw6bUk-E8{T:AuکȯAZh.\:߄T1.ѥɥhUq5X<_𖝋T-qyFx㕪p VUne5a먡Ia[¢=7/_UwH8`a!^YܹD͝^W־嵈j YR3KۣG7Q=UFv 㻮p] a oZF-w-uLT V{~Of=cB[jC#Aғxȍn+ 2Ck{ꯣ lVeƫH%*{%zp۲|&6,)Vpܣ{$: .-MHiknыȓA{״ >{>g d@{Vvb V+hk'Xttl/PUGV5#9-U m,:>]Yb +kPL\)Z`#Ym_>V52'W~2*"աXFqJ>(Op` lsxx zMu \wT #XXg4NFsB# i6M7qnnZ^yV냊OG ZJzJ2sʀLsgUӴ̠xM@sU9iD37=i3pJB A8,MthH4Hke;Z\*-% 7X"HomTڼN_^@%vQ#~Piߛ l"0\ݬP|x;ddKtXdkvؾY'$Qe6Ynd nr `t&adPU8 PiW@͆.p{hBEu-%zK&Ty><+2ּ$"x-3GE}/4(S!cǹGibMrB/FL,т0UMCDP.a7g- Cp]VB[b5\ w0`sTo*+.iI1ApcS<+OPkKcxqzͧ$TA^ItHJ5 O53ӊ7io'TU80⫓k;eYuBhγ[)Be[ ;ZZeKڷÏo"Qol]N4CK(g,ME(l" \4wl?d?i+!kee_:L/C4D0 8ж60zRTR'΃jhS xVDS73a/47 ؑOkJwWGXIe?g ^7 mWcK wγk +ȏ= ~R?o} :VDyܭ 2kD08k>αb=;! f/_QCӴҒ|Utga9ٱbKćV0D;^۹B>*yAVfuk tV]6FZ3 ȠDxέ &Oi(A_EX}_V)z 4<8_9mJt~^Φ1\؈9rϯ:KQa'N`8 Ggwbҩ 6miUYɃϥj{a48(ǐivDiPI5:w9R'NuJt9a SǙO\U3*hωW yKD: wT_:ymBÛ5"0KNk۸QY>ͦGsQVOiQ{JJuQe6@ź~D2~" ~ay"?4hTkjm럆93oF#аCsD. ' qXM褤TQޣ^5HdaoalŰgG4'=zpݏ'd ˑ=,c°INV.64U !Nh!sn(.3 'M5!u>(%5&,ZQ}qrfH7L2=KSN:hx&wHx\#555>gIn,M]9QNmR/jֈ߫)Hg Dξme :" hfIG!hL:+N8ϣ 5Ҁ3|( }:q+;{RBjF]9dh8J{,rߺ`,E7)#ԤWW c!j 5Z'`?|Ko"bSh} k+XRD^7}Fr8#O )vjҒF+X{/E!3=3$ %Ӊ89Q[GޢOsJ?hГ7U!x)Зz~e}zK"q0Q "Qxnɧbb:UzcuVY/P=+M=jJZ /QKƾQIHf+,,ҍ]tzojg㓙T(:͚&Y _is?b -TE}fط|jƍcN4+}_].ҷJv$2b= tT!J[TEEB]"Q{>}z$r2HfpUǍ88iF@:m74/d d m-&R V?)>^6xU>&؏SogXsb Bn$o09hQÐM)A#mҸ=.,䑀ϞSJϕfѥ& d/Hpg"TD SđkÔ+Ʒ+b»7[מ* c]a#\aV6=9$ }bM?#W5) x(jkufFاRܞt2n[w>w.9O}ș(Ö7:IͨFݧƒ9:kApa@3-@pd}{@~J#L_((꽦G.i.N?qf[۴C1\S( ?bIM>Zۈ m锫.NգGm FAB}cKc0;O+MK_ҧsz)gav ƄOu?R} }q/}LQx87^*]r.Ɓ@쫚%^4ɤ݀c"oФshKqQEs\4Yթ tqW}#Ћ5A}qU$hB*XW'p=j@J{3~Ԕ0|f꿚~7UVu)kraƚI >ϼtk&Umrޣ D [&[6<]r4֘f~C2Tclz ]Jr; OWj8w?uY7EuMM@֟Cp;a};XCI'fZݶpha:zϐ,}#ߓ5T}}ҿ !Jԧ*-X+:s$Zm/f;1'TX!(\ ;x&B htALq Kߢ [iWdlWdKKM.C%f&>%H@EgX=s:xcү".G yzZW0m$x ]7wt j'>xH2Si@Uxv6d(zj/%&$\DMҀ`# [kυnw7Z_CKISo,nd:-d`|y?("P|QzY @E֓i\iMD _GDfq#7zޮT]C(G|m[f_ܰEr.N!U/DZ^}>'!E?> ?$sl'Nj;'[Ul$>"Guӗd'1\f/N*% !.e5ȿtďk2R5\klbbe1Q֋gaFluy߫{]?&Ğ#d+b|U ;tl6ޯm&}B _,}Ez±C,OKo2ɬξ&k-ʵ EŸMF!=m߼9nbobYx]_Kp}3%{ZrqEALh^F1Kp6nb 0ҷGN}O#f3 [;C6,XTM@В25U dWҘ=I>y1C`&=A)c"2,1D\W~gO"訲`ҭIZ[8nVPJIv5%K=wAu7IL1ҳTeY hNbQ5 ==9a5)IENDB`perfbook_html/img293.png0000644000175000017500000001715711672746045015332 0ustar paulmckpaulmckPNG  IHDRg vcPLTEb``^\\TRRMJK# gdeywwvstmkkcaaZWXXUVVST856C@@wuv.*+|zzrppmjk[ԗ tRNS@fIDATx] v)c@K2chBmy܊K5܌q3J ʪN T"jz A`;;Q ^(WGܭM?mZ]a.!,&5H+}ko >]pJWۼIC{`5<">e~vnޞv#N=ַK?C}xnw=mݩM8،/z#~]- d4fy<&ov7=7gλ`q㔩I- p4ӌ:i3]E<;}Dkii"BB9evF?C0H32qK:- _a0I+'^[+o;L?7"jseg+Ӡvy_;]^/p{mcpN# I㐰Ni;<{] Mkz:SU~mlV.4LǭuZE=l[XU ~)*La2˵[˟aZ+n |#D1BzHmA:y崂aqR!FӐ^:@;-xtD龪yxX'O#D e |'vkDΨG<5o5NM?_}73biHJ3$`i)SFKbC%O&79L>25: >opgoND)G\n 5 .Zԉ@iͿ?^0D DF!Qά@#h<ݘm^> NoNN{" R+ȞGJc$.TKPԿʭ8 x6F,Z<&}`q-~!1!lpA \ڄIGaa:)0]=A=LݯE5fL0X cH{US"ڒV!˽HU{b@ -HX=E. C`Nl!p^N·s awJy~}^EiUD$SƝ෭x)m!7mH!iklĤw}ͬ:;}N͙lX85CMYj_& @\5($Qgr~##KdYPϬtsT9J\h2 :+f?7}lhl )n&X FOI=־y$oE򋞩.Z>׉/H۩Tz>F~xBӐͮ#D/[veN M:Q]gK4{#+$׊iqbU; @&>N|'lCBӠZ LӨL;i}"Y 3F$y _ ;:*v'"8>iCὛXRbw`* Pd`HE/6l]Vw(#!6™ Qk.fw,hdfr.-01~qzq.ec퀪Vvv4AE6 $ctJ(ԕQ㘄}~*݃7Эm4 R+,П0 5n AS,.naRg@ s\\SG&e1# Me Z=(F~1nեy||1\:y6!s%cRA#Xk9j0 m%ʄ:UTQ6+Waڣ LϕP[hFƜ{RB"腿CŽ#I K#ܝUT|"Ubt ."ڭYLܸ=qG߮$k +T2Xk#G:{4yh62t/gA]ˀc)pN_̔4>HD؁VzHR#9BPiVY =zCqA:|3XحdQx {R_Gh^ .S=SSX62hYVE+6h`d8qYR@7V츥uˎӓ[2bIsImBxK~Pyݾ8z~y2&?:70]+/wd,z#~+>U,czFy\-mVI֑w"qǏ)R>͟_>YR,N}}+\z3t*X:낧'b$,عPƠ9Sgv h ˋ)S2Ox*33ل<Si}QvN\A%lBqĘs2%=䶿 Edvٱ{POcO,٫\/'glD f̴ GtA&wW旀6τcvǓ|;tęJR6ema%I! 4jMX4WDJ0q-m6%OzgoY"&-tr$]p_n P9LD.1OV nԅ孮:ɶϘ̴Bf/#15Ëh9%ټ-KM/U6۞p Õ"uP˯Pz6E (19b0ٲ>Dh(Q6G(ӐGlq'ǩd񊑏⤘\e{]1MMЃEm dN⽷0=`i1_%N q= ƱM[42¯Tbیd9ircQ;)r٤G)5;⎍#lșElqyX0_ OP^XG~-3#v{65w`S-q;>!?n2@Ҫȱ#L cзTlt9ct-['$X_L2aԈx2Ʉ6 ٲס{f:@Od9"4C(i$~ ##M4N_ch6N/dC Wgvj$捀yòfsDH`V M.Ƒ , HFm/, 0c#$|4{hqIKiR++;ѭv"AWx]5,;4ky, v{=dR/Iʉ6XX@p=W aSHw]EEEE|{ipV#%Z3E5b~+Ҋi2eNt%;6_nV;!'_øpd!cYeҒ͗99 rEHur<DǹRޝ~ywg9;f)YtDKH4ٓcLm^t~u#*5*8טWj$i`&(Dm Pɇ =?s8W7vYoJe~aFeKsyS&Oe üxdAZrAqٖUfޭRAz6lqj<)l7?>8^tEuk3GOk \H$gƼ(RwHt-U`,,[+G6O}./cgԢ5"B(yYSDR`jʘOJB]8S, :BjaBaYb^Hd-ɡkrM/Г,EKiTD/V~Ԅn)\ -o_PEh#=`L ]ᜠ7C , &H(ΐqKyˉC7Jk1ҷ.NUaP`mࠕYq!ĐvK]ݢ\`tnL]4ڨ8:sҺẠL'zbrMbQn_,ʤAZ9J[f,'YGNZW5\s?[Ž/©)x!qM9 USpܾ(J2aJ",yk}a-EX,+"$&oh€Z/˔Z>)NfdX-ǥT)ƚ%-̢d~N+&i<7/)}1&jyiY?TtO0>"auŝE$.E93ESKY/5e#(Ogu) 6DYQ$SK&߄0:kdq#Ǭs[sمkC,zDSIZ>X͡"I\ԃ:.$4aS"#z67C c;1ԝs.\t*3|E-â}"N*3 ˯NjW̡y(T^[v9%,3i ITs.\)rP,5ZՓoYԠ:mͪ)55[HeEtĝxz"%g1hsw…!0#w@oMsU{Lri{2;br_Hk}CUT*(^-eG0M|&>*({,Orrsq9yro_Ozү O&uBFL?nqJ"9y׎犊'zTmi;: f7Em,T٥x(Z-*d*TFcXAvhx;guBduũ[٢T¢pʔcKY6=y ޗ4^~,Z <4p)TPY->>sV'DZWL}xOܵ+Si8_d)2U \2A{2[TCN\#TT ٢T"wʔcy,.%9T13ɓhhlp|~.i%ES.ީ٠o?_%Y1hI Q@j\K%PEx@?"XDm8dZ 5j? hAiBI0,OVrK "SpE.§d/Kfbo(;ɓeKǰgFܞ({z,H1C{u4VK?:) I^(}@|"xkPU<`S1/ɆAάm9%_ #lAE펳tOB0 Ecs0eY:iv&/;ҙ!K z*l)JÕ ,,gMW$&LK2ߒ\s^A2Yc-r[h2s%d`[Z&Iq************x~ЯeJ{[$H4cNbL2|ɒ5MAR ͶwHy\vBgT}YP ں̃>Ej$l =#J'l2/f) j}ٞvtGR7[Uɓ3r;+x?כgIENDB`perfbook_html/node334.html0000644000175000017500000001674711672746163015664 0ustar paulmckpaulmck D.1.2.3 Update-Side Primitives


D.1.2.3 Update-Side Primitives

The synchronize_srcu() primitives may be used as shown below:



 1 list_del_rcu(p);
 2 synchronize_srcu(&ss);
 3 kfree(p);


As one might expect by analogy with Classic RCU, this primitive blocks until until after the completion of all SRCU read-side critical sections that started before the synchronize_srcu() started, as shown in Table [*]. Here, CPU 1 need only wait for the completion of CPU 0's SRCU read-side critical section. It need not wait for the completion of CPU 2's SRCU read-side critical section, because CPU 2 did not start this critical section until after CPU 1 began executing synchronize_srcu(). Finally, CPU 1's synchronize_srcu() need not wait for CPU 3's SRCU read-side critical section, because CPU 3 is using s2 rather than s1 as its struct srcu_struct. CPU 3's SRCU read-side critical section is thus related to a different set of grace periods than those of CPUs 0 and 2.


Table: SRCU Update and Read-Side Critical Sections
CPU 0 CPU 1 CPU 2 CPU 3
1 i0 = srcu_read_lock( s1)
2 synchronize_srcu( s1) enter
3 i2 = srcu_read_lock( s1)
4 srcu_read_unlock( s1, i0)
5 synchronize_srcu( s1) exit
6 srcu_read_unlock( s1, i2)


The srcu_batches_completed() primitive may be used to monitor the progress of a given struct srcu_struct's grace periods. This primitive is used in ``torture tests'' that validate SRCU's operation.

Paul E. McKenney 2011-12-16
perfbook_html/node311.html0000644000175000017500000001442711672746163015650 0ustar paulmckpaulmck C.6.2 Example 1


C.6.2 Example 1

Table [*] shows three code fragments, executed concurrently by CPUs 0, 1, and 2. Each of ``a'', ``b'', and ``c'' are initially zero.


Table: Memory Barrier Example 1
CPU 0 CPU 1 CPU 2
a = 1;
smp_wmb(); while (b == 0);
b = 1; c = 1; z = c;
smp_rmb();
x = a;
assert(z == 0 || x == 1);


Suppose CPU 0 recently experienced many cache misses, so that its message queue is full, but that CPU 1 has been running exclusively within the cache, so that its message queue is empty. Then CPU 0's assignment to ``a'' and ``b'' will appear in Node 0's cache immediately (and thus be visible to CPU 1), but will be blocked behind CPU 0's prior traffic. In contrast, CPU 1's assignment to ``c'' will sail through CPU 1's previously empty queue. Therefore, CPU 2 might well see CPU 1's assignment to ``c'' before it sees CPU 0's assignment to ``a'', causing the assertion to fire, despite the memory barriers.

In theory, portable code cannot rely on this example code sequence, however, in practice it actually does work on all mainstream computer systems.

Quick Quiz C.10: Could this code be fixed by inserting a memory barrier between CPU 1's ``while'' and assignment to ``c''? Why or why not? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node330.html0000644000175000017500000001155211672746163015645 0ustar paulmckpaulmck D.1.1.2 Isolate Grace-Period Detection


D.1.1.2 Isolate Grace-Period Detection

In Classic RCU, a single read-side critical section could indefinitely delay all RCU callbacks, for example, as follows:



 1 /* BUGGY: Do not use!! */
 2 rcu_read_lock();
 3 schedule_timeout_interruptible(longdelay);
 4 rcu_read_unlock();


This sort of behavior might be tolerated if RCU were used only within a single subsystem that was carefully designed to withstand long-term delay of grace periods. It is the fact that a single RCU read-side bug in one isolated subsystem can delay all users of RCU that forced these long-term RCU read-side delays to be abolished.

One way around this issue is for grace-period detection to be performed on a subsystem-by-subsystem basis, so that a lethargic RCU reader will delay grace periods only within that reader's subsystem. Since each subsystem can have only a bounded number of memory blocks awaiting a grace period, and since the number of subsystems is also presumably bounded, the total amount of memory awaiting a grace period will also be bounded. The designer of a given subsystem is responsible for: (1) ensuring that SRCU read-side sleeping is bounded and (2) limiting the amount of memory waiting for synchronize_srcu().D.1

This is precisely the approach that SRCU takes, as described in the following section.

Paul E. McKenney 2011-12-16
perfbook_html/node180.html0000644000175000017500000000613611672746162015651 0ustar paulmckpaulmck 13. Data Structures


13. Data Structures



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node309.html0000644000175000017500000000644611672746163015661 0ustar paulmckpaulmck C.6 Example Memory-Barrier Sequences


C.6 Example Memory-Barrier Sequences

This section presents some seductive but subtly broken uses of memory barriers. Although many of them will work most of the time, and some will work all the time on some specific CPUs, these uses must be avoided if the goal is to produce code that works reliably on all CPUs. To help us better see the subtle breakage, we first need to focus on an ordering-hostile architecture.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img26.png0000644000175000017500000003302011672745752015233 0ustar paulmckpaulmckPNG  IHDR=k}NTPLTEb``\ZZURSMJKPMMFCC# hffywwmkkXUV<9:856URRKHHC@@wuv.*+rppø tRNS@f IDATx] ó,rՖ]V ((^ED.PUUU Tp@ʺjd46M{QobCU ]}Or`|A>}ZI}ouW_`%fRRwﮃbbhn]vK"oRGmg<+m=첷VrճǾAM(8zT wVfQ5z+=C 4LAM5ۼe%[Fi.t$NK2saOe뺖Ou:c;Q[ɤoO=3gBOoV>ߴGbW/Y6hkecoLJ1̎rf] fn1}7Tboj0 >g?r9.57:x#|ѲM ue{dK4)C{;h6Ab5R54ZZ7 yJ i-VI.ŷn莫C9eS Ȯ%vrjUG~cuFp ^p(c-a>(3\RA{i .?rq}:WHM.ρcm~h>7Jk4{y{"\ƞJ-|DW0SU?hQF{vTe!ƕ#!NPw /ۮU5k!ܬ}P![h#[Z,$. )SNѭg6J Nkpy@e wA`8j ˱cֈqlnsgJ~=\ګ@@z# |gN(a0+)^0>^l]Xӈ^ae>D2N-ї[3pͺ}O0HP0ӪȻi9 cDICl~s/(7r~ZV_Q A#̯ maz]VEa0ZWCW`J \»7\r0C@F}KW"!h}mPU+ihk6RZMx0Mw^gRFDhrE{My@:+%Ibv*n.Z(=ptM٠$ ۵ȪVKm0P9=o XOϫ~2z (Y4:h\=uTU({<_WASv9%(lNg8@*2Q=Bȳpj+f񧆗0|Fbtl5rkjp4^BmsQŨ-*&t-;NN2tc'ԕp75=osp{5h [/P 2q5|BUHb꧝ckaۄ5UP ꙷq2}nwij+%KxcG syДNULC0V=}^&$Y5LENEkSeRg' ˬ 'px̉֞* Z̉*U0g$'IiNj?ܛ/ K&wdornc2i&C/nv=ǧ VȲ'$8<7:2g*4y%9#+9v@W|x_E%s>/rxlBtU^h\lj?' c]..cHvgعoa\˴aKl9;7[ôyW5v>ͷaԿ ZO'{Wɛ /-vn姍Ɨ:kW&}8q}j|+q0^nsMPzʥ{G3W8uwMk"x1hkڷ# r4 jT_kYNsc;/㲳Հ}F Zg$mӝ}u?y5@c:adCz\p%:e?O(0S„l.7^BecHV@7eA]&V7SiG*|,jO*fj#0.#>ܥ&]IM}OAOYZ3}4HWXw.gd$9dg3}1)z>a(8Gt!:X!pKΟƋ&s}S 6 ,9 )v+-70?I }\cOW%/~`} {k?j^߿D5Fw c YgfNf v'*d/7gľ]-6+1LU mJr|Kl"w/*0 $-Fexw"Ae]ޙn0gZAQϚh=L\I y\77:?gޓuNtBw˕,'f kVKM W6| А籃`q!rz7.8Nl0K% 'ů_˓BpM;E#fM9\l#ߋ/W6~uy|]Ԁ~,UuU0?Eq0(l50+=kW{ӏ2yd+^l%,nSXp }Ldҋhz}Zof#YCs?ƛ$ b9_]hCVkPK:#}=i:~@ϑg!5ki2uc$[WFOpeb@|cF ]&77@f+uq0. n`o8AhCd3T`蟃jq7vZ%_Ω}"[њP5IzJPyDžϞ%y>e[;L/I\k.F&g*JYa& -/{p8ϬI )L)h!uqEɖB._r-EKZnnϵn6mK-8 }RTz|`#8dHit͏ȹ@0vJ@ ^ՏTJ q<;7ɝjD$Cub0ō0=@g3dp6K\ LX qr!//՟Ɩ{3ɥ-#<_X/XXI50/uhP@Gaָ,+.n2>} ղuz.(۷Cى.e|ss%d8hSXvΉq/,_k9>?>'Dq3U,S?FsL(d/{sw@/6iw^nd_N:2r 2[Hw $dr=FcyĻM)U7iOٞYdH-ه.S&Lӹz/N>w]c>TpOQ#߄^줴ЂO):0oLg,ٷ/4ArSfW›{y ~r_31N"-8uq.d̪zP5ua-;0;1_FO [XB-^n 0.{A(ϣuNG̴RW8` ,l6? 1T[ r7u:' VS8M] Ͳ>m6R'8E%i)1I6R˃lO!BmSx}։6 vzI5tࠉmgc ]6Ӿ(k xiZH Z3M/N=^l6G{b >%єZf9S*U%y6_v~SC4rSZ $+ E Ir5Gn]RGs-9概ZL3$ZT0^q~s-n21~D(} jgud@wkA]`2Xq7bw*cy:ض'ylD;0z=6 6{L Z^no?9L6f+#S޽_׽ړ d$"~>DЌmd}8M$<{#!Japp#~oNc&T>uF~T7U$~]csAz':yb$R5 cMzukhG㩎m$16änKܦg!]g-.e0觘>ЦsWP)M^l-q@ZtUVX,\r)h5mtp?-uO0Ӯog4epٳ)bp?Vϱ jw{殗ol߫r7|C=¿4aZM+ȴ7ZZ-~@tUb$ *\MhHcu|,^!( B"9={ɽ[Î̻3 TGQjv?9-,{ ='mZDց_8ZRUAQjޓ$~Ko YۢBp?gm}0~}iu:A說ŲFm]aDׯ'mu5ml% Cw@om6wJR5SLVoi;<45>'`ِ 6_ۺLko$^Ϸ=^ k׫wI3Mtޯ-̼s၏ݧ&֘W<9h3D!h _hoF˃5 Dp;s r/ҋaW45 B#jm dͼ{C' UkAfmX)T(ly&a{^n<:[P#t GΥWcJ7"DK7\mP;8i jָU 9̇]]كA .b QpaSk6ahcH`^\e`@rǑ dFWZ ij+G0G ǮS,1?2%-BiV pker)]+a(mCgc) ,xnX$^3c>VOd.م.0\Am "|Dj4/YK=0JG6a𓻽0)G#saz/=D N3-7d7Q4rϜQ465w9g1<2ڠBݒNwbe8.D5lFT De-LwCFzBgᯃ+`WdLBݒ^!w g_vмgފ&kpl/FjBQXMu3Wj7X>Rmˈ H3+T/մeZDKF7l>f8ŷ1\k~۰k j阒.xD@ܹ+@E]X_/3 9+LA-= ^v7%y_{X}Uf(=Qco;rK?<-ܩx-J ~3>vws/ֻ+eA-{b43vdoMްX?FK$X5ޱX_kJ"G@k^IDATȒ 53b}oP"zoPh7EDvUAmnI0W2p(J/FY- j1y%ff}d[,ok¼ ܽb}Ιa; 6%ln8N 3U`oLu-S*g ygoP1@Yzyc(=p?;6F>ѕڛA5RRN iYtj1+x7 GUt<|tԓw˟Kr:>Bݐ~+&=\{kY2uғwFg6LͮJgu^Ś[L[na{燑\tK')J铤HtՐb%N3t c[dqg/O0 ;`?Qos7nk\w돎tsVsW(cӉ=O(cnQk=A'dD51AX1pb)dny@ᾣkO" SnuKϝ؉ޖApV txY+5J Nb,K 9*J=Rz wx)˽Z\.Ʃ[tlb% `zpP2U=xN'@QhHJЏ䘱{+w'L]$0qd@̃pv5w*=V*u~;ƺF(|btVt'J0!Q$Zg!X Έsd 쏬u:O T 5hk]KЏXgnE EƘPۦ|F[їm/?]T ^.vBRzb J-((}4$V{?ĘhieT|ryȐ ߧ†GгOZ>:a`2P>UYkݖ0ē/E.0Z>wJֶ6}U="+(vZM-#oÐ98'=,=7;yޫI^&i_ԷL!B! o tv_s퀛syoM΢Ekw.ſ:Og{^}e[j7q:=y?A^[o''jèMܥT O:N޻߉|t/,:1`c;fیWl_&ਏS{t=\ə}L}+.|$(cVS)]. JLL߈7/E$b8ꃿ݋{fgb9^tJ#{~'u38plyŽqP'3xrFپsQ<`#gi#!8mAG }:o4o䌲=%4rn 2"fl 2=JgOGݜ1sFwGpx?uoWE/^(k:cp*00 uJśy.P!w* <'!gE<ҬkBi㱔4AbU~f^ɛNt*z L$FfB|hX]*.HϾG 0idmtb΀҃ЍIԽ\PPp@ 0ÎHGrOtVGCQqbߛ1x Jp"f>UNpbŵW­hĹ1WnloVS0hEOwTZC7Ua0b(=؇f[ J `}jʼnݛ_]N=vc,A[Tm륀k4xaKu> if6 Y~G8v#D!lzf'Hpc,*Ip=q3it8m/Gw؋`k%4DOP&אTCDͪL?SY?OG[cѝ` wm1VgҐNɻqϠ  \{U@fo!v[,ׁp^mp̭>7n;X)C!N j_MgrS7[If hrɄdS8{+1叒);u\*.q~* rǛUcST (>GqDE}$'H/Guxo_q9n^{]\1iž($ 6q@@ qqϟe}g6ؽ%8 _P+?:п>j=9EXjy_oubw9]?mNqߣ{-*V"<Q*LH'wQ~%=]~)IK^&w~`3Z'݁I(a>} ʼntv_owsޥ 5{sz<Tcj=Dxsee=i/WJ,Erޔ;&_ 1yR 0hU< /ɇ$uᚁsYF3֏a@(N~JlPG;=ʥW '/=pdseg>uGKӂ^;GT. hĥ`iLq6u3 {w:|hda@-kb_2 ߃=eޑ47cR;̄qO~P2=; 0Kc:S^Qҿl#gʽ G{Rmx8[xf~c"\ZnAAC~o4@|B315.'ͼh]?>k6h!bǣ1f>*߆scJFZ!bL^ щ^ôYtA<8NPnV St$܍`=s"ǣUm?a{(O;bYp7:omKV[g=o|DŽl}۾%O |Ų=?p`'9` +((4 Œ\oF}<<9\[~;z01}q7>[~r<|oE}8\!'?g~3 !Ė/8q]|bQ <6)Ӳ C<&3|בֿuĈ= }Y>6Io䌲\^̧tF<O8s7edzCkDnΜ$ꈽ#)=;nUы]j>Ĉ/x%8/7߾ t/B8']Sp,fEoc ;xbFo߄N8 /B8'S&E n݈QUV42p>;rT+qwV5K[PSxҫ"˭JgX>55N(;$?C-; up1NYXeֶBn{>iáVgX5,uocc!({'PK.&uϋL\q0ޙxL~h`0 Z:ɴ'1hĐq9]FD)'ddUNx"1Γf/ >.(:^]+!zB4]V9቞¯{t8J}ckL;]rSc옭fIʙN$ QbUgP$cSۻ,A gmvKޅɧ^Y`sjң2A%;~Pza L='}h7sI6LtYƿF1t{_Ց(B݋3!`MqoD~uoW?`KoiԽQv+(YbewƤ|}WFtg/q/i쉙 oB'ǽ{#3>xg=J^^^^k/^z' j5+ukųr ?o ųcVų~ NY_<@~`#^t^#0ZJ>'v|g K-((A3O,xԹ#f>*/UŸǎ~/`D[E%I4V¿?/( y K+i8 W;,AܳpIENDB`perfbook_html/img291.png0000644000175000017500000002650211672746100015312 0ustar paulmckpaulmckPNG  IHDRW=(PLTEݧ{{{wwwgggeeeUUUMMM999w---'''U3 |||tttppplllfff^^^ZZZTTTNNNHHHDDDBBB@@@444000***hf&&&χD"IJtRNS@f IDATx} c8nyˎ֛sl9jNYNsg>(Oۊ1oY@Aq@ g_;&z %dj?3}`n~_Vmx߽J&eQH_yW 7B=l_X21ߍjS_XsIw#W~o3$ d֖xitG~#7ހvow%7ܣ-[mQ~-ك7u<+Ҷ[L}n8ރQU|Z{9WKS_mmzAK&BۺĒ*5fm-0{&24.4Q~=Ky~e݌ `)ej8 }}rT%P*D;c[{TGщflSVƛt~R xk(ڶ?e .ӨV%PHUKzL ^gް(;&!N@fqxyff /+؏"JCoQA2^ں r0;hп[l:іo-tO-ͶM }PR 9k5$5|@ q$  g >FN,z8)}EzBYLm}NY)Z↤^7jMqٖu3A*tu!_ 'V^OdžADmG[=u/q"kҔ8W " 1$n,Y@⮆e@C89O@$n<8 NpFKZxh1a!!+s!b$zcH^c1^炅(QKڭ3`/[+hc38+EuxM0l%\--Khe Et"UPJp~ʤml"-,mL ãm{rM_>zlS5ոsۯ}.@;L4M1&5[D;ЖbJQ)꽼[Ѷy'-@ !ګ-T5H5ގ6+ի {tv@;EwlAѺXń>/RQ`[5pR@~U3 :HA^ ƞTNKjkzf@5^1Dk<,7h/,ޢvlܵ@p<7v6s~[:9>;FhY8j„Th6k9Zj emPm&s2W)! õECbTh[TAy!!MKs P〦:4M`ƇaNsjj>t6Iй}2pi$$`MOc'@;$zVѦz&@*hx:XSNtϖNj 1N'ZPr:L%i%;4cx[ < vu4;6hFkxeC1Hs(݌+ƒ+6ނ:܂֑69nmƃi?YZ7f^:B$\J_D_Jf3ˋ2@jsp-c5~miwEhEVIh6j}4b'Qm{imxmѢ&'sӓPhCBh[SKZ!t'ׯ A=ft k5P/cFH((8jY9Y!ԀJ.ܛ?Y15^[H~HphI| jKOjsy(XGY5 E=)e3hƂ2<)k^oɭG7BI8Kh$k|Ѕ6ҳjmImqeomԜV\fbK&]hیAkT8k#m?$# -o߶eN=Ўjq5V-S$ihKk|6HNpqNu^u0vB`*S*%;*eX>t Wh,GA T#/T$-sny??R߃ey0OJ(Oy{ڙf-r]WCi:AnHEac؆bvf0f FY.#gi(8 B5u܊ L4/hsEh="Ơ ՘? ,IX_iXc {Ơ<0-mw-yj_M7!zѲ|PoS9<~\-BRm4 PAOh r jFBL;Uѷ# [ŕٚ8AW뢖%!-H(@xRZC(!Be@OzS@Y=k(8~ʋO/HoHl h :Q cz$%8fu.Ac0ytrޚ0#oXhO%4Fr*Q-!QcLR}"=kCtRoC2L-q[&!lmb'%:[@9JqTǣ8P݊orn]CD3)5Djͬc'&KfS~`Jr0E'CȎlEl&W/#4,Ui8˝_-Uf( d*OvYB#mb{ݙ*6Lz6A<0\f_*z1̤*SB`VO'tXbkOf6hb ĆG?cAFoك&%"tWt&UWA z/gRpzIbKZ6=K9;Y` eB6hQmk M۸9+| #tzs%#tmILM?US]!6tLsUյ~ă}~#~ă=78jab-)X9]Yrm]n1g1M7JZ%gW ElM_g?Z0=O3;z^6El18֑dY[sJ]d-! ӬiSv׽͝"#vaZ-J^oBni͓X'LاSNl?=W%kE_>/_FCT^ M+҈AbαspO$s?|~~W5GvdX:'WXh{_jgVع\{G^h'7س:3_>͂x': *lt/A%[0;[#Tjd4NpLE;x @J !MK~R^~0c CA40H;9Ҟm[_J=)3`"蚄ʭҢMkq68[g6,BGnMRXM?os0}Q#AAmvgG2ձ߱yDbrS$1 |È-LGOw8mee%N>G}-|+s[ l6۬\Oq牜+{ %/:[)wbP%v8;k͊eGQtpsQxnItݨ=jC1S ]6x$Q īz45pUn8.5ZQvASh?Z-pъ i&QQNjZ>x_[V DyNn8vH,'eRK`aء}UZ@j*a$i׀W*SDuziv;7̜vqw&m:+XNΧuhD uQge@(Y Zׂßc>/C]ZKJTRH<1 A+|5xSpwSZSGKLu*zBj`v!pS.Ud(k.HsA'݂B[>4y z+ۄ9 W[ֶs[$]NZciͣ 0ۡ56㎡[,/:x`V=fm e1+ +',k"c1MWiJ!Ÿaػ _f;F sl7F2ߊ>RdeZ8#-~=<ƅZfm}AڊEOkx{RۊM+O+$GMQMonI$VE?<ֶ~qϱ էgA>zЅе%j"X YdNwoh0?w:GqMVůݿ*CtP1H뫤"Zk+1,+DU> NO[pﰗjW{LL{u5kr jإ( lKuŘLX k2V_oMJYxTC+sv gX2DX994P~Bۯ5ǂLէG|Tb3$L5d`Q2p!ˋW vPPkßoVq!kۊ'lƐ\+\2d(\0d08cH\1$M Ns=Ѫ Iqa`<[(ғV6$ޯҊ?,[{8p8pX`]?8k8Z'^{8=X㵧Pu`ZPjYW8ܗ!x5nBrZaWSׄW˸bs?9#zOBà˯KWs!sJH$Pu,L er,ijfvѻ\q I:1%kƦ:h+}S.k3^A5ib\ ~ cr!.?֋flBP*jY|x08-L+(Ǒ=bW}xN[h-[PZQ!Jc4gڱZVLN쏡/(xµŸ rGx7 F\JԪ-.77 mjΞ;`8\Lp a Zǿ28+1rLB4k׷\8Y#DŽ\6DŽ1\fxm/bH=1za(BAdG) 0oo b0(O:0,Xg[]iNyAz`dg .$|z.\Pq:fB-0^31`8!3P.5ELk*33R5)W8N(ބJݙC_d5}n _0 2 K\]kA|{DF* Q7c3ut' )#B3*yz5|UԨS>[qDLL>ӃUoxAk__ Nul%ɪu 3.BWPgL$ jOQ%OTz%kӴJq.e ;_AW} 7< ?[* 3'ޘDֿ)ϲm,eF5Z/f}MOʴE{O㞫]=R-1@B" HB%X].Cu-T+ݰOpDo \9j.ԸWWajFfcؐ2y>{P_1di_yzCDNd OW;[z@+|tKg~,RZ|Bwd&bFWnk\+k띯`gR؝3oxd@_; f1_4GTy IDATN_ AUym#<%%ꂿzGJqf *gފn}jOژbzS[YqTקז88 +$e:>o5m,]CPCb- ?hC$O2zdYqY38{Te|:]7ɼ4&G6+C/Aj;+7oR_0apwf ]$ڙA#}L gV^ ±Tק~7OV\k:|4_"OjeMqB}:h*ݐWUJu v$f*Дl?~}|׌_ϟY Iq̛xjŞ@sS *2Ux/_g|}ko`a¦ }nG~A8(DIr\M7p~UfV~|78J\F#^;˓XB!:%_K,2mpuZXY-"#ͅW#;azvPM S3j'W<&^{:6Pn9)Lj8p$_M=^{n%2?O\= u|9|9AO|uH r)!Y W:$j|u:$}u`S|t=L{lK|gaMg^b>UxDi)OzK ~K>|}_~- YʏOS)U!3o͙ ǟUS8Z0ޭSN|[½2h|]w}u`;|C:zkY_{uVѳ[OU_{׾:zљV]Ggކ[`*=z^ 6׶vx{^v1Yu,أ~*Oڙgtg5-yFwV=rݟzZԃ_._;_4-el-ln*=딲"xuWփ_OX~!zl=xfV:O㯏5zmnN=*r# qu/ߝs+(w |ׂ-կkck=qe埫W=Y'F+oL#tuh-@KN}>X<#G]tȌ-է|3.]UaK|߈Ю_%^WWu;kN"T}:|6.U_^[^=o6z7-a=o% |u"LBl/ʝƼej8G84RI .}s|ߘ(Rec-.i ̜!>ZrYFgzKE$KӠh1~x떇3C_ZY};W'JB|zՃy:t/RprE3}dzx_Q[ā? ֖86䧘j1O_^WH*~|쟾DQ\aV>nLfx*)ۄ5M,9ƜW'F2z{5zx:?$Z+ ,F c%SүO~}x(=GzO;iԃ֍lWbg[ z$Q&}#*嫔ߥw(e$JAB,d{T^-GO$Av=~s}j>QQ7hջnz]/>\}x&!Y&hv~lK >w|(gNoUnK7o{:Vz}ۮNsN=|}6ֶu+uׂEtӧ/Q+sy ylv\l+kw]9k̂_%F6x:7SY[ކ8۱ZESwކ6k;ɐJ#Mu6LՇ@* w׾ڸ -S z + RZH?亱*?!d.?Wk)w& w=N '9 )bhll|q2wZտqn¢BV9%qZL l%K \Mذ~Jm_׎+hҼa!֕+yKMDF@dXp+3_M~45VRW=&yBF4t _Iul[~-AGJg&++n=-v͕9`Uvt-WGwNOn\UzB'<b|]6"_w8Zv\]d:z-y8†e[-ǹJ|m8Wћgk[$rh*v,|Ġ܌o!3IENDB`perfbook_html/node151.html0000644000175000017500000002601711672746162015647 0ustar paulmckpaulmck 10.3.3.2 RCU has Publish-Subscribe and Version-Maintenance APIs


10.3.3.2 RCU has Publish-Subscribe and Version-Maintenance APIs

Fortunately, the RCU publish-subscribe and version-maintenance primitives shown in the following table apply to all of the variants of RCU discussed above. This commonality can in some cases allow more code to be shared, which certainly reduces the API proliferation that would otherwise occur. The original purpose of the RCU publish-subscribe APIs was to bury memory barriers into these APIs, so that Linux kernel programmers could use RCU without needing to become expert on the memory-ordering models of each of the 20+ CPU families that Linux supports [Spr01].


Table: RCU Publish-Subscribe and Version Maintenance APIs
Category Primitives Availability Overhead
List traversal list_for_each_entry_rcu() 2.5.59 Simple instructions (memory barrier on Alpha)
List update list_add_rcu() 2.5.44 Memory barrier
  list_add_tail_rcu() 2.5.44 Memory barrier
  list_del_rcu() 2.5.44 Simple instructions
  list_replace_rcu() 2.6.9 Memory barrier
  list_splice_init_rcu() 2.6.21 Grace-period latency
Hlist traversal hlist_for_each_entry_rcu() 2.6.8 Simple instructions (memory barrier on Alpha)
  hlist_add_after_rcu() 2.6.14 Memory barrier
  hlist_add_before_rcu() 2.6.14 Memory barrier
  hlist_add_head_rcu() 2.5.64 Memory barrier
  hlist_del_rcu() 2.5.64 Simple instructions
  hlist_replace_rcu() 2.6.15 Memory barrier
Pointer traversal rcu_dereference() 2.6.9 Simple instructions (memory barrier on Alpha)
Pointer update rcu_assign_pointer() 2.6.10 Memory barrier


The first pair of categories operate on Linux struct list_head lists, which are circular, doubly-linked lists. The list_for_each_entry_rcu() primitive traverses an RCU-protected list in a type-safe manner, while also enforcing memory ordering for situations where a new list element is inserted into the list concurrently with traversal. On non-Alpha platforms, this primitive incurs little or no performance penalty compared to list_for_each_entry(). The list_add_rcu(), list_add_tail_rcu(), and list_replace_rcu() primitives are analogous to their non-RCU counterparts, but incur the overhead of an additional memory barrier on weakly-ordered machines. The list_del_rcu() primitive is also analogous to its non-RCU counterpart, but oddly enough is very slightly faster due to the fact that it poisons only the prev pointer rather than both the prev and next pointers as list_del() must do. Finally, the list_splice_init_rcu() primitive is similar to its non-RCU counterpart, but incurs a full grace-period latency. The purpose of this grace period is to allow RCU readers to finish their traversal of the source list before completely disconnecting it from the list header - failure to do this could prevent such readers from ever terminating their traversal.

Quick Quiz 10.31: Why doesn't list_del_rcu() poison both the next and prev pointers? End Quick Quiz

The second pair of categories operate on Linux's struct hlist_head, which is a linear linked list. One advantage of struct hlist_head over struct list_head is that the former requires only a single-pointer list header, which can save significant memory in large hash tables. The struct hlist_head primitives in the table relate to their non-RCU counterparts in much the same way as do the struct list_head primitives.

The final pair of categories operate directly on pointers, and are useful for creating RCU-protected non-list data structures, such as RCU-protected arrays and trees. The rcu_assign_pointer() primitive ensures that any prior initialization remains ordered before the assignment to the pointer on weakly ordered machines. Similarly, the rcu_dereference() primitive ensures that subsequent code dereferencing the pointer will see the effects of initialization code prior to the corresponding rcu_assign_pointer() on Alpha CPUs. On non-Alpha CPUs, rcu_dereference() documents which pointer dereferences are protected by RCU.

Quick Quiz 10.32: Normally, any pointer subject to rcu_dereference() must always be updated using rcu_assign_pointer(). What is an exception to this rule? End Quick Quiz

Quick Quiz 10.33: Are there any downsides to the fact that these traversal and update primitives can be used with any of the RCU API family members? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node366.html0000644000175000017500000002557511672746163015670 0ustar paulmckpaulmck D.3.1.3 Per-CPU Data


D.3.1.3 Per-CPU Data

The rcu_data structure contains RCU's per-CPU state. It contains control variables governing grace periods and quiescent states (completed, gpnum, passed_quiesc_completed, passed_quiesc, qs_pending, beenonline, mynode, and grpmask). The rcu_data structure also contains control variables pertaining to RCU callbacks (nxtlist, nxttail, qlen, and blimit). Kernels with dynticks enabled will have relevant control variables in the rcu_data structure (dynticks, dynticks_snap, and dynticks_nmi_snap). The rcu_data structure contains event counters used by tracing (dynticks_fqs given dynticks, offline_fqs, and resched_ipi). Finally, a pair of fields count calls to rcu_pending() in order to determine when to force quiescent states (n_rcu_pending and n_rcu_pending_force_qs), and a cpu field indicates which CPU to which a given rcu_data structure corresponds.

Each of these fields is described below.

  • completed: This field contains the number of the most recent grace period that this CPU is aware of having completed.
  • gpnum: This field contains the number of the most recent grace period that this CPU is aware of having started.
  • passed_quiesc_completed: This field contains the number of the grace period that had most recently completed when this CPU last passed through a quiescent state. The "most recently completed" will be from the viewpoint of the CPU passing through the quiescent state: if the CPU is not yet aware that grace period (say) 42 has completed, it will still record the old value of 41. This is OK, because the only way that the grace period can complete is if this CPU has already passed through a quiescent state. This field is initialized to a (possibly mythical) past grace period number to avoid race conditions when booting and when onlining a CPU.
  • passed_quiesc: This field indicates whether this CPU has passed through a quiescent state since the grace period number stored in passed_quiesc_completed completed. This field is cleared each time the corresponding CPU becomes aware of the start of a new grace period.
  • qs_pending: This field indicates that this CPU is aware that the core RCU mechanism is waiting for it to pass through a quiescent state. This field is set to one when the CPU detects a new grace period or when a CPU is coming online.

    Quick Quiz D.21: But why bother setting qs_pending to one when a CPU is coming online, given that being offline is an extended quiescent state that should cover any ongoing grace period? End Quick Quiz

    Quick Quiz D.22: Why record the last completed grace period number in passed_quiesc_completed? Doesn't that cause this RCU implementation to be vulnerable to quiescent states seen while no grace period was in progress being incorrectly applied to the next grace period that starts? End Quick Quiz

  • beenonline: This field, initially zero, is set to one whenever the corresponding CPU comes online. This is used to avoid producing useless tracing output for CPUs that never have been online, which is useful in kernels where NR_CPUS greatly exceeds the actual number of CPUs.

    Quick Quiz D.23: What is the point of running a system with NR_CPUS way bigger than the actual number of CPUs? End Quick Quiz

  • mynode: This field is a pointer to the leaf rcu_node structure that handles the corresponding CPU.
  • grpmask: This field is a bitmask that has the single bit set that indicates which bit in mynode->qsmask signifies the corresponding CPU.
  • nxtlist: This field is a pointer to the oldest RCU callback (rcu_head structure) residing on this CPU, or NULL if this CPU currently has no such callbacks. Additional callbacks may be chained via their next pointers.
  • nxttail: This field is an array of double-indirect tail pointers into the nxtlist callback list. If nxtlist is empty, then all of the nxttail pointers directly reference the nxtlist field. Each element of the nxttail array has meaning as follows:
    • RCU_DONE_TAIL=0: This element references the ->next field of the last callback that has passed through its grace period and is ready to invoke, or references the nxtlist field if there is no such callback.
    • RCU_WAIT_TAIL=1: This element references the next field of the last callback that is waiting for the current grace period to end, or is equal to the RCU_DONE_TAIL element if there is no such callback.
    • RCU_NEXT_READY_TAIL=2: This element references the next field of the last callback that is ready to wait for the next grace period, or is equal to the RCU_WAIT_TAIL element if there is no such callback.
    • RCU_NEXT_TAIL=3: This element references the next field of the last callback in the list, or references the nxtlist field if the list is empty.

    Quick Quiz D.24: Why not simply have multiple lists rather than this funny multi-tailed list? End Quick Quiz

  • qlen: This field contains the number of callbacks queued on nxtlist.
  • blimit: This field contains the maximum number of callbacks that may be invoked at a time. This limitation improves system responsiveness under heavy load.
  • dynticks: This field references the rcu_dynticks structure for the corresponding CPU, which is described in Section [*].
  • dynticks_snap: This field contains a past value of dynticks->dynticks, which is used to detect when a CPU passes through a dynticks idle state when this CPU happens to be in an irq handler each time that force_quiescent_state() checks it.
  • dynticks_nmi_snap: This field contains a past value of dynticks->dynticks_nmi, which is used to detect when a CPU passes through a dynticks idle state when this CPU happens to be in an NMI handler each time that force_quiescent_state() checks it.
  • dynticks_fqs: This field counts the number of times that some other CPU noted a quiescent state on behalf of the CPU corresponding to this rcu_data structure due to its being in dynticks-idle mode.
  • offline_fqs: This field counts the number of times that some other CPU noted a quiescent state on behalf of the CPU corresponding to this rcu_data structure due to its being offline.

    Quick Quiz D.25: So some poor CPU has to note quiescent states on behalf of each and every offline CPU? Yecch! Won't that result in excessive overheads in the not-uncommon case of a system with a small number of CPUs but a large value for NR_CPUS? End Quick Quiz

  • resched_ipi: This field counts the number of times that a reschedule IPI is sent to the corresponding CPU. Such IPIs are sent to CPUs that fail to report passing through a quiescent states in a timely manner, but are neither offline nor in dynticks idle state.
  • n_rcu_pending: This field counts the number of calls to rcu_pending(), which is called once per jiffy on non-dynticks-idle CPUs.
  • n_rcu_pending_force_qs: This field holds a threshold value for n_rcu_pending. If n_rcu_pending reaches this threshold, that indicates that the current grace period has extended too long, so force_quiescent_state() is invoked to expedite it.

Paul E. McKenney 2011-12-16
perfbook_html/img125.png0000644000175000017500000001223311672746115015310 0ustar paulmckpaulmckPNG  IHDRRNPLTE$8D6Sf^^w<BU5;p*!lf8nUf+W]/eȪJ6$UVE6A@SvRWOd0+8'd@Y.C+ǭ+ɔLUԨsEQ ㉕G%ƎbZpc۰NH¤5Mk(mV觶1ǬP4cVsc[|>:%fu1 H9Ū@b-Ljۑ!8"u!ttz'N[0|;xZ;@$XC:HeRftV!U ?{zzѱ\ү2omWCm|tR~f;9Qd;@~lreB'u-* LZ: 7 | OQW5=zރbAf9 A&S k@\0GXILYjH61qs3Tߢ%l&ąd^.q4V S#n㒒0tbHb*cd;9rs9z}PuJTcř!70&SB=p4k7b^80ԺӔ4\VF2 r9-g253AZdFLTYOL ˭Mo@)4)N "4-Vx{>`˒e͆CY!zClM.VJYDɆ15T`b>cLp (hV}v"Vυ`} {@  6Ihdhՠ,IILc 0L>H@C2HU1Yumg(P1%-_=mM)ՠ;#Sj`&ʔtLXva0mF!6J #C)Ed0C)|# d3eF3`\0~4?Jt 1-2ݯ,)7pL;뻽1+/ 8#L:_NNpү;|xr8[n(Xh2?X'ký)l_ߝ>FSJvKm/mj}Icz'ieFvo6Lɔ3ba8EJFy;AǾ9yIh8Fm}bL)/k t=D/x87/%nnpSiR.SOy<e*;C0 f`<Bh&jkiR>S1L4ݲq;L)i頹ɔz]6+zԓ0Y3.liR>ӂiJsI"¼$EF59A]bV*fL_YsTrB knXT**_s?ֲ ði9|շ䒒vU5hhKўrHT-'oT;f,1[ -fgFu3R!Is#.)gHzeyTӡ^#i 7$6dOb =3/` AK%͓OIb mO OykF[v+d0B.Ѳfku`Xᒌ,4"i|I?Hꎐ/!pڦ iQҒ%U8Z 3IjDL, F0Ncq'Lĉ/X8nwLk}yul'~4LC j$u%0/dd u:NQ]uP0hokev[|y*oCA{C-% [}a_͔!p:(?OҌinܗgNlO! uv~U~Jҿ@OT'I i|e{' Mr#^`d@Q+&Kj2wQf#iz<@Rw?YPҒ9DPlsWYTRw?YTҼ󾫑T0W ߞe :G6Jww5 *2;8b]a-Ud쵘@XRyUJQJ몯'|syEŨu`JR= i%OR=nQ>_FHZ9I+G#ih$͉C;Iq%3*|cA;mvPN&ikDJWE]\*9T 6* Tr19|-fmH ..\Lj i%kDJULآ..\Ljrůj-U+~dQJ&5bNHZ9_R_cgr4VFHZ9I+ǿ')~+Q9V҂D*&FFFFFJr}($ݲ}ɑ*ϗْv ߽YSտu:#){>KG_1H=T. yw${CAk=v4^{S>5}v:G#vLAk9jt$_Va|(>¶C'oOg))^ i!*&!y$ ~eнV<{qχ$j,ih$m$m$m$m$m$ 4hРAۋr|l5e{^B/hcdMB/hIe{_A2Ns4ܗs4&I7IENDB`perfbook_html/node398.html0000644000175000017500000002143611672746163015665 0ustar paulmckpaulmck D.3.8.4 Code for force_quiescent_state()


D.3.8.4 Code for force_quiescent_state()

Figure: force_quiescent_state() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 force_quiescent_...
...pin_unlock_irqrestore(&rsp->fqslock, flags);
62 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for force_quiescent_state() for CONFIG_SMP,D.4which is invoked when RCU feels the need to expedite the current grace period by forcing CPUs through quiescent states. RCU feels this need when either:

  1. the current grace period has gone on for more than three jiffies (or as specified by the compile-time value of RCU_JIFFIES_TILL_FORCE_QS), or
  2. a CPU enqueuing an RCU callback via either call_rcu() or call_rcu_bh() sees more than 10,000 callbacks enqueued (or as specified by the boot-time parameter qhimark).

Lines 10-12 check to see if there is a grace period in progress, silently exiting if not. Lines 13-16 attempt to acquire ->fqslock, which prevents concurrent attempts to expedite a grace period. The ->n_force_qs_lh counter is incremented when this lock is already held, and is visible via the fqlh= field in the rcuhier debugfs file when the CONFIG_RCU_TRACE kernel parameter is enabled. Lines 17-21 check to see if it is really necessary to expedite the current grace period, in other words, if (1) the current CPU has 10,000 RCU callbacks waiting, or (2) at least three jiffies have passed since either the beginning of the current grace period or since the last attempt to expedite the current grace period, measured either by the jiffies counter or by the number of calls to rcu_pending. Line 22 then counts the number of attempts to expedite grace periods.

Lines 23-36 are executed with the root rcu_node structure's lock held in order to prevent confusion should the current grace period happen to end just as we try to expedite it. Lines 24 and 25 snapshot the ->completed and ->signaled fields, lines 26-30 set the soonest time that a subsequent non-relaxed force_quiescent_state() will be allowed to actually do any expediting, and lines 31-35 check to see if the grace period ended while we were acquiring the rcu_node structure's lock, releasing this lock and returning if so.

Lines 37-59 drive the force_quiescent_state() state machine. If the grace period is still in the midst of initialization, lines 41 and 42 simply return, allowing force_quiescent_state() to be called again at a later time, presumably after initialization has completed. If dynticks are enabled (via the CONFIG_NO_HZ kernel parameter), the first post-initialization call to force_quiescent_state() in a given grace period will execute lines 40-52, and the second and subsequent calls will execute lines 53-59. On the other hand, if dynticks is not enabled, then all post-initialization calls to force_quiescent_state() will execute lines 53-59.

The purpose of lines 40-52 is to record the current dynticks-idle state of all CPUs that have not yet passed through a quiescent state, and to record a quiescent state for any that are currently in dynticks-idle state (but not currently in an irq or NMI handler). Lines 41-42 serve to inform gcc that this branch of the switch statement is dead code for non-CONFIG_NO_HZ kernels. Lines 43-45 invoke rcu_process_dyntick() in order to invoke dyntick_save_progress_counter() for each CPU that has not yet passed through a quiescent state for the current grace period, exiting force_quiescent_state() if the grace period ends in the meantime (possibly due to having found that all the CPUs that had not yet passed through a quiescent state were sleeping in dyntick-idle mode). Lines 46 and 51 acquire and release the root rcu_node structure's lock, again to avoid possible confusion with a concurrent end of the current grace period. Line 47 checks to see if the current grace period is still in force, and, if so, line 48 advances the state machine to the RCU_FORCE_QS state and line 49 saves the current grace-period number for the benefit of the next invocation of force_quiescent_state(). The reason for saving the current grace-period number is to correctly handle race conditions involving the current grace period ending concurrently with the next invocation of force_quiescent_state().

As noted earlier, lines 53-58 handle the second and subsequent invocations of force_quiescent_state() in CONFIG_NO_HZ kernels, and all invocations in non-CONFIG_NO_HZ kernels. Lines 54 and 58 invoke rcu_process_dyntick(), which cycles through the CPUs that have still not passed through a quiescent state, invoking rcu_implicit_dynticks_qs() on them, which in turn checks to see if any of these CPUs have passed through dyntick-idle state (if CONFIG_NO_HZ is enabled), checks to see if we are waiting on any offline CPUs, and finally sends a reschedule IPI to any remaining CPUs not in the first two groups.

Paul E. McKenney 2011-12-16
perfbook_html/node305.html0000644000175000017500000000574711672746163015660 0ustar paulmckpaulmck C.4.1 Invalidate Queues


C.4.1 Invalidate Queues

One reason that invalidate acknowledge messages can take so long is that they must ensure that the corresponding cache line is actually invalidated, and this invalidation can be delayed if the cache is busy, for example, if the CPU is intensively loading and storing data, all of which resides in the cache. In addition, if a large number of invalidate messages arrive in a short time period, a given CPU might fall behind in processing them, thus possibly stalling all the other CPUs.

However, the CPU need not actually invalidate the cache line before sending the acknowledgement. It could instead queue the invalidate message with the understanding that the message will be processed before the CPU sends any further messages regarding that cache line.



Paul E. McKenney 2011-12-16
perfbook_html/node331.html0000644000175000017500000000731511672746163015650 0ustar paulmckpaulmck D.1.2 SRCU API and Usage


D.1.2 SRCU API and Usage

The SRCU API is shown in Figure [*]. The following sections describe how to use it.

Figure: SRCU API
\begin{figure}{ \scriptsize
\begin{verbatim}int init_srcu_struct(struct srcu_s...
...ng srcu_batches_completed(struct srcu_struct *sp);\end{verbatim}
}\end{figure}



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img214.png0000644000175000017500000007442711672746155015330 0ustar paulmckpaulmckPNG  IHDRY?6kPLTE^0jT+a;|b>te<yb9|Z3e5 |X0zV.zO$h=aZoN\6hE \/urvM#~`8[4~W.|U,fB{XTx]6u`xUn@c>osa9nL U-h7qH h> uGqCb;^;^8d?vk?cjG_3~vRyQ'{tK"Y0TQpBpOpF}T*eA|R)yP&b1|{l=b8jEpC tI{Z~txO$c<꧑rPlK6 \rDzR(pxL b%tRNS@f IDATxԽ}XW/-cKзuN=Љ h8Qr5XJ6&)GeBԋ7'ma(hb$--+CJ!Vo"]k~Uh>OםwZ{՟,|{|2LjhõrO c扉9u}m7G|x<|9fp2}Mf^Əfv s?Ypl\dS">[.w̌8>gO >L垒USs?Y s"Kf:Db#{Ãpo5ql;uYf&!‡/ {'9ч;tx7WY#2>\>n.JDzڝCv\0xFS}|?<[3 VYr\+K2C1Pnq+[萝!rqB=Cqعs'|O(4k&>jG'߃>Vk*/kٝh?YYo:$cJ9|.cpr "ܥ/{zN@H`A`1>|n> ga)>ڛ;+v|8ax[< Y-Jӗwf (08/E޵}8/8p`}m|b0}ʊ3s^wųa Ȣas!xI-\^)~|p><.i6WխIÛ ?> E<>%Dt/t-O~:>oshx4Ǻe{ww|fxΌ6jY w`eߌȭq#PNPiX eeYxgݻ|{?Y}*],"]WNUy%^ްaY3Ji]=A+Z֞+::WўU\T^ d> *Ν˕"<:>Y#ʠgHk#}sJDYK`;d賠\ FKKG{%1TF/tl.:OZxMDvpLVOW[lH􋫄*O]$3!d޺]tItLw]ßu0m)yk@<&quAa ,- wQmhy ^FP]l>!Յ $6--f0DUu!!Ng-*Y>wt*!PY \5GҢlo[ ׋IP]]\M~O 5iqEZj4dÌtZgZ?5m K wtZux1ЂԂd-j+aӮUYÃu}aŜo@w3w`@g2Ͱ{43j yz~(ͻD6hg ʴ] zhb9S0޿=}ASLQDuy߁$dGڲL8idr_ۙ` G˄:AsZ|w`6ps5W 4/h+xᮭl> Q͡(Izһ*<+K5#۠C2U~ǑMW(O³,g( m[``h?̕fW>< . Xg`1k{'ʼ+"̛ld&8,Zf/@0&7[|9I}wyc oTfE۾ZOYD[`[pfSnƔ] lC.jsc0o|*l}8/u7xj*jqP FA9z3yyAM= }߾}mM^ܠ3wQ8"ټZѵr%eYf,y+1{ et 8fEaO( gG- Pzs} 2z]zu0dtZu\io @@- |k of&̲:vpTw^k=6贸0oPe¼kThmgʨ}֜+bmHʲw眹#%ifTaK,:VUsl^@yڀ(`~>㋂DAewʐcJ7`wZ;p)h,Gכ->D>(T|gt3`ݢٞ-s bMR郸 Ų _TT<񬇝FEs-tbT6GV ӓ>G2 XJ#>Kgz3EY`OM .[ЀvuQ=`oHdY(7dI K_J6l0kqi+Ý0,b`q;J -/ 4[ ތ SMnBO19 w-:0,b$lc$i&ӂ`$b4OZ; &-z uVsJwgD;?kZg67?:ѻ[DEgƜ9ߞFq6iF-|(:ʁ͒2M۽g7*| tHLuUS*n)r@=J8Y{(c"V_wV:tlJ ޮ矿,l&)2]]Ze^=z5^)@4c9m e1rK&es`kIhJHF7tìs98!ЎRzZբKi|ҳ  ǂƒ/;F2pqoOz4I8@^C嵛#A +D[EC]Nfzz20Lf2T^[v{{ ^X p ߌH_lOuvuhYvJŊ- D$Ee`@7m3@,vEWs,YAa^9G  e$[:Dl.ݙa?VW9ن<7dqB4uhNRN8PSL{ZMI&֥% %'Bm, q~$P g}eڝo`޼ytڎ`Gx(nBݨDPl f[H<+9( 1Wv j8%G?m|HIt)ʘjP,@5O+K+Lb&ԨudBAXl(4P5c&Tԁifi@3/]zC)&-IuZD;M2K@@CzjJG0.Uek pLlEdknZ2K0yfkӲ([tdr8kIR8mZf`$Vq\ _˼v!IAQ\>c:F3tڄ.k^bq]RRK=5- ; eZT֝0-ؽy egqCsT`z6-reh#9*?2^cQqJTYU{ -9|Z6jM٪eܹkIk&9`}m`v)WԾ/e,w27k* > :ERLK'`Z~jyNϟ hz?T#[;T_{Z;L+}*X˜.GbqXJ,`ƖXo*3괏i)RN/di48P NoyNkpլ;7vZQ=riX76j%e6v:N67+QeyayI4<@U;AdVU9b<@ڬ.eA3igZ rp#MIUg5:^67~Eo|v)q}ZW^%u+;pW`^%z$Ϊ!jZ~yTpڮZ{$;J1Nlw &!hWWxuHcե87Wmj ~B OEሽ64?MTh)qPá٦~9bsDF̊(;+-|lqp[58LN;=R+A<&@ ;O;%YƘhKw5N]`nG*7x|Z a)Ӣcj՟u}kkե],K)u%Feu̱f.LV.P 8E쀐z(=ȭ]t~)!{}ὰ 7x ӈmJb=0 poƚ.'&S,qNVTV޶+fk)Wm7ПGfOu 078RY6hN#k+c@ XpRKå~|d,Ydb,㵌r %(G.rMbTVZ~-lN5kO" 1ڨ/L{MhqYyKAj7 f{KEY :P+=W,,~2<|r|=s(_xlK lTci; ] (%ƝɝߚoE_HT CȯM]BYdA +fJEzEqGNLlOM%N(G% i FE#V¬e4Ɨ٨a9e}U @a4>YIZul H[uݪVW1T[= WЅ`Q=Ps塉7߬U EDL[`IobN WnӘduuR)P fC**]-x"lT?B.@1^!l;g_U"6V-,H+ZH&b-OZ/d((c^̵-bA+JdA+%kB ߄Pz2#SRg+b-Ӈ`G{ V8VI+$Ixw/?+K\aanӍQ;\(xv̊X.?(6ccڀ7LX sec܆=::XHc&u98^zKǫȬ©V\9>~ZP]|t uաuǠ}ϭ76v׍vlJu4mA,Z 36p46 ZwC,ȉpgΜ}G;) " YHY,KE󞉏0Ѓ#/PN M1 `{&_۩֖\[mPî,9Vp>ě}=MLN5"w+iB0%Za oH7V0vr%>-nA^!)U~\ KѦu1-p峋Qg@e#E{8jD# TSBkPŖrKѮN=U[ڈt)pMvI!I`(;aa*|La͘c 0H<`e%1/T$fxBC.TuZĸPV7=fX#U9,iEghS g"Qb@ fNP[Bp13hBKe{uh)7KC֦*.M=`ם%s'͖gdģjvBE=q{:,ql<3Yy<ٕXYu؉\xP >; ;k;:t*=h+ SZޣ hqkP5;{ݩ;&I0gҚi[.X| B  *T`ezDo +Єv͚S @S8Z5-&;3,=3&ڪZTϹJYjTUlϥʋ1bohPxޛfޒar$U2)X&AAe'rRk]l >rc!&#q`nʁ hqeTl(R`+o^us&is&$usrTz=dɭM k$]u$HN豭O̦C]LZ1:e'$LzJ=a6[TϗKå8)%g/lDR ?}սsL%7|!YydNce`*VVVV&se@vvvu+sfL4Gg.&L$`!4R6ե2(`ZLИJrbݩ4No:E{dd[ IDATڧN(߬>=JR|f,dn~=ڻ -ujQ6%y0t[J]`4iш?:&_bnȇ쨐57mq(+W*jƾ5ª"w}w$E]ܵvשkMWԁp5g~욊J"! [ONo)R0թ.U(ea&-;xqas/ vIST2ɘCњ߫KNYW󧻏wnV.E(#VGUdq<F Z?:N-&};r~@:beZk{tR06hBT.sS (;1 E?`8n1-MFR] cꩱ*&^ j[S]rY`ee aFOC!2~hlP쁊6TY XDR9<}fHN~87$dv̚d< e&Q,[:2 T;@tKm93`$F. -5gU ؝[/^lϾ޾`ޕ+W4=;`c #C]rmgNH&ftPL %hwU_X5wQg[r)$:5wI*!3Ci>O].u_Hfe솩f E/+j4B Gy=uQfJ':H(1(`06&;kW Ѹd"D$Z54N)RVϏ/V͵]̳uvF;PY./3Ujo5$ڋD$bLNqU1-[jb.Չgjj엪V] 1Z!6ʐvP`y(6..BSZR'sȺfPk?~#`д4k?W,0isﳮhE<%2?<>C)٧j_'!e0P(yM4JlJ 3nO?f]OVT`s5gwy ^Tj7 ^Q2-ay]kO7"7nCƬIz(Oq1m-Ls8v]"DB;6N!%%SUS'Kl<}"R(UE ֕+n%J"fWA" `6&MIMPO`b?L̮l"iY(A\!?<Ә!pJ VD`O%p.#$/"XzBJQ cjk_, GIM)cEKgwԒKLmX-=[c˴Rk*ؘDxOzGX&;U x6z)@-" H(wX]!a`t67F,X}WLq`پd'ˋڪp}؜`hЕ4(Lf[WQ)1Y&.REՌCJA, A_1T0s y:4dL M V_=eZjjY l Uל>"Ozf9U X!$(pB.ǥ,5* aVU5qŚ\s|Ar9༤ؓ -V }j>TxVo&6b`3wgݒxj I8(Aa(y XuK8t yKk|p-ОK)é>')QKb;4 W+9XZ'2eY }p`K9; l[p("Zq!֙nI %~ K\RAT`mlEmI]KڟA֪%>^ck֗V `h8qbd?;k񕪓vYN洮0^43M+ 2eWئ3wff;Gve:>rtԾk~HxP8vKAf `Ϩ2SkĝUxb+fo$Yt;G﮷aZV-qS=EmC`8:+oWX Ԅ"Q/gʺe"[-֥V#,3gjTL?{Pi޲,3ݪDUbx CeuҦ)&nL6gr#vؗ5o';X7?bT%8B.X/qX-537IJ膒… 삋c_M$01:Tu,Y#w^-UGfړV`u.Οׅb3BWM8u1l4%NDkrZժk #G>"MzZy*_,-\zUmQ!?TD+AQf(:խm&QtŻw`)wyV-Nֺ)V8`]F4 3[cR0fUsLnyةܼ"YUCX][l}Gx`LK1d}Lk|V fҵSfu]9jEzmjJrq|Ɵ*Q >6G%:+2Vd 2;V1zXg֮,tZ;KĂ=r2أQszRH*Ыalu,XCUxY5!Wm{{UA~A k|*΋iA f$%X jXU,Ce$p+VYQAòrAhjgu7XoG7FDgG:&_A&s2fV7UYlVWxggԘUo>MMl1ctw7G"韧?a. 4,{&JR:Y^y;ØIK_11єE4-4GM7=:[՞48h B/tm D?%ZJZro$!+e"I)v4eImo|"}\$;_rZ93gCV򄾮N}!OenQklȎc!zm ~CO>U[Jii+ E"0&R mE4Ir6*w-Sn@x#7ix!{-͵HH$-m]9In}{NXb*O 1.ϒpZq4p.ŒҰD#U-i[tn \]®#MNZ +rm&dzR.$ vQi;~_eάy0:m;H}urXk`ZVwJ,[*-}Mͦ%eO*Ñw*{p8o{*~ڵٳ 7*0n]FO*uΪ*PjMУU\Ћ~ Bo>+nJibd8\y7=- a}t)ccޅ.C`LMv?dE`yB^cptp`ZUcЙU0 KR7:z`&P`'o$lҊ)j+d?[r+bp;2{Hsټ–%y*H ${nPam]Z,V-fغLcURn)b.a㽽?wY^ꓥҽ͖Q ]3T,}Y%_Ѱ^>\܋ jٝFR}g_`~77L$Xjuvպ[) V-Ɔ:X/Іׯ#a{#cM45䉤Q:XYkR|$?,X}o眍/`g)._\1=E3?W_$LE?1AgM Luߞfc6?;'~Mߞ X E׹nei?E!oN5\wW TV]iktNvgXoRnS2@֪[Mz_AU5 aK:۷O}l%!WĂG@10dgi,b!j!.$iNǠasewOM$Li\^mTra~ށXF@kxBgWKz39iiZzAfRfw_ٿ3tu'ճ-vcxEH+ݕj2W&7&`@2肣Gc-,Z-kw*Cl]J0#lblbAцU[^|&+k'jGOT J͌`YRwW#T-m7!&o.,QucoWcƭ AȊbb Cl4T`{ĝVu*zݶr+vkDb#XUb(\pV(++uz3vʨ֢Ցc8+?'OWk=e@f !uX$ ]N8(]7^О]-VĎI 1%A D`SfQm^ :%vY: 2`X?CO,-?d6f!LX6ux]xv".&.Wl%YsuoF}gIpt:? A ^-Yh nN7촇Q`o NX|lwUi}zbeYZX;4㉞He~]7v!3NwS&o)u``] .mMfD,fQETE@j_ir춹Zo oBLNrPQU 7R0= ߉h>Vަ MX]_/w=ifٮ]Լ$.GR|>!Q,.M(-<K^(u~,44 @RKTVh:QrUHs 05E`G/$R\ㅇl@OqA r]SzI,;=9:a-8سoB#3+د> ,fd,h.-vۈ$ĘJE c| :֯{=pH9ڠw3>v|ZY&A 64qZ6+ %/֗QX,Z6 斞X)u?KF Dى%A"N5-I1 -к5łEq1X[:_ưZ1UB] IDATSYz gVbLX/NDJA͚Io{25/Եn3 MݼxRt?NdٞrP::m^@[?~ ]`}ڼ/E muqTVK6''ǁŮRHwEFo,%4(E?=`,NhBHl_2OuЃm6Htc`GEuoz`ӣ g4!XKܦ@CS[~qup%o? _l^ݡr:_6bn1OG$9?ekY;(N!Sݭh}%l4E-̅yKixQkmb%FJst}߹shmEyOe=9ouh 6 - ⓨ`}`i=?)X-O/}N$ 65UEpt@Abۆ=`y1\)ǒ՞]x ^=e-_^gBkߠVbSڭYj}.lbEIi7sa%zrz*6. ?9xmJnۂ ֝XYFV^/޿յuٍqN,l\'oeR_C ƋNl^[90&ct~䡙5yez TN柴BڭE$om*$k$9 @ -Wl$b~BLDW+t,M~\?FdYr,լ{gTf0KYsOK;?/}8fRXK ܻdtѾ,vxPx-z%lü/'EE.bWߋY&5*=ǍX5ӺTO-%,'A !ݪlje B^DQBM׊roK1}pvq61lXڣٙe#Uנb5^qz2S9fگ K kK쭘;!m b!,,A^E wPrlb+3;5lf5MZ,^cV@Z}}um-iŋ;w.-֔+dܹ6=dMxMVn[mnM'+-{ ||$6x*ޘnȬn5 )ء]V敵ZHub޲?p8v8;--!VU:0IYkv͵QZdw ]5f4 ,XSlʭ9IAŻ2')uɘe!YvZfn* fg3N'm U6xEeRIr/ْ(fY/lx霭1#m3ekOdf}P#}yD"DIVgliNfB1\f^6Vf+B5a%?6`JGr0w9ݧY1eU >0^Ń8@GR岺_,nOuLٕ_1V'_/a`w>;S_S~e]Jl9ngo1țL,'eSh2 ζ'4 q%N;R.H,|*-x`v .PYRbb̞RkKdQJ⳿I&NRx1;r$&E߀_9Qi'&l>7 G1 Kx'9#&w u&7dX.ȥjeA ά!i=ì5ۯ 3k$0MPXSYpQ `&$`"}`r|$% }CFfOE`q f%lƤ8f2f ̪I!Fv(J.XZFnnd 8%}C$e9!ej~MGߗc)e O6⮈U]eϵ Q}1;:*@H=}LH0`7T"1QYUŪWz˨@:?1i`69>͙ yyXZp#@ DWj<ъĶt⃥Ru^ϔ셅A"$g |!#/gjp:+c@k,;JY(@ݾn42@faB 懯Nf3O9xM"?^ WC <Y-asK}?#2gcATL5Zm;8v+gU4O UQeD&$ xd / m w (cu?EP"1ڠ^JѴ֮nxVM*(KeCWe*uwhvY#eqӸj+RU]RuxmW5{-W U2[+WΤ`W&`ʫΐW G0b10ȵ__2 3׮}w'[o95o{;imU֡.m dFm(2bQf2b_]ld~ɱ}WsEiG阛ɪ-L-nmw^gѡ!=kD&dv=W3c'_X7kL>}*!o+cW %Ȭ^ 29>gs×}⵹]@A,$ obňav2skRf0@+#+2[=h}tlëW Of_y?w3TYZ6J2cu;m22Jhe:m !=* :fU'̞a#ޭ缝(0j`gnzQ{jȝhX٭vi7s\)uԮ~z-6,QAOb\K`*}A M0_{d'ӇjFwMupcbbf$Ŗf+i1@uΫt2Fq ^Ukt[o99.eu\Z?'޲n-”" T`Qt>Qbj^qRs{ %%[3Ku? d6`'>v[ hߵj咔zj0.x}vȑ|%Rk ;Њ/3C 8An}$}oڧ'?; lT%s d)M~%ȵ%w=EV:FV.]e.QӊٽmF5an>c ۣ͉nFC6Nw6\1\:sKmJ'݂ i˗cyUU%][uk/6[W-nц7!mF5aV2+ƙK>V.GtMlof!e~0:f/ k.jAf*:mō+ɡ~9N 0fu9zfUߠ>JFL)8f'a[}fs=1.J٪y 5\x_ |λEWXAmGUI*ק ڡ!R<"l=6ܶGL`tئ/ԏ7M`&d,yU􃏪c;&Dc~k1j琾~efx 92Ō8@1Ao%R~Kx>"-Y*duUx5ݐ1WYRdtJf躆ULk>V-Yv$@XY0TF- l4n/ۼƆJcij[MޝCjERfifi ?.رRՉړ$vtӋENd3K}r9}gha3ղn6bn}f+f7sk`444мc8& 6&ZUXzEQK8.f_KٗNϜAA}9N,]ELMH ^H|)!Yfd G#M•~80aG)hR8يfJ7LK [X,WO,gN]߈$'L.1Ԥ~l,# HW啛|M DIέpˑ -f>.ViIid19`9\ -#w(Z/DUvm&F ZaQaԳ2 {(n޼fk~"pRd ^Wh?GA65E;NFSwoߞ`@7`&'R=zGY7U/ѵHM@i4镣xhݍ ÖVrD6aEo;R-Lo#і?&%%}jF\ xV["fCv*fyӶG=al?sK.9b7Y:lzǃf{@ÿZG .ҥސȈ-*# --*7,-c{ةJh_Q: =u{k.#(cpU~abz30Tg}]oPoQGRf_z;wڀ݁{ƛX mGV6ǚlRR5%d6Qf/S"bw1KEiUU8 YTCj$ؽ,r kC-v$HTX-R&(ßJyGE!H`?򓴴lrvvX3i %d[߀8\wSq,U} &= Q'JUۊoH|*; gr枊 %t7;aUQdeS{K,+dicRy6`KWؼY┲MG__ _NJk׶ۡ.^.mp%n H;rdb]&s!W0>G m-ɞUȾXaG|l1Iq`RZRfK?v;ۭfJDe =+(j}ؽn-z8^-yZ+9|9\v$JX.f VCct6k Ldu̺XT@W tq,+4XlJ;mݐPu"?'*"Yt*uO՟\n '\o3okFEOd4Y\|f+;lCj|Tw0/h@&]jw-MۯRu4&R@+KBU~춚vjWw)Uylq^_ d{OUoy&9âS신\{\ ߖl-:Y] t+lE URX̛R%bY R?%`r}G[?qz"^'r2>\;H t%5ed;Ӌ5dЦnBrhd&S@l]LƵ-Cf!\dgSv/*^/9d anH y3?$B{U(PYU9|_|A^_ƛx[3kȪ`_]LՒ/=f Y>Ln+#1Vc 丄:r_wVf0OAya:| wP<;@n&{;εjϾ뭷H=kiz:yb\w3=,ig&OPK,ә1g]L!vIh%n%`1Pk1&g7NzpV$w2 ܫ^A֣ϊG؆)va{zdNVٻimiu:6˥ƋZK5z'+ǬKISنzD[t;^*X:d'{+"Y] 0a)x%\ ԇŠ_]=CNmD0;7}6@_‡HW I>Q@ѯ$&i.PYa3(۔DmK4Yn$b3L'P-,1MNjd+?r.Oըr7RxȄ; }$hסf$ɓ|v1}Z]J2c_ZvbV>*մ/ŅUhOɁ -b+P5P˝dFr]=w[R.K ۂ0x7I9i V!c}jvMa,LA.JfId)kXWh Yj\'%V14B637DgC.kd7>Wo/wZ\9Nb^ m97װErgӍQ2 ^^ /%X.#01 B ']+4X+S`RGO-EqZ nk;93:"g@ۀLGl8ZcA5-, @2Egӡ֡tz&kq]m=V@[gi!J+]+Y1;x+t''${mx@*B~cRD?q dpҕ񇣎9ס;é]WR<хӱP%pZ^Kw--as&Ol2km(yWD<ʐSusӜ@srp!;L 6C0jkCHc!%}`wեxj..|~Wපk^D*=0we'^ֵv*rGE><"O$ NABp$6?֌ׇjX) {J8%-kiKW?@`Abe/ c¼2T$[9,ob|~i \ -:~$W斖,,«Un@|JLmkeGZ#\*ւP,̳kTX:*]=b)_*AAdB]ce&ڜԎ^إM1yM< cבuQo1YמKˀ0Yu.`1[SB@);(x5$LE+IirŐh:xZU։)Z:!I}5V[vL.dM2U'"n}$]jU]Me>Ɩ+e'(u`&{#uro%!Q081f9xGW:zHaejI1P=XfjS,R5` R2v-U^Quʆ5,z!q]⥣X,rr9MٰB2!ӜyO Ήx:j-}}PqY?CBel0{>-k)h99a@VdEbV@bG ,ldXY1 X(dX_ٲH:*hwO>$ۚ`GI13G}뷶}⒂e+X{ձ[kk׏1` d{t"UH,jȕO>LpvD,wY9to!=*fI19Cwڇ9stWٵ 4!lC==8b }Ȟ0SLTeU#Xclzj`MV+]u՝ʪ,|Nsnnm֭~ƻ G)'J8u߶H,.][?֢BLm[rPۺY,2ح8!O *Y Qb/hbYK#;s[C"Kئ_];_E^3:Qnax]6P?,YYOHq|(-Zn%0]Y:w.sE= > ˞Ӕ˺M-`b",E<9*h~7 -X(61?R7z1qLEW%FJU@©~xʖ)`+k LB$^ '9IֈrJY:rfmi$~'’7EN_ Д!B 9X!)YRʠhYlYU^/֕5UJ|Iŗ$;זA vND 9da(26Vߋ#,pEmvt)?feSp*[Ti kMX-(Y%^,yDמ"UO[fʵ8F^Xಓ$u853~aG t TH&P0<__l+|N **' 5]Y޹V O=2 B**kYm!T^<ѧE~d>d/=LcL=SЅp;8@lFWz""^,>`ˆtIJ.~H̛IlОHhfmM'},^ZŨ1~F#vf8N6(qrUpALIX=/A\Dnui[aBµ-m0Ycj=uR@W:MXg-?Û19YlxY+a3áۂ!EۦuZ9@` -#;=  w,)1%&v)*0x\`z2?/%@)CLfKuY` πE]VmP!Xfd^,g $ \R8!Aim,qR9`BAɷ,];?YY^^RbH {ԠJO0ѓg[񉂴G;^'JxWt&&Y(` w:>kKNdZ[ >}b)ɫ#)/%/]d/"U`Ġ$JIj0±{rb;̗JLaspÅTjL3xŔs ބ锜?M3Ng\6D,{U`TW%\B[ ]Aw> -/"J)/KXd+L@ݚIENDB`perfbook_html/node340.html0000644000175000017500000001613711672746163015652 0ustar paulmckpaulmck D.1.3.4 Update-Side Implementation


D.1.3.4 Update-Side Implementation

The key point behind SRCU is that synchronize_sched() blocks until all currently-executing preempt-disabled regions of code complete. The synchronize_srcu() primitive makes heavy use of this effect, as can be seen in Figure [*].

Line 5 takes a snapshot of the grace-period counter. Line 6 acquires the mutex, and lines 7-10 check to see whether at least two grace periods have elapsed since the snapshot, and, if so, releases the lock and returns -- in this case, someone else has done our work for us. Otherwise, line 11 guarantees that any other CPU that sees the incremented value of the grace period counter in srcu_read_lock() also sees any changes made by this CPU prior to entering synchronize_srcu(). This guarantee is required to make sure that any SRCU read-side critical sections not blocking the next grace period have seen any prior changes.

Line 12 fetches the bottom bit of the grace-period counter for later use as an index into the per-CPU counter arrays, and then line 13 increments the grace-period counter. Line 14 then waits for any currently-executing srcu_read_lock() to complete, so that by the time that we reach line 15, all extant instances of srcu_read_lock() will be using the updated value from sp->completed. Therefore, the counters sampled in by srcu_readers_active_idx() on line 15 are guaranteed to be monotonically decreasing, so that once their sum reaches zero, it is guaranteed to stay there.

However, there are no memory barriers in the srcu_read_unlock() primitive, so the CPU is within its rights to reorder the counter decrement up into the SRCU critical section, so that references to an SRCU-protected data structure could in effect ``bleed out'' of the SRCU critical section. This scenario is addressed by the synchronize_sched() on line 17, which blocks until all other CPUs executing in preempt_disable() code sequences (such as that in srcu_read_unlock()) complete these sequences. Because completion of a given preempt_disable() code sequence is observed from the CPU executing that sequence, completion of the sequence implies completion of any prior SRCU read-side critical section. Any required memory barriers are supplied by the code making the observation.

At this point, it is therefore safe to release the mutex as shown on line 18 and return to the caller, who can now be assured that all SRCU read-side critical sections sharing the same struct srcu_struct will observe any update made prior to the call to synchronize_srcu().

Figure: SRCU Update-Side Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 void synchronize_srcu(struct sr...
...onize_sched();
18 mutex_unlock(&sp->mutex);
19 }\end{verbatim}
}\end{figure}

Quick Quiz D.3: Why is it OK to assume that updates separated by synchronize_sched() will be performed in order? End Quick Quiz

Quick Quiz D.4: Why must line 17 in synchronize_srcu() (Figure [*]) precede the release of the mutex on line 18? What would have to change to permit these two lines to be interchanged? Would such a change be worthwhile? Why or why not? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/img98.png0000644000175000017500000001413611672746023015243 0ustar paulmckpaulmckPNG  IHDR1=1:YtRNSىHIDATx˙g4& $ ^~ R0 4 hTx9kYHE{5YV@u~F<^Z1'R*}@DxT[kMj5Hɸ7.^$F)+*"0&s;]zI'A_r9"&|SrYkxZzyy7=' [w@oO q&}?t|ޫ׆gQ7FuP -(R )rR[XK_'dpA~{H fH?W_(椒 n%3JP,'+Vȕ'h%>O4_%?Cao-Ww)L"<|ː[7J֭J5@Jw(0.:*L9m$ *Db ۞- `603,z s肿TvO'|`WC1KۣWhJ+_܌}o*b ^>ѿTnRR,Vg{WpE+S;bh( *vJ!"t": N YJڳdD~]?!"mk۾SiWPzD[2Zai4@<4> h^曞P6}T2k0 #тcF,v+|_kBiW C?^oD|Y? /=)L$EЂ+-UZD=$HL^̪mYa͘1f8){uѢ`asCHO-td QaֈVhzx&Y#>x#: }L9:7}Oaŏ ?] 3-J +> ApU-G_fd 7!ig P`}=(k/eDP{nݧ 0b QCeJ-p+6 xDCuVQT5J8PVO-;^B9Dqbf[^8^'(5" (h;%w:>v3zSK {v6AfS¶#YYRa}Vh-pP1fRgvoJbh(M(B3s=[u3a\7v&u>V¦"l v߳qEa }(~9yղs?Q79JBtf=(6#0cDȞeTG<_oYP?]{x͙7˰h$J~~Q`BG/D'Xp9 zgQpKdam*!13Jk5jk ~Ч%X0sOxh]P1OPfv:z6-]mjPV e={HD }{2e" -7'-p.R0Y=;6]ɒoԆ88 W74 =`# tdFDvB'}&f|Pitf+-H-Y>o$+ D״9j֌h91~LO:jdVTL\-9O FV}^l[]ZW]]s 5io<8;PG;Y4zn %<Dv4F֡Hഭy?ƶ_T0eR(ʦUޓ KȏPvgJk1sڃ -O^:hq.FqX*Y~f XdWVDwwsJ[-xm٬m?\Gw$c`:Iql7Pd& 9[#+DXF)*ࡄɍ7NԘ̏$,Ʈ?W^9f bbw*{0A>ĤNtENN~w=퉺cI=>+ ]Ѥ>}#},@9nB'"ƬqsۘbS]_] 'QQZt<_ aeV aeV ae=/hO\aUJqTVIQ ae/lDWF4פ kex<IЏOy&~槹vdomouG6&y#=h^c`׉ӳˋ^(x *d)1*s{#UsVX '_Oǻo{@>e)ZÅ(BI:DyNG~+0kBa%tJ_[@yfo ckNFQ]rŠ9)Gį%H>@. ݤo5oޜkOy VONGVS."ۡ9ՙSjmoB@CH*6HRƒ"]:F>ތ{7N:96WDz7UnNLYoc+C USET{L޶WB ~4jfe'sLRJy2Ht1|{I&o oS.rn&5m|v+:u`ۙa;,v Z N]~rô{p\[f@$f  }|,&YRnH\>Ԑ6MrobpXMY&- xߊvq|>>WWfI]qvV_x{) z a8vUO28uƀ ^꒹ G`o.]EWށXHl9Ɣ'l(f 6gY~73M7d [i=ZuTnzS6V+)}t\XF #[cn;cMI4V6O 4l ʢXY4+ce 'w`F.r`.]6sB(w6WQL}?BU횽☖?٘vi7=8|}-Oșn~+ҳrL_ 8)ZVwi7]r-rd08vD^vV JQ%:\S#oZ_ R(_ceǤt<c1>?&UZklnu֭dF-iwk۬U ̀(`ѹt^xI>ΙM=B-50 4p젖ê5 w8oz/iYtCPǨ}Wt'NZppqtwoF]҆u p"|)ܨ!xkeȝT.Q98|6EY\ދT.ϕYƉhҏDaqF hj7xߧQ'xָʱO- :qƶ!œfdQl琌; ~8ws >~/`&^6/X~/nVZ|zC6`94hodQߋ"+~LnH#Z'iR}g+ؿc9&H/E`~)fd+A5|HMg:|MgX{7֑򾪕쟮<$AbgMGGи_8βc/9hl{hOu>}}ӔVYY@ñh8V ʢXY4+cep,Eñh8V ʢXY|BA|!:>c5Yh[|zwZceS_{M*"VBɱ$*-\'sjuglIVi's&Ig8йw7I7i>5ĹO+/ =+zw{3Y˜>mmjxA33\"ksDZQ G{n;2f4Du">Dw3xBqW q'MIl x[IHmW 5U>ޕcbE4åtߕc!cuht>f)Sn[zV1]|o||Ky#^;|8ǨIh&kInĠCIENDB`perfbook_html/img59.png0000644000175000017500000002300211672746132015231 0ustar paulmckpaulmckPNG  IHDR8ޚZPLTEb``^\\\ZZTRRMJKPMM# hffommmkkiggcaaXUV856iffKHHC@@744wuv.*+rppUOtRNS@f IDATx]*sůRKiRC6̀oCY?P .`mx7Z7Jx0Sʔx, 㟬/9ֺ TI*aʽnsp-k|cQ3m%sM5sY˂32?ݵߌܠE@, @7BY_zQ\+Sڜ{8y|DV듧nuvQaWwɛ3wJ WSxvVuLlO$?zJ&4ܐx #Fa1K 84zy E8uou 1qY6eK:ݎ XZ~ڕ^Od'lip 7h Xn a!}YBuKH:BXI k:ѤKGHHEgbgJ &0NfT3ˋ Z"zTZf>I\ʺ?KwA5ԭi AAjH/AԗU "(1Q0H\ڌgR~% 5 Ip1 gwz+}Sazjg<gƱS;<ޟ+( Brl^ݛG-ShpOd3ͪ5%>6WЏU* VyQjz@snUKf_:~wW!y[33%xEyW@\-hxɫ'4a/ŁM4:V %Q~TLLHpDA+3`I;ޕE&g|[UL!ݯ|իI01ɏkÅn5/7Ro]{Y0qi*ݟֹV#ʄkGЃBU E<,'Hޗ9qFnTv/47WB v:dC$`灖M` f +ABy0J fT#c:Խsi%%jy@qM!':{E̓·fjPsu\GkOqWvΏ(|]eUijLqɉrhW v@t>Ǖ8i ]Jw\h<ɍlaG%2wb=r*NKX _RZrlŹ3g}g6JACWǢp]a;Q׮>TAiad_.^lLiY+ f,YFLWxkJ28*5vfg?ap3֏լT9K]$3-Wم3/^xI06n,i6X k52JG +*X+ǯ'RG0j/OG,xV8XQA"Gx͜͹SBq]=wAtʻ%P'juzȋ" yA\^ncG*X8UJߤe˔:9)[ΚJa1C9錊5'aɷLԍ~y]QqEɒa7y 5GR7Hq1uPaqVü!vw> PH "LRO<C}B+0u50Japp.`197@˕AB*gYp)!5*^ˈh+[֐!s?ex`30)|@*MX~!*9y$)Kϩ7rHkZ:rlqӓ7|vO2I״3zkiDٸWa6>ǁq |NĩU~m}bVJ05 LYQk?jlyszc"VѺn.i)DϝD͚t&>O `1A4̲ӃAZ;KLĹM=ͅ k<~D@\r909 j@{R-8_`GLVAJ:K d,BLsLijUd|i H>W'i|8S>E=1iǰTyFʅ "E')v1qº~5~}_ ܮ3pc E~>ѹ((@=w0J)"Ηe u?@4!obzW9J~9/#Z;uCգ\aXd\eukY-JB}+>O9NPOkE%ȄHQH9 QoFTBq QBI:L§\zd5,i%O<ׁ8 .]r z86N渐Ƚ7S{iK1ϥxsIÍe"qgdcI%_/i]{/_]:Yڵ?NvBYU~*p/ n+\ᮣ8y%W{}ܦ/vuni_8s2մ+8sqOi׽pO5r'`aDžJڕ7NQl,M t0ƭ+ u *f6NZ$k>9yW˴m)r $w>z4,]7ttɮ%4ufM &^sύm+INd_^7ZËG//M7V^a>]<{䋀g3N-{EpsD:M^ݶ?G˫sJ7ap}.B$NNkwjȨx 9jێS$<?ߌD0u^Do &pgWSDffKOv5ig6SH:6q89g®(24Y2I#8bnw}iV%Ό6s1?(z$\Xݬ9L͸+\ q.@ÂKq٩'i4XkR6\l#Elv(DوX_v5Hl"NԠPiϑd,0"idzw=3oX#cތ[td*|S@"#'BNσneXa1q$v\ͤuwoB2Ճ?ۺ$'@OۅTL'UO T۔6c,Wkvu g9p͵rL(nոL(Nz^^us* "zC)I~jƚPZi? Nwފ/ǯnF37Ժ@yJ6oM'J&)ߔCn=| ]ZZuEK v4g% ͿG7lcG *'ы$4]516atii9JF VzmpN0oCS#vT,oj9]D,ĺ Uel?4&v!)7":PdmSޤ*2;j.3 2^"=f4-:5%ӽjU$ N'OK`Q% 'Y1pb)#e. @Φb$˔l#/s%1.Cɭ&:}*\.q?4:mc^5݆(tjğ#jؾ ŜS*,^&ƾw.9眡wEձNTik"1/02AU)txN#x*қ!ăt[S*#A m ٌsY3ML۸h-g^¥,k]zYdiB8?Y9-Һz%p0J!*\+Cd΢^ĜQ=Cٮ&lkWi9kh>05x^gҍps䐁#ws豶\:o 2pkړ{MXM(XƟ[=1f6y4HsB-޹eOn 9c y%9 M>nVyPIEm{dŭs[OӅY;rݜq[evsnNyuτ<[5!F5KFѰFcտ".qB=,Mit[Iid;'i  0i@>BBW"B#yT\TF”SgQ2ºT0y|׺pC$w+w2=ٔHZL) ]k. ] '*ݮ`<.EկkPlWexS3pu B|ͧlWz?Z乲kD%eЮyF*KZU)K=eΫsGfh|I6IGg((z'lWz?Zlh ҏ*:UW@J_i8ZH tRR>lM!.Yd.)+$XblW3N%v[Veo@UnzY%ު?ү2lWȦI/]%bB6=G2u ؒ`t6Nc0QV$ DMDҌ{Ep ޱ1,N=6^_ŵnȡy(ivWAey87Q\P(>iH9.9uwE|EVD\mEWcf} όbmtsoveخ,:cph{XtQݭbES7MKpm]ooVqst;P*a.ze9% ># c 9캴 wV}>ͅn/Gͽ HpÍhgWrqg6N?,х&9&6tTt7} FnD{n5?Glnpth}HQ [&+2Y aX@m:z:ЙPzY S 3-Xn$~ EjKJ}(h ̊pw\hWbښ|XpSE86xkRP'KH͗d EݦP2Z\?Fo._,^g3eo6KHEQ_!h@'8"*Eq3ំ3iG<.Ze`!=͗㯯km'TEaX0{ׄ@:N/Cζ w*OKd[s槄$ğ'—$!+lJdS2appIDzX$=7Fh&ä] *R]^*`u_&x!j$ߍ=Yb%G$fGpp)Sj .0sS%U?~^ L8l 1:猡/Yn~ up_0?8R1fմ%vbV?JΘKiAk87x\u`iΰ|)]=̻`6kUӦW旙{GVbU t )kbs@--$eߐhTT8՜ץ۩h8dy!eN=[K jq HkuJ{x|ZaO t?Jt;G-=˾e8mdX1ZV L%.}Q|Bg=}؂ KT HpTmdX~(ޏl3En6+4я]5##=Wc6}SERW +@H<###Elo^~|e>:PeY".OdddKA~Jt7_h~$ µT+qay?e:m U4HE/ {J*r~~hicR- U4_`~%XE2vG'UΠ3h=Ъ_r]O*. 222~u7JAbaS'Z]R4|Gꊗj$?FaaAU\ uI|lbt<!N8ZR\/-_IuGq+A eX|5teV_OgF3Tjã VUWHדG*J-$â} k צ%VC|<#{Z^],XM8ZjY-..ð4G0zM|l8'o.1mXm(:9n>9N7O7쫁PwY-gt9&3JIDAT'LJ']+;<ƭ gx^Тq+b8&귏z|U?bw8DqNz*>3@zmV>j+.ޗ("3> aKg,§/*_ӏ# U1n~܄@ͧsȪfynf$71K{P]s.1sky|ڈp<*Dz\">/1~-mvѮ<$١05y&ؒUYׁFuz*(u.]+X*KȪr8HYjvxs ?m4h8f1.h[V<3Šk(F* (fY8Pچu'sNJ3C | TJ;SC.Җ]ʏ)HҒ*-VVVe=%ǵr᭬IPeUYiɹW\9/_TW\H{u XK.? ꘆ廴ο:˶LqwYhrnﱳdU=|γv6}CE9.|@r<@ĬVL{H"xȋWq.Vܗ%)uʏ(!/^ OmbA80$-NM~1%8:/CF {+7H+s\q-~\r6}WNYBU&?._Mr z^n?T]g\"J^g> ثo~k D.3.4.2 rcu_online_cpu()


D.3.4.2 rcu_online_cpu()

Figure: rcu_online_cpu() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void __cpuinit rcu_onlin...
...softirq(RCU_SOFTIRQ, rcu_process_callbacks);
14 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_online_cpu(), which informs RCU that the specified CPU is coming online.

When dynticks (CONFIG_NO_HZ) is enabled, line 6 obtains a reference to the specified CPU's rcu_dynticks structure, which is shared between the ``rcu'' and ``rcu_bh'' implementations of RCU. Line 7 sets the ->dynticks_nesting field to the value one, reflecting the fact that a newly onlined CPU is not in dynticks-idle mode (recall that the ->dynticks_nesting field tracks the number of reasons that the corresponding CPU needs to be tracked for RCU read-side critical sections, in this case because it can run process-level code). Line 8 forces the ->dynticks field to an odd value that is at least as large as the last value it had when previously online, again reflecting the fact that newly onlined CPUs are not in dynticks-idle mode, and line 9 forces the ->dynticks_nmi field to an even value that is at least as large as the last value it had when previously online, reflecting the fact that this CPU is not currently executing in an NMI handler.

Lines 11-13 are executed regardless of the value of the CONFIG_NO_HZ kernel parameter. Line 11 initializes the specified CPU's rcu_data structure for ``rcu'', and line 12 does so for ``rcu_bh''. Finally, line 13 registers the rcu_process_callbacks() to be invoked by subsequent raise_softirq() invocations on this CPU.

Paul E. McKenney 2011-12-16
perfbook_html/node383.html0000644000175000017500000001001711672746163015650 0ustar paulmckpaulmck D.3.5 Miscellaneous Functions


D.3.5 Miscellaneous Functions

This section describes the miscellaneous utility functions:

  1. rcu_batches_completed
  2. rcu_batches_completed_bh
  3. cpu_has_callbacks_ready_to_invoke
  4. cpu_needs_another_gp
  5. rcu_get_root

Figure: Miscellaneous Functions
\begin{figure}{ \scriptsize
\begin{verbatim}1 long rcu_batches_completed(void...
..._state *rsp)
28 {
29 return &rsp->node[0];
30 }\end{verbatim}
}\end{figure}

Figure [*] shows a number of miscellaneous functions. Lines 1-9 shown rcu_batches_completed() and rcu_batches_completed_bh(), which are used by the rcutorture test suite. Lines 11-15 show cpu_has_callbacks_ready_to_invoke(), which indicates whether the specified rcu_data structure has RCU callbacks that have passed through their grace period, which is indicated by the ``done'' tail pointer no longer pointing to the head of the list. Lines 17-24 show cpu_needs_another_gp(), which indicates whether the CPU corresponding to the specified rcu_data structure requires an additional grace period during a time when no grace period is in progress. Note that the specified rcu_data structure is required to be associated with the specified rcu_state structure. Finally, lines 26-30 show rcu_get_root(), which returns the root rcu_node structure associated with the specified rcu_state structure.



Paul E. McKenney 2011-12-16
perfbook_html/img266.png0000644000175000017500000002261211672746067015326 0ustar paulmckpaulmckPNG  IHDRtX6PLTE""$8D 6SfDDff"l̙̈3''ݦ*3-EUQ}cD33U@@fMM"33wZZHoUUZww~ ff?awssuݪSGatRNS@f IDATx]bڸm)p'$ɴ87q%?eFIKZZzoK_-e+_ /d zr]~xʈN8з`j_. >6tzх,Ί 2NYwo7Û&['|8E?ƾjWRx `e 螐l}Y^(,y:,5{Sh?p•W,faTewKDn QvCufz[mp0inV[dwU`Dw:-.U[X88ḁ,sZ{YvUB?6dp߫S'qp.Q'kݧuap588"OMisrał *4KιzI;wQX\ N1q!5`iP!ƿm]WwOi5*pPZ1wNoy c@ѡЌAM}wwG:hQۿ:@QY< gc]uh(lPD~Na{.,:f 5#Rb ΰWkP$0u![p :uiArXyիwZEʲ?~C?e 4:qT^mfT0γkf[ Z[cgmuhm]f)3cf+.?m<\BZgNz`ho&S&X֤!30C;qg}527i`l_2u|' VZ|&j-@uw2넓TpaZ`n/.㷸XE#'=TO2 |p' .): t$~y b=0wGӝV[.a(/5Q]\0nZ'u'_gBV)k5f޳PҺ]oS~}nY iIݪDgޛu,_gm^y0)RW;c^Pt:ڕG^B0į.N<6INӂup Ywo cT1:I [9u#nfGT1cºbPcYw;h/< uՔ[ZɤuliMc5ɽSNgIȎ:qyude}ʲ:^ʾRL]+ʳtj5W{$6Ϣ};9YCK? +C6r@-ߋ7Nƹ]ȱ!#_J:IAe]ݥErG}Ya:`cF.SgUfȣ&s,4} Reu,ljBCurغ.tǂWLVQ\!Qf6>Yui:0γ٥S/֭rddIT (23.e. xkztAejfaL:oe Qw :,@;35*l]0#uK ,o3okMD&P=۔.n|:]acxi)t9wp?taO0GE">=Pj^";+x!4U'}7gH4f'=J+Í%np;O:u>w߿2ז <<IS#R(M1d"g.7XEJ.ӿ ijoohڽ_ VuO:o(o߁aG k K! {sq+beXYD7*u$,w=>v] ,*0 K`vu9>iF'"uyNbpou*l2bbo[!~R:#(wv>;USNttšuOo51B꘩j!!S:fbu^mO6})ŤYu(:?ˇo6+?eQTE1L:) 3uQy},((vo'#zСN;z'o D]яC5!-p oW.ԩhWYWAP7_$I!T,e-u fbq5,/&wiTt=6]3E M ,]հKdktd]̓b,Ql}԰B:{P'GuY2P(4;4,kX>{fʺ>A[ (![(ꆬ&*Z/_;Zdu:z9`VӟY EvS u20s^=!kX02]u=Xud*[zÚhI8RdW=ʣ{RWC2KCQ!Rދ1a7ʲi װ} Ԯު g.UbQWc֘JKu0MPa}װb̔vSeyz+aY*:qiv"1QGc306T;=ޚHe]83@n^5IDF4i02Q'D:*^FqMFmBcZ1l _C7&C ?M:9|7 4'oM$,y)m1 لoW3e3!Esu=u+UNסNL$DvH.ns=*QMh8Xow{9a:&M&V}[F7 53w~֨Es1SfE~}Ro~S6y|>+4ᢺ/W;!*M:&tk_/Eoؘyj N E0Dj=|QNDQv4Jڇ&|o xI[U׷l>9ylf ezVSgpgՊ>607qHus2nu6eXyĄX`:C&65[1#o7rڢ:M7€}'Qw O}'\0fa{&3brP`Umo߾m~ ço*me- 52, jlPP*:m>u H]~IEu^dzĔ'1LCΨ:G[Adgx_@ְӦ0NbuǧI]&m6qd4O?%7NInH3$pwPOdgAN"Qg_|ӣk*%*QgLzh0Q&ƅ:(Q)K `߈[p:u4$ʡtmRfCxf3n?tF Y#@l M9:R1Q@5_rQhgU@F@ )wo ͋}l 8/QgN;SGCȻJbӦ;BXBԩzh(Bd"9uֈ:僃C1!n֣Ӹ;qdRWYY.yQsì\r,b%.rҗRuh#VڼG Swƕkk+_k*я3,Q$B_L`|@(b^%fʺxPƃr@_G?R(Vmh^%u n*ylrHYC3 7:\`:HAʨlE@<IV&Tr \jDG u@NGl>NLa۷17.zoqqR@;JZq<4^YRx`9l˺AC#y䨳Ê$f3Fxչ*x e:uM?x:NjX|")ꘅ դW$uE""4E"HfԁHf8<,u AA3u}ض} As˹?UJ3(@+E,u#ήk"EՍ:u fT$VԭE=gYQ> ]E!/&bzgQGC4f}p}֮H.ԭ u |'3(G=āk%LnqQGv'|RG #\6NnH}hBo"!΄C,qFЇ5u 9G ʰXG!G)lI^9`:!=5a\9u'ļa8TIK]G$P[uPGyvzM8Y9.84Nj>{OOPm>⣎ م:4㍍:}X:yX'0%5_qR]ҭaJ]g?<ΰ Hn6ZץPQEl0 ) Bԇ>&&;Ze'~$@-A:b**2 uay0^COaR(0nnyPR(nƣnK4-!kUuF>Ò7~yIu1?rUu su9Wd5uqM㑌-Ѿ w^ B3 '&fީcB5Wyeݱ:6GdGyxXh\K ."jF!$h /. .ҤM^ +y2ɺ(LN -:˰/nHD.:l4S]5bz^-Vԩ6Tv^w97'V昽Ж9.{Dt'btݷ7.06x2mkC(܏fUSO]l/|h,{\IP鿖AI9d>>ޚO/g[mHxIIӉǏ<;$z4Xte:0aWtO ]lb9}{kAow$:=sNWs^,PW=]OoVeCuJͷJoqCn[$u?Et1g|,Тc.C!ׅ2Q#6M]t*/NsƂ!I%ut\!$]茊+t'MtY3b`@*##nRU*]u(z]}҃5vn*#&U[17}""~"#'Um|>C`ET08r ȬN$:It jU މaDXZYW aZ9v฀B7MN@߶}$:D]ҙs}xH߱}uοenК7ooC D ̺X%4/. EW/|S-I rK{WėJt"5ѵ2?ܒ':ѻY>6UǺ?Q{Ë'^IU,*Y)bC\:E VgcNVff5Lݷ|gL͚tJqiPnIjAWU.Q^1&";jwğ.t‡EFC&>$F}HOM%k/ 1'| Dԫ<$!(qTsd/:qnJtSL|UZ>@r$ ;ۋsY'1+կ!k$1a|)nP KItC@EgS&EIKV՛^It0d}v|~):"EDEo G3V.\EUru^x1^ܨROt_>i,zŢ[͇M߹jTt!"$:M7o.ˆ {/Gt~=)_e\(It#C8:Ht?3h3|l˸aO,/_5-ю調sUڕ/XWT#D7.t ax^k1m9ӊ{Yz_֎m:@AtBtjx=Kn69[K=0iGbF':q$:$:Ȁ0蠡^ a0 I8EgZ FhBtT];!2$nαAu< LNH1$:$:sKØzwp%:)I>Dt=$^)?uuwB;Wg?0|W$bZO]~'K at$=uw:Nf$GFTFs%EDwI^7Hɏ$:QItL2w`gyBtt?&瘓:):`$ V*ItޞL*\'j4I<*Dg:\qIDATj̽upX`_O:5DWz $Qa6%B]B5At5u$@GbQ\p^P$9 B 93kt917*P >_λ@)~5$z Xr$ bKl-$JxVeY!+h;+GV i?,猶4Yq&+5Vh\uJ\Q~dze٧- Gr ~~_~H.n/pxٿ#Y:= k/o[@=yYQU6N.+f`!,/v$@!Îj7`#FA ?`+_b 8M7h6`[L+S,K**}S$Zê˴Մ*) V#j2?}wvBN +|x+IYTvvρx3VJTvU|~>+eaDnP N~5O΋tgk⾦ٴj@sƗqÈ)]3ϊ%5UѼ.T4mvf`jDK͹%`ҵtxzGx&vvł%m&!шLK(dAeilzG_x^ NBQΟtʼnЪHdc+,mY V_5GTbTۗ%` ҵtF+i 9W9)kS-O*yA%İSM-!LTJmmbvI[RgXT5ըI;5׽ BԔurFUcyf~r#eWzW{{H6rWGG|![RfSy>/c횡^Ҵ8dW8dwp8>"!]y[Ju` u6 g5fi$j`eBX7)ŝy+uhq2l_Cu Yy]Ey+*5urŪJ+ǪPʔ 2J_g۳jDv򒶬:mYTZjDjNVYjêwFj-XO^zaVݨS ׬_UT(UfYh#V9FVL?2~ iV9}ezXDY=@o9qBʲʉ~z@P /{eŘ'QV9NA  OwOy,Y!֪9No.Xg(ZE׋ПOƏQP({?1Q>+O,yTXKx11QB(YEkjY-k/c:k Smp3Fp]^x5R휕{|,"k]iRMdT'ӠuP32*j݃( PTSW]'GkAM> {QjY z/ksn VmղZV:rZij ʲA1Z Xeų!g8Չ\'O5^&ιYEx#ʱf_񤐗e$:APtEʚ`|eDDSa}1-(˚ 2&F;,P,%]"HVT{Y:d-euL[a&e~ZFEG*R D-eu;ᛏBr?%X/nӎ&rC3!ueH9W<nFzdYo`[s[+I͕՝ȳ::LRdVG_I:*wCn['~]=U7a")c)kY-eǹ}|m&f&S|/E_~qӷ=~8YEӲNJqx^=D0x8x|%1qU4/]R=k q+Ji%_s{O}//Y_} ҭ:w3Aw?>zǷфYn}^c'd$;ر`pWx=$7_C VxVO+:W=[>R<1 SXm+jp}ײEE[R׆U5)D" @mػ̨|%ބ u&z;>|suнݽ>nkvk;}k|n|9@mjRuİWǨ25 :DWqteׁUΌC65 ӄ&|8R ׻6?yG&@[7STʟ/jFT9x3 fa6zqw>_$Uu壕+ƥ_$U5pK. eOsg>_$Qy9}+$޷]n|'dNŦ8oNIk):%s:f5T]JJ)}R [OD1@9 AZ}6UT̸40!9 x6ͤEi-}5W8IgW n( vEJVks+z$j.mo*v1RRfJ)ڦb{շ Z<^IK[vE-)_"^2&DIUJ~5Zv<*Z_͔j}5SUT~NN4y n|;A @"h2 5oq brx!rA{ 11.1.3 Discussion

11.1.3 Discussion

Quick Quiz 11.4: Wow! Figure [*] contains 69 lines of code, compared to only 42 in Figure [*]. Is this extra complexity really worth it? End Quick Quiz

Use of RCU enables exiting threads to wait until other threads are guaranteed to be done using the exiting threads' __thread variables. This allows the read_count() function to dispense with locking, thereby providing excellent performance and scalability for both the inc_count() and read_count() functions. However, this performance and scalability come at the cost of some increase in code complexity. It is hoped that compiler and library writers employ user-level RCU [Des09] to provide safe cross-thread access to __thread variables, greatly reducing the complexity seen by users of __thread variables.



Paul E. McKenney 2011-12-16
perfbook_html/node284.html0000644000175000017500000000546111672746162015656 0ustar paulmckpaulmck B.3.5 Example Usage

B.3.5 Example Usage

A spinlock named mutex may be used to protect a variable counter as follows:



spin_lock(&mutex);
counter++;
spin_unlock(&mutex);


Quick Quiz B.2: What problems could occur if the variable counter were incremented without the protection of mutex? End Quick Quiz

However, the spin_lock() and spin_unlock() primitives do have performance consequences, as will be seen in Section [*].



Paul E. McKenney 2011-12-16
perfbook_html/node139.html0000644000175000017500000000741111672746162015652 0ustar paulmckpaulmck 10.3.2.1.5 Low-Priority RCU Readers Can Block High-Priority Reclaimers

10.3.2.1.5 Low-Priority RCU Readers Can Block High-Priority Reclaimers

In Realtime RCU [GMTW08] (see Section [*]), SRCU [McK06] (see Section [*], or QRCU [McK07f] (see Section [*], each of which is described in the final installment of this series, a preempted reader will prevent a grace period from completing, even if a high-priority task is blocked waiting for that grace period to complete. Realtime RCU can avoid this problem by substituting call_rcu() for synchronize_rcu() or by using RCU priority boosting [McK07d,GMTW08], which is still in experimental status as of early 2008. It might become necessary to augment SRCU and QRCU with priority boosting, but not before a clear real-world need is demonstrated.



Paul E. McKenney 2011-12-16
perfbook_html/node425.html0000644000175000017500000002052211672746163015647 0ustar paulmckpaulmck E.2 Promela Example: Non-Atomic Increment


E.2 Promela Example: Non-Atomic Increment

Figure: Promela Code for Non-Atomic Increment
\begin{figure}{ \scriptsize
\begin{verbatim}1  ...

Figure [*] demonstrates the textbook race condition resulting from non-atomic increment. Line 1 defines the number of processes to run (we will vary this to see the effect on state space), line 3 defines the counter, and line 4 is used to implement the assertion that appears on lines 29-39.

Lines 6-13 define a process that increments the counter non-atomically. The argument me is the process number, set by the initialization block later in the code. Because simple Promela statements are each assumed atomic, we must break the increment into the two statements on lines 10-11. The assignment on line 12 marks the process's completion. Because the Spin system will fully search the state space, including all possible sequences of states, there is no need for the loop that would be used for conventional testing.

Lines 15-40 are the initialization block, which is executed first. Lines 19-28 actually do the initialization, while lines 29-39 perform the assertion. Both are atomic blocks in order to avoid unnecessarily increasing the state space: because they are not part of the algorithm proper, we loose no verification coverage by making them atomic.

The do-od construct on lines 21-27 implements a Promela loop, which can be thought of as a C for (;;) loop containing a switch statement that allows expressions in case labels. The condition blocks (prefixed by ::) are scanned non-deterministically, though in this case only one of the conditions can possibly hold at a given time. The first block of the do-od from lines 22-25 initializes the i-th incrementer's progress cell, runs the i-th incrementer's process, and then increments the variable i. The second block of the do-od on line 26 exits the loop once these processes have been started.

The atomic block on lines 29-39 also contains a similar do-od loop that sums up the progress counters. The assert() statement on line 38 verifies that if all processes have been completed, then all counts have been correctly recorded.

You can build and run this program as follows:



spin -a increment.spin		# Translate the model to C
cc -DSAFETY -o pan pan.c	# Compile the model
./pan				# Run the model


Figure: Non-Atomic Increment spin Output
\begin{figure}{ \scriptsize
\begin{verbatim}pan: assertion violated ((sum<2)\v...
...onflicts: 0 (resolved)2.622 memory usage (Mbyte)\end{verbatim}
}\end{figure}

This will produce output as shown in Figure [*]. The first line tells us that our assertion was violated (as expected given the non-atomic increment!). The second line that a trail file was written describing how the assertion was violated. The ``Warning'' line reiterates that all was not well with our model. The second paragraph describes the type of state-search being carried out, in this case for assertion violations and invalid end states. The third paragraph gives state-size statistics: this small model had only 45 states. The final line shows memory usage.

The trail file may be rendered human-readable as follows:



spin -t -p increment.spin


Figure: Non-Atomic Increment Error Trail
\begin{figure*}{ \scriptsize
\begin{verbatim}Starting :init: with pid 0
1: pr...
... (state 24) <valid end state>
3 processes created\end{verbatim}
}\end{figure*}

This gives the output shown in Figure [*]. As can be seen, the first portion of the init block created both incrementer processes, both of which first fetched the counter, then both incremented and stored it, losing a count. The assertion then triggered, after which the global state is displayed.

Paul E. McKenney 2011-12-16
perfbook_html/img197.png0000644000175000017500000001037711672746052015330 0ustar paulmckpaulmckPNG  IHDRtRNSىHIDATxuPϕ]K 0M H,@ X@(@ .-@ PAȿ$<`? ;FT&`H+Tiu?BJ',xs"DL5~hˁ 2E*t<e^&=Vf-P HXFLe4,2ơxkMyK!fx2al"zO\eYhT@ eCzh4|LeX[\5K OK`0] `;Oyf<_Oh|]<$wRI߻`hD@J^8Z,ZӒ IKXxdbs'c0s.q \r-3߯9o &i,,%6HHHP,Nt`.t9cqJi8>6K"| øDr|0> ۃx4p{o}4Lk3%9ǯn'xYlHoi5[ѣ{\Ldv_v8K_s쭽s ~UvG @4ب/d7WNgRQ9~zG棣z6k7)s˻U6ܪ ?ILS9-UE驚Gr*93$r6${VwV#Ƭ<ƾ{!dH6EsGZľ,o&z%4"Zx4NC/D/D/D/D/34|Uy^4F/KrWmTM]|ﲝ6onXrn5U}8KUp37Ur[C*rʼnox>M$R2h=7U$E\;m159[ж̷.<@pV;pZm?#r<_>Ov.*Mhv\|cݸtESg\=WIFt=!KZ;"?kQ@gjGѴBE՜ VjBQtjW>H5\I\vYw ]C9PJ%n ?Jn $#Px*ڛlIRo3(%QI3RG<. **%۽J9ӰS``9),`1:X  ){YCfeX3 r|Js3v˻EoBϥ3D>e9zs 1Лc`ONҿ{E'kyhZfw]ݭ~j^x_-'3?.G0g&[b{Fr/zn1p{U.Z.rkhVsdVҤn4+d c?K5Gr6K1PJ>Kr3l3~ms%!5s R"t>~mF$lɒgq@9Țu'{M`7KBH97޿ǖ^Kغ6%P=(Et>E%ӥ3}MbrrrU-6 ϐ>}&_2|^o~Tlri44nĺ8V346ǘ? 4\ϰu`n`Gkt9:`N G1'BX5sBqh,9 F? ҤE?Ɯ觙Bjg@hsB4\Hs"آcN9!.I~9 sbD3>9BsN @W99+e_aCyͱ6|f VW~$IG,HߟQM;ls luRssj*Oeiu)R4ң0~s#:kr_}3.ÆD %8%0PhԾ[{UVRh~g߸|^-aCp<ƱpwױD.\&5soڥ>Bݙڜoٞ'́Ƃ;sk#_/&ye,&K_Cu xÑ-%o/-~)nX ɔ[=E!T˒MAɖjJ3G%#%\?i.YtiO$"[B23G l,a9uDS$uE%$+sԸ^Kh2QV9oQ3zs 1Лc7@o9zs 1Лc7@o9zs 1Лc7@o9zs ^H^_c M}ԗw/~#zV[7i+ 9[:4_s~_^\)9Ivۍ~'zIENDB`perfbook_html/node191.html0000644000175000017500000001466611672746162015662 0ustar paulmckpaulmck 14.2.2 If B Follows A, and C Follows B, Why Doesn't C Follow A?


14.2.2 If B Follows A, and C Follows B, Why Doesn't C Follow A?

Memory ordering and memory barriers can be extremely counter-intuitive. For example, consider the functions shown in Figure [*] executing in parallel where variables A, B, and C are initially zero:

Figure: Parallel Hardware is Non-Causal
\begin{figure}{ \centering
\begin{verbatim}1 thread0(void)
2 {
3 A = 1;
4 ...
... continue;
20 smp_mb();
21 assert(A != 0);
22 }\end{verbatim}
}\end{figure}

Intuitively, thread0() assigns to B after it assigns to A, thread1() waits until thread0() has assigned to B before assigning to C, and thread2() waits until thread1() has assigned to C before referencing A. Therefore, again intuitively, the assertion on line 21 cannot possibly fire.

This line of reasoning, intuitively obvious though it may be, is completely and utterly incorrect. Please note that this is not a theoretical assertion: actually running this code on real-world weakly-ordered hardware (a 1.5GHz 16-CPU POWER 5 system) resulted in the assertion firing 16 times out of 10 million runs. Clearly, anyone who produces code with explicit memory barriers should do some extreme testing - although a proof of correctness might be helpful, the strongly counter-intuitive nature of the behavior of memory barriers should in turn strongly limit one's trust in such proofs. The requirement for extreme testing should not be taken lightly, given that a number of dirty hardware-dependent tricks were used to greatly increase the probability of failure in this run.

Quick Quiz 14.1: How on earth could the assertion on line 21 of the code in Figure [*] on page [*] possibly fail? End Quick Quiz

Quick Quiz 14.2: Great... So how do I fix it? End Quick Quiz

So what should you do? Your best strategy, if possible, is to use existing primitives that incorporate any needed memory barriers, so that you can simply ignore the rest of this chapter.

Of course, if you are implementing synchronization primitives, you don't have this luxury. The following discussion of memory ordering and memory barriers is for you.

Paul E. McKenney 2011-12-16
perfbook_html/node108.html0000644000175000017500000000677411672746162015661 0ustar paulmckpaulmck 8.2 Types of Locks


8.2 Types of Locks

There are a surprising number of types of locks, more than this short chapter can possibly do justice to. The following sections discuss exclusive locks (Section [*]), reader-writer locks (Section [*]), and multi-role locks (Section [*]).



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img235.png0000644000175000017500000001345711672746013015320 0ustar paulmckpaulmckPNG  IHDRT!RHPLTEb``^\\MJK# hffvstmkkcaaXUVNKL856C@@744wuv.*+_tRNS@fIDATx] ,hnsT0hШ>H J!tL^,>th3\>]QB:8lw<[xjWJQբ|`/L+Dcl5zk etxSeŞ΀ľj3>0-K덩_̚Os@_w鳟&@);HA؞z:=Snp1ƾE}(rK.$fO0/Ņ蜬$adl( rll)^CJ>| 4^lMXB$uUF~yY˰!–pR4^1^(,ǙؼV7cJ;#8ϐ2jy Hb-fjž,)4R7N>`;ñ1? ˽Y5Ή8E`.8"Lq8ѭj%Qaz7{-ij؊V-Ji.b?ToJ)c9զ.MOī7E#T$4{ݽؤ4YB l0&%/wDap*FFFrzM_$9@,]>[}(VBڜaBjWJUFGBvr\{1ȋYvx׃'X$I*[zs> |ItMKThMY$ʁ\>woxƧwnݠ*⬶XI5Kĥag`^:[8l ;Y&[*Db@-2n%,|(u&ȜxBU :DM3iD nU4(ʡmQr%:+Hh@d7pYj7RYA V4Qt-+3O hZ/p)N{ـJ8'fDex`Қ%ނ# %[vBy}4NuH"2UeB~}wsB-jpWca"VD,G6R`]üO nKjLȩ/ \,?} ^^5$yij5" +Rڃ=TX̮TG]dL6S$izhcEJfq϶_V r [jY58,̖ӢRF7neFQ >XJ NX/TkԪ)82'z>IB>gJ7ZOͫ/f.jVBW=Ȋ{S-fs_BO4;ι[FMq.Ew}=V}T7oFdoГZ#"6`dJd \x$9Pk m#jvrK-g hYg5ŧJ\tQTIwwӒxWNyh:Ҷ gJ _Jqm3t-:PkP A"ŷĶR gd,ۀRwLY^2?T؁`y垂] |W#+QSXbS!_OIsgr%+=F<`^%۵r<F+$&M{9q\xP %p_J+mبdNʺd[%|U ddqϟCJD:{cW?{DRѤ"+٣ulTs I~KhKnhA=ꦟ*IΖO`Hg?gcnq**'Zܝmsa5ŪFǬ7rXGP ='SSH2YRQc[r'A9B ZS8xabo>i?$DN/)@®A]Iq 1dz`\â8C&v14im.>Ubb [=[3nZϳPazŴF9*!z|69zzqG֧yeB) ,6)#4o7cpymBn &F _ StUEF{Xԇ(e ʈٲ Rb<7@Qa?z }~FŹ{5Zr;P 8E3Ҿ(0!F3К(:Y|ŠgqK ks;,q%{f$,fjf˾@b|Kh#S%l!d Au0/DR-a o@ #GsFm*獁), EϳhLo2QD'FS\X I>IȮ  HT Zy9 tqV^v0h7qiѡbppgVuHd~rp>0y#ހ6KJGl3Shd:Qc]KQ2g}/8fKGQ2[c&]âdNo# @ L +'s wY'y7&ONd_$߯5َf5l[^gK&KwSr|e{&|C& Lk lAd910E.zF$<*8o\K;ly1͂cLKm"_I1 vgt8ӀSҝ3 8-+'0GC-_`ORFpbӟdP_1tDp s(Jlg(c t]~yv+.,?IPD<c?YO{EeD 1  R)op\~>;Jf|2\gGɸhkPsFpp]^`7K?ہZ"7>%g_Afҝq%qcp 80x_b|̻ F3Z| $''P99ߧpb%H/S NI3И"^?9 .L:l{Zæ^6-; הd6>;spFӽ!^;7w0"=~oJ{T"1jLD;ATmb^y5zݙak$d<:GZxb- KqٰRx{QҐxnf/>FoIzbzs`v&*~ㆨzN/\[m77Qhl'+hIkM%۪DzM@Kә?Hi=/,QnA_WRCt"ΓJrCy餙 3J #pD RZo9,lE?~~=KS/E5ىŅZko 8JcRo * lzKi޲6'u%}"Wϔ,Z^ZI;Fà ;[J̟ 5$WYke82&-kHOWGteWX-@t u\CR/8k/\SՒb5jorI0R-T94MEK.\XЃ_(|eů4V\#K~s,S?-[J_@F I늰7~QM1hDCK6}wKŇք[8+j:[jdtߩ'q~ W9{)tVpѕ~"%q 2>,((G^c+Eb1^]]ҩvRFߏtL5sef:!H^4ԗbQq(F@ HW4} 9}VCw,EZ)`v5qX;T ԏljj~x,:IhLQ3:R ~Z+ IHFBAID,miDA:<,UHWt>_>y: I^D53 <>,xH[-tz'1Dp$CtIQS9X5跷],)kVOf+)&@spn4 t)MAՙ"i2%Ȁtj}IJ|ӁTI^ ⋓@kĚ/]N[S(Tkƕu )_8$ [?e(Fm)_Hh4(gH3f]Box,4#D #{sP=_*h%Y2*ē)A8[aR0Fܰ!$ '1^5[hHb3 -и99{}i^ uyvBov5(MRQ9 G8F} h |/|roCm{H,Ǡh ^u~=`O'x!ZwJB 1Ip参#| xMZePrj}qA oߐ!t T+zm_%JZ-3u$x |dԣuʗV6HS\%y7Bc䖊ո-?rOj6[6;N/qd?'84>GvG"HFRc#АT.5|Tk-h_sC*Kq@>CʇoA_j-#j ^tJ\C$]o_XVBRpQ-+ҼO9ߢ6lc ~ÍjӼ={u -qHQ 3i^s(ӧ-j|?JQ57MߚBc G$ꆁw֤}2WϼIENDB`perfbook_html/node279.html0000644000175000017500000000712211672746162015656 0ustar paulmckpaulmck B.3 Locking


B.3 Locking

The locking API is shown in Figure [*], each API element being described in the following sections.

Figure: Locking API
\begin{figure}{ \scriptsize
\begin{verbatim}void spin_lock_init(spinlock_t *sp...
...spinlock_t *sp);
void spin_unlock(spinlock_t *sp);\end{verbatim}
}\end{figure}



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node144.html0000644000175000017500000001054711672746162015652 0ustar paulmckpaulmck 10.3.2.4 RCU is a Poor Man's Garbage Collector


10.3.2.4 RCU is a Poor Man's Garbage Collector

A not-uncommon exclamation made by people first learning about RCU is "RCU is sort of like a garbage collector!". This exclamation has a large grain of truth, but it can also be misleading.

Perhaps the best way to think of the relationship between RCU and automatic garbage collectors (GCs) is that RCU resembles a GC in that the timing of collection is automatically determined, but that RCU differs from a GC in that: (1) the programmer must manually indicate when a given data structure is eligible to be collected, and (2) the programmer must manually mark the RCU read-side critical sections where references might legitimately be held.

Despite these differences, the resemblance does go quite deep, and has appeared in at least one theoretical analysis of RCU. Furthermore, the first RCU-like mechanism I am aware of used a garbage collector to handle the grace periods. Nevertheless, a better way of thinking of RCU is described in the following section.

Paul E. McKenney 2011-12-16
perfbook_html/node301.html0000644000175000017500000000645711672746163015653 0ustar paulmckpaulmck C.3.1 Store Buffers


C.3.1 Store Buffers

One way to prevent this unnecessary stalling of writes is to add ``store buffers'' between each CPU and its cache, as shown in Figure [*]. With the addition of these store buffers, CPU 0 can simply record its write in its store buffer and continue executing. When the cache line does finally make its way from CPU 1 to CPU 0, the data will be moved from the store buffer to the cache line.

Figure: Caches With Store Buffers
\resizebox{3in}{!}{\includegraphics{appendix/whymb/cacheSB}}

However, there are complications that must be addressed, which are covered in the next two sections.



Paul E. McKenney 2011-12-16
perfbook_html/node152.html0000644000175000017500000000717611672746162015655 0ustar paulmckpaulmck 10.3.3.3 Where Can RCU's APIs Be Used?


10.3.3.3 Where Can RCU's APIs Be Used?

Figure: RCU API Usage Constraints
\resizebox{3in}{!}{\includegraphics{defer/RCUenvAPI}}

Figure [*] shows which APIs may be used in which in-kernel environments. The RCU read-side primitives may be used in any environment, including NMI, the RCU mutation and asynchronous grace-period primitives may be used in any environment other than NMI, and, finally, the RCU synchronous grace-period primitives may be used only in process context. The RCU list-traversal primitives include list_for_each_entry_rcu(), hlist_for_each_entry_rcu(), etc. Similarly, the RCU list-mutation primitives include list_add_rcu(), hlist_del_rcu(), etc.

Note that primitives from other families of RCU may be substituted, for example, srcu_read_lock() may be used in any context in which rcu_read_lock() may be used.



Paul E. McKenney 2011-12-16
perfbook_html/img182.png0000644000175000017500000002076711672746124015326 0ustar paulmckpaulmckPNG  IHDR]8>/tRNSىH IDATx흽oH3h\4X^F#\B)pn:,;qsؗXP 'Hwzwp&4t$R")R>ѦHST}%ɏMgD9J"9Wӏ[o'ۀmHÜ?10'ZC b.ƥ4Na`+\PpAO3  ~!_3Buqf.&fT^Rka&5`g %ԢZkх>0R&?oQY=TVJJTyl&ѨyƂ-U+k``k\< b):k60<$3RD|vy+$ho=0DLnxi߫ӇJ ˍÍ ŭ>Fz0fk~`àV&]}Pn>(qDMWE{o`ړH.C\_~w+!c* \nfd`W)V2 dۮ+g%Mce[;J1h€j WRFN'{feg?-E[ks0czLB~AQBn8C8q[Wҫ&D+Mܤuq1UZ0[Rr{OUD O A~vhH̛J=ǜxU JgD wqzn 9DJC7(JRn4IUޚZ#;f,+cO WRuS *DG_zR;JqmaRwNiT-ׯâ+_E49Mʡסu#Qiz Ӂj|eGB+)0*e:N٥-.b-Qٸ""|1T&aV~k?ʇ4nR0~w}>C`i??*i0[(CNTFGe.}L4YJwƄ. gLn$g ꃭyCnaz%n: k?֞rIT7 ^{ GR.pZ\'(v5v(NKrw4S2Q;Jǘ"X=5#}9er=aw׶1 .Ȼ]i:.RSqm-b*=,uN1bx)@ GA?_4ګ;+d5%g7nˡW)W6|:-J8y8WJ=b>X\HY%mmhkr|oCndO]s{]\ :2,ctZV NqO !B`SN$ެkB &B}0 Rzz.<Y?soPV廻j_x-.'~SrH4Rq1;&RSa "MLcnLI##GRE SFkͦJ<1rP&FabQ0(cݑK lP< I|Ej*=O-nUiѮ׻P{WTCF+ΠA?&R' i3.Lt~h.R1Pm;faf`~jFmZ~5 1AzvP8 ~sƟ,k>|#*n)D jiITNoeE5Tf+$$:wW5_+/KaD̮$c0(k(Od 0_ǜO[] NeӔJ9@֘(%|4L5LT>eoKF=M]K5@Hc1Apl[i0Ǐu5s03Wu&E«;pD0Zẍ́$왠L[SҿFhAhQm;_+Ju拝Or5l NF%w=0V^fzE>Q|؊ 8*B ۺ" L6:6A]9d"L]qq{ LiBc2yMm!${*S f[ؙ('2QfLڕD3̍\:V ̘ 5Udzd`Q?0).iBϮ't->q[Ԥ0c"(V^;ñH{۔-u%&n!u4SgUʢ*ysEɌU t : atu.9xֲSXj׮W 5LŝiҮ5  pl _h`r͂dFJy Ҫ7\9n\; +pO<)w 5CA˲ P7UG1(Tdu]V(}N5NEQfiµEI3H[_[iDv.zQ̈iԟJ p;͹tJF JO9V;wċ~ځ23f }]Q](3c&̘23fԮLeW&U1qA=ג3c2u8u}>!Ů 3Xaok8gd=z^+d<|ڌum?fZ!3$Q;#{br{Ns˶fmufZ!p%! l ߊ,4&jxnD%H6J7%qfh-e똪VжŃ`jD060dM #bWl;I]l[^lqCOq5N,PruB I>EfEl:M7W}jQ0U\ꍚea',oHm'u$M( d ! ,y$eZ5b 7$Bxѿs8]EɌO/%_u§*WV?"q;sӴ'oo~ܷ*M-׮r~5c(~U?]e͸?^܂&%v[K$ bV/ m'A.o`?%!'Fq6cCRSCvǯ?vG+? cʀow: Gvii*!:Y[ `)Ǡhz}_k)]ϸ$(.cuXlC~uuTTPq:x5wE㫄g5⬶)-pzZۏxDe,_#1?4\a46`oJ|ްXgU GӍ$LǝAL͘, 5l.=pE@d+-5Pmh&J6.V*J_Ə@we_x󳼣.4é: ^wX'WS8oz# `jôُU7Շ3_{y1szx^.YQ?{Tm3 DvF8ծj#pXF肨ɿ1:N.93/IoB8L;I0 Xd`ķVq>x )UMft2+Y*':T4CcuĴ$;'un ӓf}tbE"ϸvOD[g!>] MO N:98)ZcXC(HBW^8W1xZ%rHk$5@@TF׫vXOO> c5_jY!UhU{JcYnR5gPfeWmȈH_oҺ"gFXvmP^-ާW![ǍNh. >$qP}:y8tS|*'hya[3H"u?>V(,Q:>cɳF[~T|*G$Gd_v(v5(v2WT"^]3- ϋƎ"N1V//f,XA㙽-?7ڎ%Y:`ʱ94{GHH/5j-n΍AbʝR֌KmWvo>dˮhJn͚8B!n6zƫFI8;`ZKܼ{X=W"%>a$׮g \Cձf+w~O2k\7b/8:$F_{j(a[|-ZvP0+׮n/3%Ůbwړ0+eq,M`: PQA/}>/Wش߱Fj |<kN<w5.4[OѴn:`ʮۑs4\5Ư?0D0gE)m:wȳ`ez6~/f\fiQC&2Xk'O[=4ק<,nYVA kXX e͸GwmnoۡJRS~2J׮KIDeX=^|Ó]*EQ J /r%dpSԌ{KS֌%ۣuS|*׮zh_JGlwkWY353'Ԧ6=26N<4x֯w$挳)jc@"gnq8 Z[[4lv6y4~0#xtf))6){H`ӴYfy 5Kƹ G/Ju.i'biZ[aIp8nhE>󓿻pt" guMipluoi&°*3>+$"Ο/ @jl5Tsj -YYM}ê.D(c+QOmx_HW[,bˮG yQS.LP1F JEh<.~gXeUDZՖo 5MaoKb9KC l*ΛLO AG{ר ŏ7W8fL$o 5- !fP/""..yvaG.#ʭ:P?IDAT$/:G6q׻~Roheۏ:C_+V t(]O.~?tLuҋVVe +M"N+4ׂW\:5(ЅЯ6F'oFfX[V;jF3mҾ*KӋgmt, T w<6ˬ!:JKGuJĮ[ݧTۏu_cb)ky r4Ga$ vѨ_X`hAx7yhnG8sdRߟBx_UgKIF*x (^~ף,UIENDB`perfbook_html/node245.html0000644000175000017500000001110511672746162015643 0ustar paulmckpaulmck 15.1 Rusty Scale for API Design


15.1 Rusty Scale for API Design

  1. It is impossible to get wrong. dwim()
  2. The compiler or linker won't let you get it wrong.
  3. The compiler or linker will warn you if you get it wrong.
  4. The simplest use is the correct one.
  5. The name tells you how to use it.
  6. Do it right or it will always break at runtime.
  7. Follow common convention and you will get it right. malloc()
  8. Read the documentation and you will get it right.
  9. Read the implementation and you will get it right.
  10. Read the right mailing-list archive and you will get it right.
  11. Read the right mailing-list archive and you will get it wrong.
  12. Read the implementation and you will get it wrong. The non-CONFIG_PREEMPT implementation of rcu_read_lock().
  13. Read the documentation and you will get it wrong. DEC Alpha wmb instruction.
  14. Follow common convention and you will get it wrong. printf() (failing to check for error return).
  15. Do it right and it will break at runtime.
  16. The name tells you how not to use it.
  17. The obvious use is wrong. smp_mb().
  18. The compiler or linker will warn you if you get it right.
  19. The compiler or linker won't let you get it right.
  20. It is impossible to get right. gets().

Paul E. McKenney 2011-12-16
perfbook_html/img268.png0000644000175000017500000000540511672746103015320 0ustar paulmckpaulmckPNG  IHDR+T~ѰBPLTEMJK# b``mkka__XUV856KHHC@@wuv.*+TttRNS@f qIDATx(*9dN*-ۮr*b O9CT5U豋|iuv@2 va[*ǻ)7NlUn:w|>2m+GrS\-ܬ2j!,BǶ9a=ɻ:n@+ r䎽.ǫ#:j/yzfv˂RۋqY~OQk3y?W~W^aAɛ~CW^ ?iRNM8y~jYD7>jm=؇ho0FJFc$NM^tt62' U҆z.آ28пQyci77,22= }4mF[:(531Pn}TW,rtQ7qއlh1+^C*׃g9몶㛩cW}GRnAYycmDA-3+__}Z PI& o_tSRrA\.Z3^3p%ͫ] 5\9oxp%HL*m>hDh^lj=;GuKO$=|)yWQ֕?;tFIJGd'*y 7'>㫱G^z 3%\,,X˽V}SlCBxJTTì=4'9q)M޸1JnYjo;}ۆP-TzM' zD:c^ ˭ lCO\'2|,O/Mʵ( HBGk/u`ox 򹏼9bIs͟!YE%O 9d) 渤.9вЖ#35dαn®TX[:}vf'Z, QqAK)LP,N/jT; OpN &.WE E Sʷ>PPj”ڶ嵻+By5j:>X5CO`* Xw ($?18l>j-AFj(r_ 5V\˺3Aj[DMGǁ%Sx ?}=Xh,M: òwgCY{]>/~6˂\O+IENDB`perfbook_html/node215.html0000644000175000017500000000720111672746162015642 0ustar paulmckpaulmck 14.2.10.1 Explicit Memory Barriers


14.2.10.1 Explicit Memory Barriers

Memory barriers come in four basic varieties:

  1. Write (or store) memory barriers,
  2. Data dependency barriers,
  3. Read (or load) memory barriers, and
  4. General memory barriers.

Each variety is described below.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img105.png0000644000175000017500000001437311672746051015314 0ustar paulmckpaulmckPNG  IHDRO\abQPLTEb``^\\\ZZMJK# hffommmkkcaaa__XUV856iffKHHC@@744wuv.*+wWtRNS@fXIDATx]*sXb5v.ƕdNۥ#0Wbjy  ݱjܵWt]+8,@gʷCHhQCF4B<+)J;elmԝZ!XVGjt:b;Pm'vi="++^5;o_z;ԬDj{z00d]RW $ujnE\CiX} |Yc"ck|dhc֌4%XߙA~4dѝXzJ-=ωWd{ k`]QAucc]8}>QtYn PG0 ge;@2-}y@W؉$s7; JG*U OV rוԕ֕|w>PR`1>bҴH;B 좠Xg +Vd+eJEs #N Mp]joR.DK>_*UpCLHf]Dǂ< eh=3J@>0JQye2eYe9;ʫKgۇ%F<_`Di(Ng].O#O'h7fQՌs}3ÙJhf*=']{D>8 cd|<ڕI$RASJW7~DmBM]]]5ϑS_1(60`.Atny-Rԍw`ۢ0-ϊ}[:C<~ X~\Mn4Ci9 ӿ :ꌒڴ1ݴ֦aj-Lpeg%tw!'Zow؉LЯC Nqà#rdR{SdƭvR%]kr_4Z)봜ROc^}k ;ض!N*sWU?I [Jm)*SIHĭ!jӤ,YQ?4Ku,Xs mR+(":ڽ D5}|,\o:C|bYlM' C8ŤimXvO@=dql_a(7a]5|Ch7MH2bívO U,ǯRj:VPʭb5Uոjf9e_6z[~4($gguB%a1f7h>AU;;]Cn_(50ZfdP<*L(k_5@=[ݬ~ϓ\ (d&'1وrztf Gvh}Ǥ)8b >z1*i *^\^S)DTI5_G0i[Zt0mDJvDR=Ll3:/G^#1ՇRA~I0wP_hKٔt%!f/asȡ̥OH(R-GȾ V`,%/pk}mkPV;i"pDgEL ٥}8tvs/"42|G{v;b)sL=aMJwQ-8f[x3w(j(q97"xCUWVoS~{桓X&/%qIڞ1NF[z%sE{[5Y6 /J0fŴ$"A,ZP@UxF_mKr/[WG H%BPIR MbLS tc#<TA, غs~%G6TCTތӟHvsxD8iL˟4aGQdL~pb֫񵘖PpY'.<OhInjQV2Q$:jJM⪂pb_e VtT8I☇ιsYɄ3):c71E.K'20󥊹zX]CE_qYwaW+ޢPHG2tsv.PUz8;WZˊL8# E !it59`\D Ű EQ.  DBl=|`m*,lI to^1Y5jSoPE7p/\R33 zRt ".=J":_ k:e<:2QZ}4nr-r7܊FȽȬZzAK).DO`{PE8)?n Hjq1mѸLX o *y:O克@Q_]m#[ñȰ>{1/@vC3*n jaҴƟU)k[3攌 IitXUZ NW8` 8Y"N!soVQj"i +ܑyr>ˇP~gw#?CGSqz`^8Қ-ND%{1&fh/nUI/J9YLZZB9!~K }d=>48D/JDc;lN$b[=q<`ߦez*Y.Q~gqBpglIiuZӚCS f!'rES{W$) 7n|>tʇh'?W&ULk:-'ۆ8cJ'>`29n3)L2-'t=q[E0N3o ','eIU2$5=v^i{ Nƈ|dF(_tS!%#zJK[%HR^U"z)tS7O$GNdX̗k㟂&CpLnOC߬" Dټ͝*Uœŧ뤎|{>y参&CpBq"'t0 .YGV…ŧxeRGX'o=2"CaGGqSB09'#l=#?aDԔďg\9<MG2|5^MR]1gIdDP (Yb1?B!,t-'i_{74 GS eد[GT>+=p$,9ڙzS|G7^ba@tuSlk׭=c0ӢxqAEYLCVðRNGTn(&!_'hi 9 ^q9?S=C>:\\\_7"IFC;xNGS= r=~;ÿ \(ùz|[Iz|[ǫwǍc VUaJmO!r&Hǚ-^4>'ANʂ7n8r=hL{ xFܞq?_\DIENDB`perfbook_html/node32.html0000644000175000017500000000560511672746161015564 0ustar paulmckpaulmck 4.2 Overheads


4.2 Overheads

This section presents actual overheads of the obstacles to performance listed out in the previous section. However, it is first necessary to get a rough view of hardware system architecture, which is the subject of the next section.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img190.png0000644000175000017500000000524311672746051015314 0ustar paulmckpaulmckPNG  IHDR[H#EPLTEURSMJK# b``vstmkkXUV856_\\KHHC@@wuv.*+tRNS@f IDATx\(e,8̮Q~@Qt餾L"%ũ^!jiQ6 B .T'J7V eIRTIZ!]NV.nܞ.*S%NyG%FxBPSox2\1 %̰yw#?I983Js.b-Z,hb Qkgqfd+fkիc/'a'P ^#`t} 2H|n$ ˑ`ѱ %q/:$i m{ {тH5:A;0wEOU3"N|&|.iL~cKܭCuXh{=ԕ1b A]{I#Rz4E*syOe*jMs1JfbpY.85QฏE蓥@ RAF!JILW=_P9W 6аn7YY glZ\;q_9Ӥ n6~ZImxiSELrJl;{n$v4Qu͙r0rp92"ױbmeP Ƙ@ۏrT@e-[pTޠ@8Nu_rvK-44w44~ UU{{y!?qqÊ* ")b6#D1"'{fqBO FQnODOd`lqrh1!): 9ȁP~6έ&sDi P4/!ciL|bgǤ<"GGW3[iB@;x)OC^Y<_IV؆6y;? 6#ׅZ&:O< KlފoYw./%z "pI| S[bv6(iJ3rOjdg!"xm 홟HHǏ\eLp30 B= ZƄU@r98qŅ4dVn8;EceLX(+0ϓCZN fw 10.2.1.1 Simple Counting


10.2.1.1 Simple Counting

Simple counting, with neither atomic operations nor memory barriers, can be used when the reference-counter acquisition and release are both protected by the same lock. In this case, it should be clear that the reference count itself may be manipulated non-atomically, because the lock provides any necessary exclusion, memory barriers, atomic instructions, and disabling of compiler optimizations. This is the method of choice when the lock is required to protect other operations in addition to the reference count, but where a reference to the object must be held after the lock is released. Figure [*] shows a simple API that might be used to implement simple non-atomic reference counting - although simple reference counting is almost always open-coded instead.

Figure: Simple Reference-Count API
\begin{figure}{ \scriptsize
\begin{verbatim}1 struct sref {
2 int refcount;
...
...ase(sref);
23 return 1;
24 }
25 return 0;
26 }\end{verbatim}
}\end{figure}



Paul E. McKenney 2011-12-16
perfbook_html/node88.html0000644000175000017500000001330411672746162015573 0ustar paulmckpaulmck 7.3.4 Data Ownership


7.3.4 Data Ownership

Data ownership partitions a given data structure over the threads or CPUs, so that each thread/CPU accesses its subset of the data structure without any synchronization overhead whatsoever. However, if one thread wishes to access some other thread's data, the first thread is unable to do so directly. Instead, the first thread must communicate with the second thread, so that the second thread performs the operation on behalf of the first, or, alternatively, migrates the data to the first thread.

Data ownership might seem arcane, but it is used very frequently:

  1. Any variables accessible by only one CPU or thread (such as auto variables in C and C++) are owned by that CPU or process.
  2. An instance of a user interface owns the corresponding user's context. It is very common for applications interacting with parallel database engines to be written as if they were entirely sequential programs. Such applications own the user interface and his current action. Explicit parallelism is thus confined to the database engine itself.
  3. Parametric simulations are often trivially parallelized by granting each thread ownership of a particular region of the parameter space.

If there is significant sharing, communication between the threads or CPUs can result in significant complexity and overhead. Furthermore, if the most-heavily used data happens to be that owned by a single CPU, that CPU will be a ``hot spot'', sometimes with results resembling that shown in Figure [*]. However, in situations where no sharing is required, data ownership achieves ideal performance, and with code that can be as simple as the sequential-program case shown in Figure [*]. Such situations are often referred to as ``embarrassingly parallel'', and, in the best case, resemble the situation previously shown in Figure [*].

Another important instance of data ownership occurs when the data is read-only, in which case, all threads can ``own'' it via replication.

Paul E. McKenney 2011-12-16
perfbook_html/img84.png0000644000175000017500000000050311672746155015235 0ustar paulmckpaulmckPNG  IHDR$ +0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(c` &+#.P pF.~0 *T6@42p00pY&00``g3 X8,~Y L `@nace. } eU) 14)>`hc]$T00<R~3,x7@K,V$|mIENDB`perfbook_html/img146.png0000644000175000017500000001321711672746001015310 0ustar paulmckpaulmckPNG  IHDR<<99PLTEb``MJK# hffmkkXUV856KHHC@@wuv.*+ĪtRNS@fIDATx]*Ex2bV;Xy,B4O5OA QPz UWwB6f :-ƥoLk)+5Bn zAT;i:~ηhD?XmXq Xf:޾%Sb%nrM& IG|$GrϏ{ݑt@=ծijH椐e!ߘVoJZq>vaZu%d-څW4WVu;q_wqN8y/|Ͻv~,&S RgoR {BD>fS--XJ[F^[-ms_msf,: ;ݤd +huHOR4%ݕZ@9)2#UUĪ˜kVc` !JCKsQ7+Ge[htH־Ƶ~';`0O{vAoZC~g-;e͸A^4 ҷyP,2o Pۭ,]fW1[BFǪWDZA{>%MXeќwkс^[kx? /$KCjYl|+zVS97ŀmJˠ2NG\Aֲx=+ #j.Ho@[4q8&NղD(g4}??+޾+ uH\ɖ$I 4BC+rkwC9OCœ䂥rd]&ZJd5j0P /RwͮhU⤍gP6(ݠtTfOMtPN,,H0JOrWA$S^.(mP%(w}#W~(|NYJzM0^r.;dן.~q ѶPHn"*\w(~v T`S\m5A>F ("fUT9{n,z ѮgDǮ\v^SaVwMjρg;[ա~)-"NXh(*9 ֶ@)2W{68ti [!kC'ͪ{}O~ PC'L%iQ]~(rW-iXT^)Ѝ<|T,L-Do&zKq~ޠֶǝ /e/˿)Y{ooyK6ҵޕhi%{.P>1ja?z LT`*cZt[RAX v0Q8- 1Sӯ̆0r{ȿcGiȰD(~AYO{gwt}E)Ss p[R۶XrVKV*k ^UIaw^l| ǩ@߉΄pQN">ACxR~rngiS4/_cNwX1 7/2Ӧh szTdЦ*t' # * oRq0h_#8+M Q|n,6f" @C8Av,i`.e1H 0$Y3N(T,<06ҬWGC!ei"ԫȜU\[ur.ah*4#w1;j֫bSxPlfVZʼn CB:ĩIA$Y{s:<9>ܑs 8sjŜN&bN GƉqJ,١BdVA F^F 1ܛml# ..i 3 1EVx%˅FbN$gSin.!wͦ;  Nwwֹ8sY#+~КkrYJ93N҅ψ U[ra(Xx>}l:)H1KaNބ#N#åN A_׆;'t)w۳ӛ{f9Dk47Ng@U5n F9/!ׄD\nQ {)e9Rh7}dfp0=)nwk{P#j*y|m8H7K='& 'ҥtptZ!FWd/,TPY$8Qʸ's .,$1NVgu7xST*kO}h͒ 8ѩ|hG@߁| 'EY]c 8 0޵rOޝ]=΅ m8yS a2 =Ͷ2<*z~ =B/*QE '*9zί4JQMVcl Ԡ9F'8A64G RaTugY[EP2 YQ[% $Z%ƪJVC$R-T.F1*VQ+%i>#1,U4VHM%8pGa\.y$2|Vge',(HXQX >=I~@`Ȯw;-}BS)vur&eSg'<D!HJ`!OcdU^Jq,ZBx(r[t3ʃ-.v=²b_NI2VKVOMf4hDj-?ZG۱ϝt'-o/2%}8!NxG o^ )҂&m1B]|oɚl"9x .&lEmki›vt"]H[n@Û,؟,_ISa>q8S5`K|(~E8fq)ɚLiBM8]sq䱰S?c8`&KgzGH#N}=9 l+R&1;C@X˰5=fB` #I(xfsR-zc> 9Yo ɜ¹LŬ\ݟgf _#me%s#\zqM]{R"hđңX3wMz|h0DZѤ_Gxs4W~4 <){$U.Sbls9q9vN)Vߔ{~N}59gGp)S7s[>JlsTfܠt d=4"9#3??>X3g& fE]P E\pTha'e4id5UG!Jw},3 uC1X_G5SKF/Aɖ@&#۾rҝmiX=S'V=oEN֓LѤ?zE&]MzaM:aokg?hG/c)W4DzS^…oW|#O)ϱ^K2r]ܦp'83pa8Kxqi8 Nq0Þq!)ӌ'MO3{/Jg{3v9 ^?g ?>0.ϹspR \9q\'D:m?q^/OǩA[1YʸUaw[IENDB`perfbook_html/img36.png0000644000175000017500000000517711672746015015241 0ustar paulmckpaulmckPNG  IHDRw3PLTEMJK# b``mkkXUV856C@@A>>wuv.*+etRNS@f IDATx]* %g}Y@inx{"CkUؚl(7&ѫ3CLZ;uTu7}mazF,(v:>S4zaΚ54&ohk=?t&oKG3S 0&%Ĵ"-6;/{Rh_idrl2{{{rZ<^_V,0 tEsSxLWV:xy|>ѕh}^8o2_r|-TuGG B4\fAkB.d3cE=xx_]{ۡ6cPѬN( R*禄vg@R4LX=?|= tգl"!?&a柣=7L>/:wK5#â',B&S܋7{=M ؈"1 Π#2#x-DHH"4Mi|ٛĶ$RxD̗S!$![;1?"(<>-i^JO[9"G2g"&&(hƻyWlujQ[}y1}]Vi}>pkG l5ݝtJ#wL4&A[jf76/q?%z8C6d`獁߇^)ٮoG2Km- e?òiE?iM4JyK1;g~BS^tS4Vuq4Y8r>zT 7s+vj= Rq-绁v! :s!+r*Xu&P),Lc&M;z3[4՚rde^U_vN0ΝQ|Vdz$}'mjgn6.{nƞ|0kί Z^_Y5SSĿ@dL1BmvE9:8|gA7r|v&Ց=Isddq;`/#f:{Hsg{];Kb0 b`~*VFKQBc @#Xf `HFFRx/ⷳ ːF$pQG(v)|.@5HiB*'2uRq<]s|Nr&Z[;s 񱹚.,#R%1]?vK٬kXEʩH&m*l6Uׁr`3[:S[F]=j#w4ގtuB|ÞKZ1MM&m'J0ׁ:ЪdLN%x=wB}S2 NgBk/M'\`8} ];-8?K*|pp=kl+xZ l I{Tm^ LK?~AKv20>C&lʍq GOpjף_n\ 9=+DLB֭_恍yth<hט& vBӤV|G.Z ZOo\;hJZg C' AJXB$*#>p=XC rA/(1z_c$Z@K̀ C6C B 82ܯ/"y(iN&?QVG>I\@߼IENDB`perfbook_html/img116.png0000644000175000017500000001724211672746051015314 0ustar paulmckpaulmckPNG  IHDRI`vKNPLTEb``TRRMJK# hffvstmkkXUV856KHHC@@wuv.*+|zz(tRNS@fIDATx] ,a]@gF,m},NCz$k랉d}Z?k0LX}hW{Z5gPJ=St[Up d.c6@$>VmD;~C&s0ᖷF}T5g5}ff<QR}O0+s@)45G"`f"&}\nM"ǿ|Vi޽:DH=˳^'E:/Y,3|vrЙWl mnYlO M*m-t×iZMX .U紧ҊzX,rk \D;ڋiT/2z+6ieG*`;0d,΋|,5 ^܋` _12V$bmDɒ 7~c$ 't՞8uwrfEÂ\v[3ܳkg'n *6}.|r|Wg_x> =??i<Ule<h^!tvw ߯tW6RNԴhM —z cOOOo> kϹ1<9"ãf:j4!EQ$ I`z\A׽A[eݝMgyYfr{atMy,seFfɄuIrh޵6P_W+|'Pw#H4碓-e l]lN5Nwq7Z?Qzx0D C楝3vzHxyڰ=qƘR7 BXsēܞo~9g^H{'LWuГ7*;A1ư hm)k[HK8krVö^Axoϗ^~+:a}EFj}dξ!}8 /<2$4;\i0\^]~v}\-WzVMNQ:ZboTaAme^O|0*iS,A[[(#\Rwveq Iw=XF+`x&U(KbFIl"U 74"0^ ˰~sx.CW˓8pvV[= GOOĆ;ū^X4iy_7`&dkS;Yefya?~Nh6JE&h=ڏș:)㥖KM'񹷋/N7n:*˓ xh~ ;,0H:~`:O!1ՠK&BH!O'InS=(Ƿ7sEk )bxf &ߘG:ykS|9WYՓbW3HT+xf~}^- 0܋WUdrLKQ *­AۇAd6--aDz s0/x,eyDoFFZIM5W%eZuVB[Q Sdvq64`; _c N6(~j/fgu qʬ#g t$~)u]OauGK y:i򔟩k* !a_[tۯC+6U*C)еEW TEkh};\Q!f)@!ܔ/)%o0zܢM:L;R  C;^Y2|ROz~1`^L=I8 {k7)ި=O\;Lj/2G0<߯Ib W%7:/Kp}(x \&K QZB^]AL% ƩU)%Ŀ%&>>?>'7v~+*ಆ rS~ƥG |6YDx.RxZI۽eHlQHjx)];TTEpH{qu ɸJ\{T7T+Z৐cUCZR+]7fej)sƞn9$x:mU *SVLMat^1Q\h=ԜF6)sNִ5oəw6uq9>t񵑂]W ގhԽtV?LRb(LȌ~2fIvbKhB%ZL=IFQDLx|{\/^I Isy@<1<ЅP zqt*>Ձ%1ZFhzʞJ>eyR@bF'}X)mI0^u!Jf~vVZ(,_p\?io`@D5<jB_ruD^'}l+WR7Ǯ]ɂb)z?Er }*oeSXrkS|:0:$:ޅcC=$Օ4}Û2 bFۣ)h/eS$Ds ip%]T`$uT,>@ǖ|qM4y>X4iP<(r&YkXZ]N !~pP=uO2sh6ևE }P׃:"A_^2e( 0¥[/$+B jPp%уGO0?Ya5kEC)9hirhMgNE30?Y@t*/ _.4z xz84O>TMI|o"2a^WBd0;*QqԄ<(J2dB:$mJI`Zyy}P$YLB6VA=EIUg=PϏB]X@{9WxQ?y閌h :?]%XÅ `q3Sl*( aKFMO6T9+Pec%"/KV! fE?)ӳ8ul4(f":e8]ށ{$ӽáCߴS51jy^}96$͉c%97 >P{%7SFWh;'B;?R}⨜Ѣٰ}+ I-6rrԦes;E3S}`lN $Ϝz]huySYn%^g$6vLGw?MD{q<nk ? p[+C2\tcjiox2]%'_a,x`:\'gM~:"+ZtLz@j-ܧꉠ-`B/ۇvЎrV5u29_`F?jlIͭ臨7o4aU0gcO{[h zOh%ȴrcJ'pіFW0BD|-jL+nk:XwnIsBs̬ ^ZN~VJCLrqD+?[lw\)cgsʈ 9fTa3j qVgxђw2mɚX)#@@ YIPskz[0ߛ*/4gj>d kzf1X UuWX5}1lAtG[KaikX]0ym]`"585Be^</gd=!<\cYPP8k6XZꍌ$DN/V5=Đ]UOnz6JAUM-)@!.om[0'7 ( P@A4-I[~d7d Ι(>_PHOJm1Ht{RO.WI;cCv4O $M-z6$J_۬CJˆtIa>DWQ/A&ޫ_͐O!ß,x?YPP7m!X^=@ F{SZ(ˋ YPXJyE ߉  1IY˹R| n\5dkVUێd0= *`N[SݨE$d9jawl-CB˕Cz oOsʔnF >l K$s-!ZQp!ۆZQz0 `NXN56^KYR(7zx%MHTV/`֒OŸ,(#2fLT㫌xp!M9E)!6R/Iq5+'q-a2-CJ8 .wLDՌʒS/ӀT.iƟT>QUpG=r%)NWĺ,s/_^/$5+'suoN59W-,HĺAL×PY2^eʽ:.F!]^8yT֮Oe4S}>nkX"tc>` y'}@ ZF{!6}ngx&1%x'Pe=e߇g|v_j=&ZؚDQ|D*J<I*H,TŋeCq,(((m/`''з/"@r9`;jo>LIċPƟt^\``[ċ?^t'Q3mgFVpXo>Jv ?m_!an^Ns:1β(JC}Uɒ -I=xDeQw'1Z >D"t,\'K2$^/0?C/9bQ?P={Q@/D}}T>EŶ9aXZ)PÓ et8S(5d~p~cߴ|71˟n0P7r9nϣlݖwtNCTҹ~Bʈd?j!XN KEL,,Ӓ[Rc[ ½1g&f }2`Lu5 0ՠFW ?GɞSyF!b\! Z\Y1,~K$C̟J=Q)nC2ţ&P Ff!%Ɵb%Ģ ~w\J˥?`|grFFOTېƟLhԍ O#3L[kEW\D,!ehA.1.׃\±~i6|d7$nDI'd@!00c\q2@1O᤯z('1֬{b.Ғb.|a&DAAO N%AYLY5DyLdef/u,F2mƁm!iKVY^Z:Cek   (LDa $F RdQA ^t]-2F@ &>Cı#I-UuOK} R$d*PRRKDdQB1\jMe> LllR> ʰ֐5S, ; ;(,k>\P~c3dLtx̳(2=J䐖ClUx3:eOөcW& "!-!Y.tz^d4ftP$=(S«!-BJgcJ'-$i0VOS6S&)tkΣ!iR-cJO*҂B> ڞ:pLN)$T&'W⢙#G"r۟Tgu[2뢙%Gb{Ts(TȂ7!h7);ܴט2b1T?:onPR00i8K,j·Y+nAV{l>"mi0ğZ(r~ Ȝ3vk-ϩ-C˲[k,$)jPǣ\$h햩쵟ݕ]N|vOrrsV+-wIENDB`perfbook_html/node278.html0000644000175000017500000001013011672746162015646 0ustar paulmckpaulmck B.2.7 Example Usage

B.2.7 Example Usage

Figure [*] 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 arg argument and myarg variable. Each child simply prints its argument and its smp_thread_id() before exiting. Note that the return statement on line 7 terminates the thread, returning a NULL to whoever invokes wait_thread() on this thread.

Figure: Example Child Thread
\begin{figure}{ \scriptsize
\begin{verbatim}1 void *thread_test(void *arg)
2...
...,
6 myarg, smp_thread_id());
7 return NULL;
8 }\end{verbatim}
}\end{figure}

The parent program is shown in Figure [*]. It invokes smp_init() to initialize the threading system on line 6, parse 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. Note that wait_all_threads() discards the threads return values, as in this case they are all NULL, which is not very interesting.

Figure: Example Parent Thread
\begin{figure}{ \scriptsize
\begin{verbatim}1 int main(int argc, char *argv[]...
...threads completed.\n'', nkids);
20 exit(0);
21 }\end{verbatim}
}\end{figure}



Paul E. McKenney 2011-12-16
perfbook_html/img310.png0000644000175000017500000002024311672746026015305 0ustar paulmckpaulmckPNG  IHDROT~?PLTEb``\ZZMJK# hffmkkcaaXUV856C@@wuv.*+OtRNS@f IDATx]}h3@Ѩ1FUr3('nzHi1v9fψUSoܣ_͛ΈR+xB%[6K WhWY rmeцmBE ъZU k芡plw{ZЮB #n}[LؼPzHvu(&} Zvy~u̿ε\U ބCVVS|VBjg0I w]Bs8Ϸ?˻SJ g-Uԕ4k>د_%ꊲ~"Znf}|Q*{Ah|MR~Z%d4Y0XBhF"rY lcMn:&$3дB2tj d3v! =oYVӘnpb[QQd`4"]K~j8Yv_UJ/9>\; wFõR8KXB'hCΚQvfgL[qۻ^%dVV+oSTB> =})eCOܞJB:" #䁆6"A&#R$U(yJեT0UǸxkCra/68,\3PA}ҎqfVͬNjJ?z!oy>Q}KJAdn(FV|"#8WktJ*/]*)^{$5BxZ /ye͍U~ k~ՕsuQ4NIQȓba@"ś quI6A8'\-N:}#(Ч~*"w8`Tid6 cn\髏沞8W' Ry = ~i<[ u˜ZmOP`0m k@mPdhvqMӫ2;r3=)}$}{tВrmm, V|C );A_~k̷gRɄ%5I|QT(4 4̾QC4bXh&&cҒ/ȮbvEU̞m}Լ"(TCf(o mm!,~8 SgQfTe `Zh.5rA Y3Gȡ u/,YAN+j!wPnj5mcr/ЧV^!אʯֵdH^AM]t)YfFw*ۮo$FU*j: MWN9a,C?bJ+%+*+Cs4'HN#%R^jx^ZoVN;,йQLdDSht¡PR@a"ӻVFRǼAEoY!dx9MV̞q-Ut#a9EOo)g黮,fN/EMT8q5S\PѕȢ°1UĵԨb+{AjxWwKTyY:c8e;|z-$**&%XkS[Ԥ͗Ny'yΟSi)Z4,_.=&*ۺ_LG*d +T36 R)zk;Hmd9!+SC턱Gzh~XZ6}! \l%ĵ 1 v#|ۉw-| HIT%W'8(Deu+Û(we`yp\ߘ |Ms=猤2GcQ0aaNgft&ajԿ/gb+z"JXb'0ϴٜ {=YJp&`WVt+ƹ-.lCܧq\9MD跱;e^Fz4LG"9+p0Q[\ڊ&ip +߃ͱ" gxH ~D SWRthv(Qˀr8 ( ӣITI6.F`"H.F UW$ Z\Cx3M:թ|)ѮMCDTH0YbΞM:v;I7vʦtj٠?+)GCBѠmf¤Ruq\)HR!3'6^oNbGކFd@rGm3rC9lAjןbm$ =?rSP|S<^״'xa'W~p%)MY٤舢D 2"/z݈E )wVH>+6ubO壸H'+W|)0@i~a: )hF11Oh_JQ !r1V Qs_ ͛j`hˎFYϽԛ9ϭv> ?fs' ˈeE5 =C(V: r>uO? ŨL/LgUjEOپ?*eB~iQ&KQW rv( 8+5VgNT 8_ SdaAq o"5z4LT~34$9hYl+X̫iJvl6| Z1=W$@/6e=d?b+YNVnr:9z@;φhjIB>|jܗa0Vm% 8`W|C9+2NC˪0UIvZ8TVCCj RpZ_ZO\kzL|M\^3,[H1tL6ӆ~!8Ӂ.Q+g\*u?/X"!n/ ]-&%!8 j[Ѐ"R! ʫ+L]Zl1&|pA UpPKxZO鄠(EIM:!JtPd.jNϏ)]&#'VzslM5v#'w~CN*=uA\AlVV`/5I҄bX&?k+dksgY`7*=ZJ =y%@x(odL*5&NyWHv\$}I22,$%\!G$9l`>0'mdLR{$' CBWHieKP@ql siT,.=AIL§עBC #kh~y^8Ex?!.+|;9Kp" ȟ>v&2?s#3ز*,UR7|8BO lEY&~ BzM9dJk:$<`l&?ޞ꒚֌`6 OP 3 Hڼ0c<ƉLgF?fn:YQ4]3HM撓H)ԌdC„Xw2ʹ}%rW'FLx=n?X}N6ׅLXF~U?S3V'e?ӌKtrO~Q~_G3]y$ ĝ3./B*~gZ;k=nw[~gLbx&9+gk9(5tsk%=8*ja\; Cn&zdk緫FVI= i>CgffA3TORyX̀Tq̗!Ă4@,0Fs 1L0NMRЫ'~fj}2/wg:5Nj%A?Ӊxp¯Ŧ~kYySw֝:SwtS3f NV;gg4h@$ly}Z ATQ4bp#]~gN, }+ sߙFgs$̺nFh1`PE':m%a&GЌL}ܔ8zzjqJX>i\MlȔqmTpD#GrzXqUODa/_6Fϋ`e {zb%iZR ?ޞ "@ׂ1<?x|nNlv[)d0pz5jԞڅ,!Pf#:p5 Y6s*C )dhzS/3dWc |}|ޕ(ygU-%&˩$4. fǜ.3zjYٶҤʐѠb`ْG1[tD. Z6 81>,x/J eEpXI AgQߊDb$Ggk(c_@(6žvRY; EP]H $JwMQ %[ޞdwtS}P[j32>%9f Mm`ޛqq4E-R8%2UM{vt$-to+>z&VBU )|#G}ѭIjߊ32,OnL1)ov\R.WzJ1jOc SxZR;tba0Oo9,dIyҞ(%Έ66&)!7XIMIsMSq"F;ʥL1gS!炂㦤'*Ŗf%f/WN$8L8s1hk#C24gswh{u9?BS񞑑 A/s؃@8$}z)gFFFƛӚy}~tׂvcNwRr$`y=1?ϔL@[7[X?Tgwdz%Gh9u~i0]Q²o'S28o4gw|ZQ=2 xJ8cyۛwEz9ghwJt~_A`L3o h^`fNz3}}J%g68ޅ4y?K"gq.tԞdddddlG;{b!gl0Rϼٻ.~Yơ^Rй;: 7.3.2 Code Locking


7.3.2 Code Locking

Code locking is the simplest locking design, using only global locks.7.6It is especially easy to retrofit an existing program to use code locking in order to run it on a multiprocessor. If the program has only a single shared resource, code locking will even give optimal performance. However, many of the larger and more complex programs require much of the execution to occur in critical sections, which in turn causes code locking to sharply limits their scalability.

Therefore, you should use code locking on programs that spend only a small fraction of their execution time in critical sections or from which only modest scaling is required. In these cases, code locking will provide a relatively simple program that is very similar to its sequential counterpart, as can be seen in Figure [*]. However, not that the simple return of the comparison in hash_search() in Figure [*] has now become three statements due to the need to release the lock before returning.

Figure: Code-Locking Hash Table Search
\begin{figure}{ \scriptsize
\begin{verbatim}1 spinlock_t hash_lock;
2
3 str...
...}
29 spin_unlock(&hash_lock);
30 return 0;
31 }\end{verbatim}
}\end{figure}

However, code locking is particularly prone to ``lock contention'', where multiple CPUs need to acquire the lock concurrently. SMP programmers who have taken care of groups of small children (or of older people who are acting like children) will immediately recognize the danger of having only one of something, as illustrated in Figure [*].

One solution to this problem, named ``data locking'', is described in the next section.

Figure: Lock Contention
\resizebox{3in}{!}{\includegraphics{cartoons/OneFighting}}

Paul E. McKenney 2011-12-16
perfbook_html/img70.png0000644000175000017500000003217111672746145015235 0ustar paulmckpaulmckPNG  IHDR[-WPLTEb``^\\\ZZTRRMJK# b`a}}hffvstmkka__XUV856iffC@@wuv.*+ŹtRNS@f IDATx]rŶT[{Z23`4Dwf}H0?k؂,+6U$eRZR{ڏ.&6j5oDfuz%x;^B9u.Z5Bwѓy܉S}VhE7]`nQ>4k؋lч+ ?^ cMI׾G`ް\9>ӂf L۲?9,Q왾zjzu-\vz3Voʍ͠AViWY˶1f(}>5O p7+G{wOI&Ďeb39[І˄9l6/GM!5 |9}Ty0HA@(}t{Nv4!-%92)Jӕר\5SGlgPO]] WGkFvap윷-VR+,3*:~ȅK'q0o[|Y{69ܾK=J=q~`(D's=ԹM3#RzamzD˅–9Z~vṈu'R>^p;-9*ߍ-%U<^Qڡ'[P؁g3WFDr`ӧVfU-+ȶ tu#p^*xe; Y<пZ϶yg>gsEnPy}>҉EϔI!ØyvKiqWJ?Y0<0w6bwkydÅ[W*B&:>{b:lgrWҌnipj~MJM}Gz_lDݞW^²1=$x`],5u'4Yg;]£VƠQ3MftHيp^7-{ә$|s;/,QH0!5-ۙ+j!+z*i.hpj_;0]f5yHd)j27?M\v1׏;hz)s 2쒣rU:R^VLv@}!hQ bj4n̩0r7Lm^p9{觃_e(S v;=UDF+ko O sV`Rn{CX\vwz)Jx[r͊"G>ڢk%?,# CcA\Dx:PzSt&8t`ӕd4.qМy88G'l@[JV?(2ϴdptR x_1 `Ư #cxYb!j(a ܮWݗR:D¬οa uEpM:t^.Nh68A_G`ܳ6="~I^ۻkw=kL\dm37rT԰ ^%:=n NY;E 4u%L ?t~Mb/5#QaZA:w)U)Nۍb)v$L VJƾ(x}5ZMr{v} cM%sF˿6q\il}7;*d+%'?̼uq$7Ƽ$0*[l0+#JoY~O6>X/)+k'O~PuM=m-Mtbn~:1wWdwS7IZRK+TJ@5g+[>~.f۷"SUC=}^u%5$jBn.E q1q+ْ K]wBfB&@Gd9gc<b w*#9@%%a;< ݨ.17˅Km*| |U*\.vA?<q?t~؂TPw&[]]$a)xn4o{9U8.p0*\ysl!S숸 3JUe-5`(hSL6~xC 4 cZkViEK}4띍|/^eaKbp3T7gCнjprm")mͿ7Ӕ܊\/O2`h!J>K\#Ik~Ao (roAiwSl[޽\v NoPGfKws4!_/lA8ڒwŸ/P~²KyHV+ fhH7''+|~ ;&un48+۹z3)Ҋ;Tp4vB u-|pC*88FԌw)g*g6ZK-< 2tJx5}u0/ oW0]Z mG1go%'+*m|2ʸp 4c㨦it3=$fwe>a3L/?Id(B eX2{ktS2p%WLL(# y5W4FφJyb2NCu+A|7nea Za;WϽl/Q +ol|@XsF_y-) ffjˢ ])a WǢ-Kc~T =q޳P Q|1zj8'\DD2_vOI^9].\n'yx~R])i;#bTaJ5%SF^3q-o?~|=`Bϗ~g3Kw68ҷg!/w3K9utMMP{^x3M;=]* o ^J]2Υ}Wގ]pև0`'kd{R܂c-1(u5.AU|.z}vB'Y)'C5~NgO /׊PVQ"\}U(zyݮXFD `.kh W^TL[+Jߖ"V8|+J5YDⅧ3W.-;h9t3(H" ^q1;!z|_l`ɹW9G6.tD_I=ߥ|_EBO;HG鯢T$W!o6g ڃ_RK`ڎ[ӑvW׸G[ry4Ӂ 1;PjMc#mpeo;xRMv#b>ooɳRM7020~)ӷYKw\³yi:'Tx'H%)>ԂQv/{$t> 6%>HgȗT96E$|]3J ΏBe-.M-TBu[FVfp4`Ƥl6*K' jv&x+MweN/]9і3Tmlz״̓x(]C^FQ6hhbFEka? '^ T8?BSr;?}ߌB;IOD|^Q^vN' t#yoFu[ w>/e%}˸aSES,sT~S%Z˞** 3sK?[+z 0-7aD2o%ɓqOЦ'Ӟ*vN9a/O=U'GQ/uW4ɟ91O>Rg=Z R `v'dؖc {dI9[9AUTvD;)'Yrw^]QwX({ i\'Ҹ6Hi-Z`3^{k [ko8Y8-b. +Ē1id/~v ߎ/gkM?G;rq`O; у6̲\Sg o䷼Pߚ#c|8{}-k##vV"NgQګ`#P%ou#$ g+({uH32{$#rXoawRͣAvۜ.bַ*auM>ܺ|]蒽1 Q8'CxNӼ~yjVSji=*j)*Y4SѱtzWJ, R\-aTYW5Vz*3;fl-];?ZC;[+Z9jz㶯0;JQ)uIDAT`/jie?(}k*mx[h*3Qvr2^qj%61]'dV\DgW'ԢVTNe K{Bd%\e4SZqZr<ӶQ_Lohl;$z v(yA 2"&3(` Ӣ).c+ f͏ıʹr4r\5 q?1Din؇QsT]r7*尹叼iT@A\\DΕ0p]+E|ۢ|çs]oqYݤ'#ƕ;x}]Dۦ;o[tO?ۈ\yF'oaa0>2:E5":93Н-ekqxwIA$R"/#659# 9Ta՝ѷ<q;8aXc([I^Cv|`vK8Gʀ+zԥõwRǬ^tSB$$_1H4E٠jgMC-KF54-8Gܸ}Ky)tcVpyl;$! rN%xdCaR_Q V0bI/b acYncAֵvӾ(~Ǿw@зȝH;I}X{}H_`C ϥuYSҁx]㱫EI]G|lY).oo xDgIx" Sem%cɁDʖJ-j_s~o)ط[|5з_Ukϣ≚$rX%Q7}7TLw-N[f۪G=u{}jg Iz[6@O\V tH2಻Ѽc߹6f$!Om:}Ѽc߹6f oXJHѼa ml:X]fLt`w0diYn2_ &!*rwr!etGs8[jϯ9:!m!% ^wU{7UTUS)dNѫ.ʠ$* r{$eWa~T}9/0 iO5lȌ$HW#h\B..0n('\iYV 7Y/rp]i()c[|]'m7.oq]Յ2wHWZmJ8= xe0~('JYM-ncGP 8.NgMYp!&)rbe0!V~'KBM3@< P0l&ȀLc3]E(L=dqbs*o&e}wWXorhcN*GƅqSop/"S 616 YVIw{wH}P+v)D*~Kg! 3 B8z *T~l`&Z'Lڊ@ -ۡѠi n0 fA]KV> xܞg0~ĦpTR/mj-z l*)ۗ6 _tul*qۗ61Wl۰`^&8ֵe^3Rpk*޷Zb]K[/78c+ dYXM!X΋Esv*oB;'}ʦQ`0t5)gBwL;a`ȏ w;;1t5 ۝}B|w ;Z !RR%R6{P`Z%od(FT? WLTf39I߶gXY?)r]51¹;/deMgB6_ $|>X! }q?ֶ:Gg{ +'kCh#ഥKo};? rhe¸M)*c0THB:e۝x>8(Ȧ*Keʹ7l:EZϹc-N> =riH0}$!4t>o9 p+8rBҍp yFx|?u8GN3,'p"XN`\dQUբvۼZ|Ȧ%|x=̱"A2(Asfj8FwzhطW$4d(#bx>$4 oTab06}q(Ne_ܽL7+o⒖F|ܲ/G ƟcS9hM]wtԽT)m _$ux}hيUM";kz.86m zDv—6)w]r]MJ?z 9AKæɉrQq *aNHNhd4X &3̩yTsSẹ¸Ц3'-c8rQ)]c >έ3|Xw2;"8Fn `Ӊj\ k,n<8ڿmu.؎sHWZЦ߲ Doyܞ0?QNxa Ӷ^h}) ǁ:ynS%/0DI0y|.}L)U|F#0Bxl{]2ո8#S6p jY:c: M?j{/n]"tǽ ~q1@ط㿭 KƘRPIy&,} J(1{ǮՔL7|ϰ'#O{-hl_=ܤ Z_Rҽ}Q/DkG ;LrƏCC_Lsn6Y>3Q~GzzY_lYkfZ6L!f`fUf=iK_czd`vxپmf7,!;Q?ڶ雽_P ̮,pC3v0li1ۛ:Z>ڗ?u,7 Il0nc0)H[%yԱ|݌}D2@:?+Q 0@:h]@>i]]_[z33zTN&$xx> yݬp}5^4׭*n"^?g W)HýJ?!7vRBUڞl^a3l*. ;frg'Iy]8Lf,^Z^^5'҄O!} 㴟 ګz?H!}X\J^)yU[ex]{WxWx+\D^/Jk ؽ*=߅ \LyiWxWx& ~ CG8bzmv^/x=|z~lJ^UF++rWZN{{U*ڵ^8#zeu^^Uzs:?6M)SN \N}fXGH r S뮯NO_۲SmڋDY:\_g:?M_lQj ю">Koe9ױқ)׿sR\u?1-\Q\3F 4\ "&5 jec;EvrI\kNR\s xs*,o"W/u1J׻ϼA9,\v#1_`\ߖ*r:)#rR@R _JK) W)/\dO\[90JӅH_\#`lj\D̋C@!R75DJK) W)/\rR@R o|K;!WjU3nɋ\/h/u\[+rߠDȕ/\rR@R _JA~yxrnÔx WͧxX)GXr+S톷kxzUnY,AV@k8RsؐK9Šԧ}YR@"W\+r*W|C*~NKr-9\/aC!vh rko>-rW\ '\BR\BR<<HraU/ Ez7 ϵ*,q-qGsmVZCoN rU:y,Es!r K+r K|H9IENDB`perfbook_html/node120.html0000644000175000017500000001263411672746162015643 0ustar paulmckpaulmck 10.2.1.3 Atomic Counting With Release Memory Barrier


10.2.1.3 Atomic Counting With Release Memory Barrier

This style of reference is used in the Linux kernel's networking layer to track the destination caches that are used in packet routing. The actual implementation is quite a bit more involved; this section focuses on the aspects of struct dst_entry reference-count handling that matches this use case, shown in Figure [*].

Figure: Linux Kernel dst_clone API
\begin{figure}{ \scriptsize
\begin{verbatim}1 static inline
2 struct dst_ent...
...dec();
15 atomic_dec(&dst->__refcnt);
16 }
17 }\end{verbatim}
}\end{figure}

The dst_clone() primitive may be used if the caller already has a reference to the specified dst_entry, in which case it obtains another reference that may be handed off to some other entity within the kernel. Because a reference is already held by the caller, dst_clone() need not execute any memory barriers. The act of handing the dst_entry to some other entity might or might not require a memory barrier, but if such a memory barrier is required, it will be embedded in the mechanism used to hand the dst_entry off.

The dst_release() primitive may be invoked from any environment, and the caller might well reference elements of the dst_entry structure immediately prior to the call to dst_release(). The dst_release() primitive therefore contains a memory barrier on line 14 preventing both the compiler and the CPU from misordering accesses.

Please note that the programmer making use of dst_clone() and dst_release() need not be aware of the memory barriers, only of the rules for using these two primitives.

Paul E. McKenney 2011-12-16
perfbook_html/img260.png0000644000175000017500000001415411672746120015310 0ustar paulmckpaulmckPNG  IHDR.%ܹ?PLTEb``MJK# hffommmkkcaaXUV856C@@wuv.*+kmtRNS@fIDATx]*Eш3v }DD(J!F( )Ń]8$Rx^[sJtV8)J8ã("^7ʯ *xc]0aD}{QR4T*E#61CFB[sؘ+\Si|{U`ۚS+j)*Pfxrл,)pwf:vCl:LIxdAh5zǶ09qZMO0RD cyX&7Ibz6z:9tRePڸcPRbk<3ى`*E젖B6>L'z w*V=Ft^-һyY|8 ̶+RD4lI"J l ]Zo8d}m!b 5mY@E0ŸjLJ~yZ)yu:F{([5U1\SIß9fRƚ013\)n6eUt3&[md,Z9C;ȐxYr2I?ۖXh{K*y*fT]kx=O {բ{Vdg.Iwv ·^_/DBiC :*8AG0x:D]J֗}0{cei>(A#m:IӬZEP}gXXP0A 2G 6JjJwm;ۣ8OyJxM3/ I |[+Kz#uA$JU,OoP){ XG@4{)AwAp ITlݡ%T+.({@ (LWki[1?&z 7K",oSQX.\ϓ͑iّ9|uT!}^ڒWur \3P-.m[ӟt#@QVF^u_%='AQGcL8d?o17p8pѧ$` Skp>pxecVRX9˗ qup>~p_1`ͫ iΙ-gˊ㳭g>NjlĖV|.gEE)W-k\I+僲dޟ<%ጅ#\t贶ȼ 2IT9 T7X@H0 !}Pkf p++8zha&,`xBzJ_J TdGGL>SiQP(.DE+B(`| y2 3T>0 $Ag+J Vy5(w dMNK89xtMޞm#Lrz枪@Ӭ,E5H >"lްd 6M!5ZB'=L_ux~2 2žb-(aw2׫5bbiU# jSԙ1|>I|. (w #1H`AEaE #%6mi ;"Xe ZKm1S tgxAkIQѻSͤȈ>+yĎUS4ٞ^'`<'%\kF=1ȁ譍[a/yԠ4NH[ mԾa^6v6:c|C+g%R fWVF&)GSs&USf?TjK&ݫɼH%Emv,IJTaYe4/@7^ :yأiM"( 6+"ZNIv t[v,Ы"$j+ {æ4t^fmֿ`}2oiF)ywhB~&:WU`~{xƟ8z΍RQk= zpʍRQ+Ffǚ^dMQ&j]$vSnZD Fk.&m9X֖ϭfoAta(ZZY 3Μ,XoL)P&XFx} ;[8 g^_u ߩ8 L9⤂>_B8G }q~G+A8Gop8u5VT)֑N1~pv 3f-Ey/h,"Zʗ/ί5ob0vdͅHo8&?88S{&/c0v{pS3X P ajۊÉK0QbÉP[Mo(p_Ǒ;LZB=F5ι6p8AQ^?^L8Sj CMP0j77_ED^ .}&%q_{C;tp0p_ *>1\IY7:1+^G5F Y8!U-geCADke@'zsXhJ\i4rLd+Ma!M'!P :DYAG>.Sxz&g)AAO5 ܣFXG٧K!;(x=LBfR5m fI1 ^!bʼnU~'*lYNiȖ*kLj--ჺ䁪~ZȦ ߠ1G^ Kaپi(g"v~<C!2: OUdR]eBW bH |5vQ*oVH>BگfE 0+?{vsnGI,EOGlfekl܎nIoʣ|FDnmR\m.{ߊhY@vnÿ/G7ll7 o̱,hV͟*N<&v;}ܦY( A!j5HOIV0|ca?!07OM\%G+[f m;|a53[rjDej4ĵV*~3|SQJd mRuhu3\\qcÚ8G-9lh'V2%qm4 mE14oá v8e!ބ U||yUq8~ނ"%kBH4X`؄%ײ;=˖\BgY!tzp~U`MPn#p| ez-6agϣ=ίLzW 2g`eZg4Cׄ5%`5)_[V.E)iX6͂U{MԡY@8DIBlJ$c,iKD ԗFITʳQդ,~BFV7&P0q:8SB(g"JeP;J?QAJ|])_હ(QAQCy[0m3IENDB`perfbook_html/node293.html0000644000175000017500000002104611672746162015653 0ustar paulmckpaulmck C. Why Memory Barriers?


C. Why Memory Barriers?

So what possessed CPU designers to cause them to inflict memory barriers on poor unsuspecting SMP software designers?

In short, because reordering memory references allows much better performance, and so memory barriers are needed to force ordering in things like synchronization primitives whose correct operation depends on ordered memory references.

Getting a more detailed answer to this question requires a good understanding of how CPU caches work, and especially what is required to make caches really work well. The following sections:

  1. present the structure of a cache,
  2. describe how cache-coherency protocols ensure that CPUs agree on the value of each location in memory, and, finally,
  3. outline how store buffers and invalidate queues help caches and cache-coherency protocols achieve high performance.
We will see that memory barriers are a necessary evil that is required to enable good performance and scalability, an evil that stems from the fact that CPUs are orders of magnitude faster than are both the interconnects between them and the memory they are attempting to access.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node124.html0000644000175000017500000002573411672746162015654 0ustar paulmckpaulmck 10.3 Read-Copy Update (RCU)


10.3 Read-Copy Update (RCU)



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img147.png0000644000175000017500000000517011672746126015320 0ustar paulmckpaulmckPNG  IHDR=<8Ob6PLTE^\\URSMJK# b``mkkXUV856C@@wuv.*+Ӕ4tRNS@f IDATh b(]F:lM' qق5}Z3 xD &cSvf2DG3Sv{睬/k'r=4:[ɀ{o2m?&;(D@0d1Nyրie@=_ MK5l8M.|MFqYiwq &E<slH0Nng[X%X넋ŃP毞Ҟ0"DRID|d&ܔ)<} ro]3."}Q{h&?tIrD91]FFAY|54-I']~|S Y&(㰙e8'hM.R*mM4v[YXzgIHPidf My2-*>J-Щѣ|YRnV{e`1Ú2/nH-ۀf>Nh+3 YCLo2v$=>5 05&u\O^&$JS&P5fۡt~Aq .復 ?+1j4 pz yi%<׃)ɆA✯m`ԥo*bĿZ'e*_N?oV$Նl5%)8S\B:[ +"s 䭗JbP Bm6 xJ M=̋D"W9Yzڀ <$R[\;3oLJu8g+v.UBB/T.½ub9͑;ssU2qb1F}HYi.%d'q␽ Šrqȼ ;?ݗeFNA-rQݿBmݗ[s u&ղa5g(u"n&W\y=J'y_Q`T1UUg2D)ͩ9%6Aw,ŌY&>+N,h[9O̔_`Xb`DבV/$<~I<JVhZ )t|$1sO^v2q>-p+vg)=&C:j5OpDDr\Dxg0 /!N }^s$}}$U`|uި$gY@s~oo-ClADs| %A ` U^>ԻHcS T%oUօig):J)\ vQ5ݹmȼN<ԉ9 f 롖D4R:Ӧh(`#sPǙ!'vfq,%M89,$N*P5G m6b $=}p.FvV^Ft hLQ6%~$'F4iQ)[ΎKO0*6ϳLlzG)l_Y| R%swl%7*rgpQ*F#-D7ӈ%^) 3Ӏ!YcfA'MI> x18r\kvA9pLx)DƙLNre+aJC޽x8f{pٓTy(0~ELRP!ZZQⰐT\\Xfab~kaB0{XzoC-OQt\2#&h=˗d6tCZB Lnj qdmošov9۴TB^iY#D%6][]tC=1@WW'/bH6Vڭk:r|ak7ٍBgbeG~5vtVW+4 6aח]6cLw_p^gp,<Ҩcq~T3Э}IDzȰj%KKȫ&w/ <[`X@9ۺ&]k/T]-7?lNfid[gN!ꚷF{Ƌ_ q ܬ/1;L2ِ{Ƶ-xA发`,X'g\†$[t?]| QIބ=D^8Fh?s,-3no2נ>GwyVNb2>v1h %QZBz^*ijo$>LM $ep>L { o7|/ DP vZ[z3߶;moVDhjP:y#olnO:Qcr㑍L+҈+QDXᲠXZK纉VV_$'ҟ)d=5OiNu_FGdWnmlo8ng3975wމ[D9d=5Oٌ3'gkUp'XOW`=ɽllh^!<IENDB`perfbook_html/img246.png0000644000175000017500000004050111672746101015306 0ustar paulmckpaulmckPNG  IHDR=Qw]PLTEb``^\\\ZZTRRMJKPMM# hffvstommmkkigga__XUV856KHHC@@A>>wuv.*+Φ'jtRNS@f IDATx} *pEޥVvfHL9瞛DD`(BU~8j {g? Q(ڳpĿ3!n>UIUzG9)T۠3G~fMB_Kk@aJQQ(x?eh7 B5aߟQ/)M ϻ`[UmH4K@or;j4E- TʽN7 J@fM浑S*+:eC Tƽ?$ 9omWB3o~0-j ^TψOݕ]3~EQ?ou+v ,Q*;-<:L,-F(3b(?|<|I`'jS3km ozNajS5F># Q3{1WʭlWv VpmHvۥƨ_:|'T|WH~ dUL(oHi݄pJ )>¾q)`^O86Oȼe%STڪzgpJ+vr J@Wr8@*Q=tTAl.&V)f5tjMrT&p8L 3ȆIs |.lN -Z95huG\qNrQ6([Pe!§ A.J hVC t0QW0,Wт9~6 $,sqVok==gʧ! oχ"Ͻ^H_},eڷD/ldj;$",Ag. Jj)pc`H:2I; ߐUA,ZRCՂql)a#EC6\)hLpk+hBbP'}T]=Q\C8-pv@X׉oPu>$0l >VGlإeec$gW]8[@pPg:ZjL 5)/=G% vO2zY Wr~?~sΏ|d +%ьjr(^Fׁa5!i -& p".Ջjyvp>p{rwܚYoش 1`s0s m+ <0ű WܢQU+\Ep琵{n.uumG>R`X `\c_ccpv]|~( ::O2vqBO3e%#;ݡJ| VAȧX?׽7_r*iԅ_U. ۀ8% QfFePtNj1s8l|0w)^EW@PTF<3!~ 0-pGR~re=!]&2,ύˋa m#"9^s4 QWaZ9F@! hl/jȶCr*p: `5)t(MWwZZz 2r gѸLHc*{I J AN/YU´oQ%q5^tσ'@>[4CN2)6]vwA}ɾ5jkj͎jmFӬ%ff8UMdfC~?z{yo ]ߑ/LxV=6DY 6)Tat?@Ÿkj[ﷀ|44"\~?z=W57^B{f qif& w=2-(qQ: 0VA&;iSUzʈk>(P[ `,b`!֎AЈ0'fS60LhI=oH#wҀL;V3j}aq0"ܒπjL;-jӅ .F|WGK~ d֨snu9%ֵxUC:~tdYe|0g& ` P8jqeKGck=Q x$[Ԓ6G󕮄 4~I:SlلqK\TgP'j K++ 0UK1Nt.561bEH'g(EE¨G..g;E)hEFz@ : 5B }D?և^|Zc݄rq:5%9v 0ID(Qa۝=|mCN;64M} M*7ElPSnEղ_Y맘M3\Hy&i?x7v]Fቔ8a?c Eszu$cp} HE= q'mr*2+O8k M-vL/ fƝ9;1yޜHP^ L䑯#=ߢV1oW(X'SJL )"❵|֩|Z^os0CoƌmU΂EuAφz) N@% CO0KfLѵzC;`T-e޵~}u*7,P o6~_Mo|]JZA6а<~m Ɨ~B50!zջeO|%lh! Xq_A2ְW5bO?QUJ~g]P.P lae6e}o$RQ XWs] A?|6eTÞmnzl*) O[ץYeƔ_p2Q>:gUuMfJnS Ô7=1q 4S3^|t_\tJ!$_8v;Vz |%a3ph]Obnɖ;krH2ըڢk ^a_=6PhWzcFyu}CaJ2rUA?-}WEt0rwtb?PU_G 0 @ u?|v- >XQ"PlN6x*Z@WiAX:jPcSA!od`d޴NL/K~PȞ:6d lzHއ)t 4t)RJ?;5Kt.+t8ssa25b/фެ%_+'- _*fnNtɾX@EJ̓mw~|rE%5tX_7IZGP#׌.V_ۅiфޓ"R޳_ ~G<[y }m"2=UwqT36Hkpאst!h`n~$(_#WϴhGa.bCR? |//NGlqr)%j%G.J+j-c00/,DoDy4|V]Q]UvW-T}xC 5lu r|qXk*oqkVW<ӯ ۠`NJ3EkBNz5A xA?磀CT7#cJH־9&O1N~pBB "҆I3c5Jʪ.%^}!?nB9kzk0hD=Xe9`--Od֥D{4CՋVxg+8PӐh_-fS9 ,$!7rn @ɇٖ1Y;[Y8us`J{+0g7{a^biƢuw ۅWt2= - >oP1mPN a0Bc ǚWDJDW9s.p,ޖyw47ige2V6Fnƞ5{h+r8x#I43*{PeHO+g3a: eƢ}v{\L:E8T~r*.t^u3MAaC,%"G#s-g(P4-9׃.mDM港ީж~mDE36#ol*JGQ歵ra+Xe3Ev ޷oEhDB!EіUPb}śk43sBwmN >do'Fr~hɾ[od?S%'p/G*A~/o> z湧yBYo~ڬ6'7|.^T|<:oEbvri Lߪ)VV:JOֶ솃#k7SؿEH:JE9e(R//@AI0 tS:S&Z+U>`ȿ^}[(NWZ|Uk-W^X/a<ٽD aV6ji؎%2Oţy&e>(B%k&gHBS*`'˷n Ê? 2DF{w|m NYaKYc{VI$#kZ0i|Z99Ai8-E1\Ҋ M,yKt~kE+p=!ZF{uɁ>F/e,|Wt]\// a)f\t{+q!n IDAT1\'`iy+j(nU~9ұ]aOE%|R#F`J(~;ajۗAzӯJh{n`7-T< _\<.j2cMUTB,Rɹ_bpkxv[3E mM͋0{YUrل~Zr #[ՙq* ^/P Cs o,_]`(~`Ïx35v?d?u\^aա.i0V܅~#V)Dƨ ť6gĩl{tq{D槒XWh5ٸ4k@ux6Y`5ܶͥif+׹"jߘW`|[-[9X][ӈ 9d2bP{x%;Ok*U\0dW_S6YN2eƘ_?;ōHVjң*T%d bKC ¾XuNc޸wz}]qMRWj7Se #3f|I7uvn.*.3>Vn1e pIJM$u#g>(`5¶8)FdJ3=0hF9X*xa0c/b7Fc3 mMoP;Xm!m!ݶP՞nK޻[%CBn1dmtn{{(2آxG/s^GT,?ck{ ū3sFϾVe>нt2`'-I?_ËU (=Jr +VCC7lpZ.ߤЬFȏ-еYU *G3@4lFV!>3*%śeS$#xev?Yx~mYW=2XG7EP&!=hu#{i] b<+xj,! |=R{XLƛ^Wɵw,s f~GuABF2#xt][-=\JGL)xeQnyaxEA{Tq,Q7'7{mj]TyjD+ iI(Hwb\*~VTK$هq۔\S&&=$;^>ɚPWcdMU4sdP_@[ ljI>2\0rfލKtwv<m!@]ٸZȻhBP Tkvܙ#xZ^nƷ`f~4X-wb3mёլ@Ii>*[LёլMi[<爙 -|owHapk:۠L;jp+M~PW_sH!~oA31TnCA CwF,ࡇɓJ^6)Yrua[3X@*s\>VsQuT&j8^luzV_[VV{?m7j)5KѯcYT 0I=IEڠZޠhݸgpU nergB>PO_a9YʔK;RO(3\ n~TI66z\ګ%^bŋquTq5aR<~L%T>JC7*~]>TD% 8='o柎lSȩ$gs. Pɽ`G nĤp`IM$ R*Q9f8xc'vM_s%C>ݟOz5kn_?ccs_Auk;,sGj Y^ZF ̝{}-c"vWd-b-sBAH{w{X>oܸqc?/\o슿[Lñs=CS+r:,#fJ&ϭ?3Rš/{F`GM"B>jΌy ˌm#*xf|}S&lA4 rLߋBυ^Aʾ2cfއڞD;m{26 EL&T,Xg3u |X|g-, y:8c>*ut#mYM`WW;?lWdRcO4Ⱥ<=+&B쬄ͳ?_'y:b1${fY/{zZ.Ͱvx="0F?|c4Uͮgܲk {of|M'qr}-ٓVY7dt3iP{ڈ,Gv|`j'Q;{ Z?ɏYΫG9&$#Q;Y=ڳH=t2yod!˧7Y}|ӄ⛁Ty2,82{7Ui2?9Pmtލ߇s:>ϩE,>7m3QCL2Py % s\-'"G;q\Q%%ExUZ kOS=Z?ɮ+nF/x`]%H c[y#G?<,z#l#/Z0 $Ak?+mJətpAkW07vOZ?h)'oIʀ2W'쥗ƧU̺9}7cJ_^`Ԡ:K߰kHVHu?<2o > {K|~({Y&7opۻATu98 YίsK 5<fGmyTFލ ót8HUj^[LP^L#ښ>W_7qhLPX΅%_m_&+؈n >;meZ;6çc.2|3{KP`Yb۾'(@n8쌿vI t" ߿e>CSPJd ~ /Bf—3C+D[- 8~ /DnHu30K`۞7c? <>ۼC UzV3;hK{v6aXdVzT5U 2WLq#LuD[LΞK" 3OBۙ+s7] ~uaz rNǂaf"k% A2 RBsUY"tg{v.|ck"7?ƍ~fkiB3n;8(l_t9Q0?훳6'2lGc|C}z|'2!.'7웓]|6;;?aGzek?a:7~'%o]6;˽ն}sxGYrЮ/Py]zKaϹ<, ӥۻ^Կ1 zU]s1o,㥜=O:n:g?o*bSf/weDP$ |D.-lvr)"+_agď.~dbw%Yr T2wL[|#H[pϳ5K]9eX'Lj|=Eӕn?O.B^7(a@[>Ck%mK”J;-$]( r"ƗCɹ4_W]t[!KZ֤<:~8X{Q\VaܜM'JW,h++?gm9(ƇYr).nx,n3{EӧQo{u>KcO;b!/`f^pd)+MFVFuSsL{pMfU`(pN $}ìo8SpJ 09@?iq{#Kxf=#iח7> Ԙݍn[өy33Á_CҮoˬ bhE>] $;T;u,3v}Y>"=5q8+8Ȁ}룇ۘ$,ItT82_&cZE Un.])}qk|f"c#dK勧S;ͣyp;_0G kk!u@upQ1=ިHvQ{K"cYIclAUp>;Xb7`NJ??=QzVٲztQ~=S&=o@%koa|fx7bٯkx|f3_?RH>lzAڒ=[ڞc# H[^'I['I2#߮a7KO$iK$i{i=Qu f>_B'lTCߨQTF/5P\G{ke[K5hELGFLǑc'Yzi :GUG\M,&/eG'<]J7jfs9> C?.%yXړStړPKh3^"J#fga^ KOd~9cMUpq| N1z7C1j!ߦ{7~!\[߈n'=糳c8` lnQB{Z m@4wG U{WrOGݮvX{! $Ѕυq7{!B+dїn 8dx+d* @)WW@.^9uF 6|jt.e&f"t`: 㐵> ɖ~hLg ]Pm!D(exedʗDf~HJg3;ǁp63_{+s6l< R;_j(+6_gloHM=sá56l /FWbi6ݢo1,d!{ey ^i ?ؼna}g7Uc0^?FNzg#}{GK ~"y3|2?ٍXVfꩽrT >S|Ά݈1 p0KlVg/+'[\{g/+_!\_  's11Ұ2wP#+m;5n,Ft޸q#jg*/;5kyidfsw;k٣7(GJeʍ\xkև Sw ^ahZJuAs}Hz1mwR+cm,X>L\aݟ C~c9ڣt8vb<|if^=F08^Ey8Aۂ߸`O= ^Ȱ^h#Zpjf`l N=ƍwo߻ގ{7nܸ 6eA溘69;!g2uGYA's9, \:MyR;= SpݙoGy#;dq ݸqcM, SŴ^kP;$x YR[xtڟg齇Pʖ kBo3U!=<:Oyx w[d `G?JG*~_nOx2^ _Q5Qw>|1o=+#Y RD\=_l ae ohI8LJ ){4{ <Kg`lLGoYEs/ Gr\9Nyv=s۷ zIDATƻc\K_(4G%P`yj#—(A +? Q=*Ǽ zƯ} G v' tIENDB`perfbook_html/node274.html0000644000175000017500000000510411672746162015647 0ustar paulmckpaulmck B.2.3 for_each_thread()

B.2.3 for_each_thread()

The for_each_thread() macro loops through all threads that exist, including all threads that would exist if created. This macro is useful for handling per-thread variables as will be seen in Section [*].



Paul E. McKenney 2011-12-16
perfbook_html/node437.html0000644000175000017500000000522611672746163015656 0ustar paulmckpaulmck E.6.5 Alternative Approach: Divide and Conquer


E.6.5 Alternative Approach: Divide and Conquer

It is often possible to break down a larger parallel algorithm into smaller pieces, which can then be proven separately. For example, a 10-billion-state model might be broken into a pair of 100,000-state models. Taking this approach not only makes it easier for tools such as Promela to verify your algorithms, it can also make your algorithms easier to understand.



Paul E. McKenney 2011-12-16
perfbook_html/img171.png0000644000175000017500000000471411672746115015316 0ustar paulmckpaulmckPNG  IHDRRS-PLTEgggMMM'''tttZZZ@@@444CtRNS@f MIDATh[ˋgvgjLCkCưA;/αa%^sl F!_E,Қ%`\b?]q$~nWW^! y JȽ>wXT#'\%Q0mt!FP(vpE #E&Lk).,lYV&žй$U( 5?b6U-$靓1+gt#D r+͎5 sSCB~~R9򠀉?;B ㆁ~ Pxo5DfͤQ:~~u6ՆysA*ؔ8WRtǢBc/܁0Oe2n4S՚V6:!~ܪ)y8C3@15 ƔSrnJy0FrGQzS#v?4qVHEE6QW:ߎBtu%ɔ kItS+kPV2Y2i& %#e]A+ sʺ}hmQ|Qiyqg Om^(R8d4+ ˆd Ѽ·}E?bvh5O#ҍxi89/CnVP4!B'~8U>F+8/nwIn:c0$GpoIpϼ~R |xDHIDݾMX^r gL-fB:6)Rq<]V!w?ml VX>ۢ"YJ# Ab׸dsqR:Umj"Ol A2ބ)$w-6lgÃuM\W}ɗ% mnEMJ 'qI*l'#T6.w=Md!菩?[GrQa+a-P8zSը+ZC5 '_MuJ:A4C:a+zZ*6 SEYb ?8YZֆՄ>_9>ר̒i6c_L^9|}'X+^l$qq2a3U69خN({Υk]j8P VuwgQ5z]˄_Fg|O!ε52#\)?akL*s9_5@BgY^8TIt5q,I TwSo/TW2kPO {[E>cˌC3^x{ڇ?4Sb{ Wj D_\ f*lAv5(~ $u񽅁ŸqzCܜrL/F/|@`k< &DWJC|3) _n[6 0VJOmF[Lpoɪ|d^,y;Y| § Ї:4,rt֠#zX)=Y q\]_]r/ Ya^^\ ȿ\?k\`RQ?6(u'4Nmń j1H ,]DK`업Tk!kzf3^ o{WY' \oʧ]Q]\*3uc\~X.kY25~mO69D t k*w}z'v%K%!m%XWvQcI}Z0al yq|rjq6]KE ±uOKDq6A yUh/q@M'/x'bR)<Ɨw`t,]W[I{?[{f{C#'f Fxutnw3vzB7x"s&䡉OOG$t8h}Zɱs5{Z錋x>4$\A2>O!G(J8pK#Ё@끱؋j<#t $Xֺ79unk2pd*<4h &Y+!y"?dw(&8#&_?d!ݩNqM Û9U~#(3N#'ńcBEW-6J~05sd-udqZ[ypd.OYк;Ll-Z a ӵXy=dz=Q e]dKZ%10/bƏ=8v? cz ~pJFLr+!GGn@f)Y 0hú1FjM U$n^zꅛ}1OtOpƷE\ai+ CK!ޝ2=-cOFW5H[\ڡ*%lĴKvzIՍ7w<ĕ6w-|`ēhYP5mD(_U$:XTzBdnU+G-m!Gʊ53׌1#r F 6uG銎#!NMMpב"MFvbT>$e@1d"ItyLǓ W 'p%m{y^5II&蘖 tX+N<^W }dZ~[eكs'-{D'< IHz$x>Q@9ƊY\4]K\<7$)r[}`\%? ^YsaJiY8J,$_%xg]CꙇW2Ci_au =eWgjolp㡼/{n\2gq^37pɚag51*"!^獫嬿3`x3xCfn\_|gv,5i-Xwlݩ]-h Mʙ98$\9/}_2;|V#BAC/ڊZTmoZg9xt<%>bd\2UV>E{\6ҡ?Mjݎt*P墐6(([7S(&mvQ|e U^_f+(bH@!nؘmkyO<7Aehk*%7I z:yt`JRkSv{{}[S"brϽֽ,S7gKF멞yj;};55GM%]nNy'A>Q@ޏha >fC9"MܔrӄL̲)ջ rS'$1v*{w~Rܺ7MwP)'U eT^Pj|)t6h&T^(ѭ%Ŧvӷ$U`GM _C3SxW8zzoL[*K5F3#r Sk8_`U n,f L7 ~-z}Oĵ[*O%x~~~'ppl-VHУvt@ vGͽ&h3i@.77BOg$ יIn(b1t9ă86II4ó؛m'h]]1{SX ţ~ӵҾ(z» ]Ǟēl'hfv=OٛrpTUUՖ9<;*'K[)#H=8NźR\Q#z:abH\멼f_bq߼?c/9wD`&ⵊ=tW%ȹ8w\C״!7ςV߃!i떜VIhYˤ8= =vP~TͿ]@G6g@9.庼F9-l֋#?36mhDĈ,\AS62S-OE۩~m@rJQ++gRo_~?6f+IENDB`perfbook_html/img82.png0000644000175000017500000000030211672746035015225 0ustar paulmckpaulmckPNG  IHDR Ȩ-PLTEMJKb``mkkXUV856C@@wuv.*+[=tRNS@fCIDATc``0`!fy;$ccdPd(ŀR7x7`d`e s4IENDB`perfbook_html/node371.html0000644000175000017500000001412111672746163015645 0ustar paulmckpaulmck D.3.2.2 call_rcu()


D.3.2.2 call_rcu()

Figure: call_rcu() Code
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 __call_rcu(struc...
...{
46 __call_rcu(head, func, &rcu_bh_state);
47 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for __call_rcu(), call_rcu(), and call_rcu_bh(). Note that call_rcu() and call_rcu_bh() are simple wrappers for call_rcu(), and thus will not be considered further here.

Turning attention to __call_rcu(), lines 9-10 initialize the specified rcu_head, and line 11 ensures that updates to RCU-protected data structures carried out prior to invoking __call_rcu() are seen prior to callback registry. Lines 12 and 34 disable and re-enable interrupts to prevent destructive interference by any calls to __call_rcu() from an interrupt handler. Line 13 obtains a reference to the current CPU's rcu_data structure, line 14 invokes rcu_process_gp_end() in order to advance callbacks if the current grace period has now ended, while line 15 invokes check_for_new_grace_period() to record state if a new grace period has started.

Quick Quiz D.28: Why not simply use __get_cpu_var() to pick up a reference to the current CPU's rcu_data structure on line 13 in Figure [*]? End Quick Quiz

Lines 16 and 17 enqueue the new callback. Lines 18 and 19 check to see there is a grace period in progress, and, if not, line 23 acquires the root rcu_node structure's lock and line 24 invokes rcu_start_gp() to start a new grace period (and also to release the lock).

Line 26 checks to see if too many RCU callbacks are waiting on this CPU, and, if so, line 27 increases ->blimit in order to increase the rate at which callbacks are processed, while line 28 invokes force_quiescent_state() urgently in order to try to convince holdout CPUs to pass through quiescent states. Otherwise, lines 29-32 check to see if it has been too long since the grace period started (or since the last call to force_quiescent_state(), as the case may be), and, if so, line 33 invokes force_quiescent_state() non-urgently, again to convince holdout CPUs to pass through quiescent states.

Paul E. McKenney 2011-12-16
perfbook_html/node155.html0000644000175000017500000001506311672746162015652 0ustar paulmckpaulmck 10.3.4.1 Lock-Based RCU


10.3.4.1 Lock-Based RCU

Figure: Lock-Based RCU Implementation
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_read_lock(void)...
...rcu_gp_lock);
14 spin_unlock(&rcu_gp_lock);
15 }\end{verbatim}
}\end{figure}

Perhaps the simplest RCU implementation leverages locking, as shown in Figure [*] (rcu_lock.h and rcu_lock.c). In this implementation, rcu_read_lock() acquires a global spinlock, rcu_read_unlock() releases it, and synchronize_rcu() acquires it then immediately releases it.

Because synchronize_rcu() does not return until it has acquired (and released) the lock, it cannot return until all prior RCU read-side critical sections have completed, thus faithfully implementing RCU semantics. Of course, only one RCU reader may be in its read-side critical section at a time, which almost entirely defeats the purpose of RCU. In addition, the lock operations in rcu_read_lock() and rcu_read_unlock() are extremely heavyweight, with read-side overhead ranging from about 100 nanoseconds on a single Power5 CPU up to more than 17 microseconds on a 64-CPU system. Worse yet, these same lock operations permit rcu_read_lock() to participate in deadlock cycles. Furthermore, in absence of recursive locks, RCU read-side critical sections cannot be nested, and, finally, although concurrent RCU updates could in principle be satisfied by a common grace period, this implementation serializes grace periods, preventing grace-period sharing.

Quick Quiz 10.34: Why wouldn't any deadlock in the RCU implementation in Figure [*] also be a deadlock in any other RCU implementation? End Quick Quiz

Quick Quiz 10.35: Why not simply use reader-writer locks in the RCU implementation in Figure [*] in order to allow RCU readers to proceed in parallel? End Quick Quiz

It is hard to imagine this implementation being useful in a production setting, though it does have the virtue of being implementable in almost any user-level application. Furthermore, similar implementations having one lock per CPU or using reader-writer locks have been used in production in the 2.4 Linux kernel.

A modified version of this one-lock-per-CPU approach, but instead using one lock per thread, is described in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/node202.html0000644000175000017500000000522111672746162015636 0ustar paulmckpaulmck 14.2.4.5.1 Ears to Mouths.

14.2.4.5.1 Ears to Mouths.

Since the stores cannot see the results of the loads (again, ignoring MMIO registers for the moment), it is not always possible to determine whether the memory-barrier condition has been met. However, recent hardware would guarantee that at least one of the loads saw the value stored by the corresponding store (or some later value for that same variable).



Paul E. McKenney 2011-12-16
perfbook_html/node288.html0000644000175000017500000000435311672746162015661 0ustar paulmckpaulmck B.4.3 per_thread()

B.4.3 per_thread()

The per_thread() primitive accesses the specified thread's variable.



Paul E. McKenney 2011-12-16
perfbook_html/img225.png0000644000175000017500000001110611672746030015303 0ustar paulmckpaulmckPNG  IHDRW! PLTE"" DDff"{{{̙3''gggݦMMM'''D33U@@ fMM33wZZUUwwtttZZZff@@@ss444mtRNS@faIDATx]bEmu-;%b5d2!$y  cAPw X1'lA?H h]`@ nܭ?[nɁ#휳N{6AcH#E'õ Cerkrd6.n/_q8{+|mЦfKIiZwn;ĒY##\"lb)-Aפ>}8q}z}e!K:̬v aIrՈ,0X:u%D"]4Yͺt4`>.~LٟMC%~fa/Q 4~3Mև`2xRc.%1֥eܗ f믂GS~l #bS$3ѽI]uRmU7N8C[@@UMV*$=o›x}[4~>mc/Ƌm57v`Q5YlWؾaǟpQ̅3:b1 #n*%{_8I618E]9NI7.(\ R͡ɪ><=@]G~ ciFT^I6Dz3 *Iwngy?Mch漀j$ QcT[#+w˶kd1mGm$kzw MV(T͕?;P-y|ldE QY+&J=Gd3k*ڝj&{"QY {aUr& 7J[bU C֣Zbn K~ RߋG0UKA櫭ysD9d5.؄D_T([1 ^\y>O9lĸ<ĵ'v\Ӆ' (ұJ{ܠ2`ʤ qe+Ԑeυ~u,ڝͺaSꑈvu1JRӸ M\^菸򅮮/:2%;F 4>`s剼"}+ D`j]J`4EHY!ʤ}NG 3Qpeڝ oޓwMzTOkZ+u}]'>dьw$|Re~%$\ͻάnK@Sl4\TtTOܬnTT:qJ_ZNsNhjT9GQ zw7yE42,qhmn1L 5D&pI¾9ʹF$z-W/DWĵWumUg~ -5VD\?oh*æ#Tj<IG n )'r\F5Nv$Z5#{qM NcnGk1hjTñ<񔰹8uc U$NL7y(-s ysdgn#WIGs9Svͳ1- Xƥxqb/\hb1ڸMd׈xy$1fcPCF*ۦq=Csoxa]Xn7{ɹR|3l҈e9#bIO9\>h0|msè){cp"qبqx"?A\9h'_ ,˶EeY8˨Ѳ*m]BsUUkWUzUѮp+$\۽2U\YdLcug\O6VUrMIΟ^)3h'gm5VUp\ rVU!c -*כ@޲J81p41 {F('EMVS,W=>+,3u_f= z[)y Fǧ-kLj'#eu @@OqU! 9s-tmx4AVёv]nYdgiOU#',]`.hɠrRO'ERH{꺪l0b&.hz;H&#1v܊4imq4gAspKƧHYgi74H:& f/BrgSla\HbSf`]?mY`Q|dA"ҔeR&ty>Vv+/-}y %WSj ef2I:}yN3o-NM?]nYb:h_LT]ZNWLtMYRˣ3)HoR:|J}86z6]$GE>)OQ)|V^+ 6%Artgz-uGY@:35N,vƖ;]1kCʯ] f)n'GlFuܬtٴ)t5gTf=Q)<0;5l,6١͔[-I]Ÿ8ϺKh]@ZW5к9]op/CZt4w h]@ZW5кU juUh] uނ}p~g9bgͦ{Y pg5t<4Y ūZ+Js޸lcQr\o߻[!Ϙhbwn*/׏| h]zb^:7Xx"÷?-}זxֲmdY*3_Е̯M~ ǠuUh]@ZW5кU U8jpEҫ8褃GF8:h]/]; PwsZ pNנπt{^u[O h]AZW5кU jZ:si:b"v@juUunjnwS$^;]\۠+kE? dJTi]è۠7w){.'Mߠs 1m 1G,5кU juUkɈ~_Vs"@u-ö܆uM[Q1W#-кԵ"ߩ๐6ZZq .a}:][Q1!s,h]t-!6ZZ(pHjbGE] !v~.xT(mAi}}bh]Z׋ns=JIENDB`perfbook_html/node248.html0000644000175000017500000001344511672746162015657 0ustar paulmckpaulmck 17. Conflicting Visions of the Future


17. Conflicting Visions of the Future

This chapter presents some conflicting visions of the future of parallel programming. It is not clear which of these will come to pass, in fact, it is not clear that any of them will. They are nevertheless important because each vision has its devoted adherents, and if enough people believe in something fervently enough, you will need to deal with that thing's existence in the form of its influence on the thoughts, words, and deeds of its adherents. Besides which, it is entirely possible that one or more of these visions will actually come to pass.

Therefore, the following sections give an overview of transactional memory, shared-memory parallel functional programming, and process-based parallel functional programming.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img280.png0000644000175000017500000000464411672746064015324 0ustar paulmckpaulmckPNG  IHDR9UryS3PLTEURSMJK# b``mkkXUV856C@@wuv.*+UetRNS@f IDATx\* P׾,^uLU! *u 'b .lfQ ۧ*v]E]T|m-RPJ5q͚\^ |4hAY%>?:'Wvˏpӎ<קrpq]g),G j5)iՋx^~Sҷ9SҬ[ .4fTz 2QUt[w?hoFduRIiE嬍5ԗ7qۏŚ(VH;+ jˋm -:GKX'7D38kے5#I |Bp^y<@ښ"С~BMe%'ϭ@OQu4؂2a g l XvϲK\eY"ڬ9dh؆KԾdQ'bT̺}3f zq-{y7np#E;QU*POn~:w-9akɕNu2rUG5Jb&Kܺ]( xU{#]Wޕ¼keziޔzDKր|X0%+p+YJ j+C/ԏ Ί3 pU:~S u :Y1\`Y'@EiIz]=FBr«c١O(֡|bc77IzQh tQk :@Bj z)j( D`O5l`cN͌U-X p9+mi. DUKGlσ #q7$(R\IԎ5+% [|6MTmLr0pm$Ip$9 xۋpBX52$.bhřLj)u1ݖiʂ5zNWx\k+y,%<>-<]G~x苋Q卙I$aQWD8"S vsO)_[#.ȑڲ+|z/Ds4Q 8["K=Z 6̴ĐHAy`V"Ώ\Oy_)"}/D 6rw(^]@_CjzԟrzvXS&*đ o"ͰW#6|9wmKߍɂOUwt |j&5&c`^"%bUj䬚|cS/Em*oVbGnOL>֮|+͙2\T)_21xJ;Xv¹D.?/~}ܡ'H譣Lw9l2lNs^r(Uv}^*c3*tf# BA0]{>Bsx3{\:pyip]R =38~$i0 ;>\$[ϑGU9Y"SiӔ H.RЃN)0滊aK+74S _̀d G, g5~'B?܇S.OEanI5` ιܤ{4gWTI)S J'.eo6'?VvaPߑ;h9]_|;p0P6'["sTeQQ65w:0)]T9$ՙccZU=tO/-)7H..ER؜_%ş%ezՁ^>󩢏M a=}}uK;6.zAr;DO"bq][2p` E?>H'f}#mu\jeU"O=AfO$k(y->m, ҽh^gSaۯ9srnNS^6?:~{D`CQ)7HG6`Gٟ݌甴Gs%ʞf5x }K["?,vůH}yy>ku6 ?w16pnkv|U,_Min滝< mKOGNul,_49y ιs_ vg{ P<պIlIENDB`perfbook_html/node358.html0000644000175000017500000000612611672746163015660 0ustar paulmckpaulmck D.2.7.9 Online a CPU


D.2.7.9 Online a CPU

CPU-online events cause rcu_cpu_notify() to invoke rcu_online_cpu(), which initializes the incoming CPU's dynticks state, and then invokes rcu_init_percpu_data() to initialize the incoming CPU's rcu_data structure, and also to set this CPU's bits (again protected by the global ->onofflock) so that future grace periods will wait for a quiescent state from this CPU. Finally, rcu_online_cpu() sets up the RCU softirq vector for this CPU.

Quick Quiz D.17: Given all these acquisitions of the global ->onofflock, won't there be horrible lock contention when running with thousands of CPUs? End Quick Quiz

Quick Quiz D.18: Why not simplify the code by merging the detection of dyntick-idle CPUs with that of offline CPUs? End Quick Quiz



Paul E. McKenney 2011-12-16
perfbook_html/node84.html0000644000175000017500000001000111672746162015556 0ustar paulmckpaulmck 7.3 Synchronization Granularity


7.3 Synchronization Granularity

Figure: Design Patterns and Lock Granularity
\includegraphics{SMPdesign/LockGranularity}

Figure [*] gives a pictorial view of different levels of synchronization granularity, each of which is described in one of the following sections. These sections focus primarily on locking, but similar granularity issues arise with all forms of synchronization.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img34.png0000644000175000017500000000036111672745776015242 0ustar paulmckpaulmckPNG  IHDR0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@foIDATc` 蠀AE=$ 0:^fNYj``Q ۧ`g&Ap}"7|>e)g`F3#Fa.ݐIENDB`perfbook_html/img11.png0000644000175000017500000017072211672746050015230 0ustar paulmckpaulmckPNG  IHDRZoK?PLTEHB@2̸^YXؽӱҞhbaԻ۾VPO0 #ϴsmk922.&'ʹݶLEDG??C;;王A99<54|{ڱ՚c^]|wuީȶ5./ռ0**ZUSᳱxrpohgٸŵó׸숁RLJPHH$NtRNS@f IDATx콍[#י/X*=]SٙS'N՝u zXX#.ܤ5}Iʮ h`Nȣ" J ڪutTӚ鰢z,&PcH{'&3_J۴>J{~B{ K{;^>+P#@|_K.U}n_a&Uu0?ӊͫr5RI]3tX3g5Džtr<%gVK1=g;*y{Nv&Vv df+|l޾X*C6ftkٲs"(e4fz3Kۅ9Q|y{ c"Μ|d\ Q](ίD4LkX<76ET9Rq'Fatj?buywF4Ipd:~aufRJ%aAYjE}+Wy L6SŘ)Jr9qV44N2)Y}0`O!`P!~XxaxI;p.c3M]>5 \ 9uF #$|࿖5[sQx$O(ɿnY:zt> g6?!K0 vr4 .>ԟͩ7o²m*`ۤ6j=<%;AhNȣO!YW#(uW^eM4b8oVc6nlN^댗yL=en..=\ A7Sؕb!Ӗ5f33+`D1+S%ڶdQ\:eb. t\x7Fu;B?PHv?:3\/ Δ;6E7oI4t U]3|]-8{e/obEH-,dVree. pqRnŖ^H)[{3uTw{Ḟ#qyEV{#;SW=È'҄Ļ!FvJڷrґL1mnY|3QJlzA`̎;L{1შcxSuv ͯ3VjŐP%0hY vQq^ +Rz_`M:. AMF|D{9NlR11ו Mk7&(ϳ ŽJ;&lTd[|ȦJfY E2"qX6c xkV 77íQql Wr t8sViST9X_ s&FZyƐhV?nakG"ےSOrߛ8uZb̈́t\Y{P?ahLRBxMC\)q gpa z0/͹f@N t8<{VNU(,uU]˭&RZ4,F: (U'Hoc"WuzpXTa'ױ?S(/'|f"XJ䝧d?6`3iO_px%^rk300nހ͍4n6u9ȇC^_CN:|az7_W!5>wHڝ]ę b@;ˎE!>g^#0Q.S^5|].U l?ً \8zp+eOx pyu FV9ᜉ4p}9* .\O:¹FKLIG-4\&˲@I>\mM?0"g$nN עf:[ܻV?c*lኟU'| YeL|_kimq-ps9>d-@1a>t;/af٭ڍV ~m8{<|/7zl0A~/_@Qu.nցS- kf!}DPkmӛjn{YI|f:Ǵz=ᘇw->sXVq'?2j{U|~1z=SƜY!"E(+$י,fU%n|wJBQfViUv0]/\V +ܹ|Yc.=әBe/mZ8u$a,A":[qRv<E܍f{Fjkמ? 7eMPŖ@ɵ5`1^cS/zj,X"xǕqSݙpO*wa Y#(7KloFďsgl^a£EIDSq N`24X4ڿj)B1*;i^G';fs>HҬq!2҂K¬<ijy ~z\=0~BO0nmע^,+Ľ,by7.)Dˆ_8';otMu ~]`wk\! U6nQyRkJJ1M@ wt1 ]߃ VzuA5JE䦳zKqt$6a!^Dq|H#I.ƿv1Lˑ= РjŃʺ*qQ/];HQ9X<$*XKJDV.-q  -vyPVx c(w Fsbt{Bĭ a#\Z⮶b700icG.a~dz0]tWYͪ m nZoM1!NbX|ϐS;UڙqCh[QBfYrBUq нH "iBe#Ec3˓TYl^Y>Ѓl5ǻ#& [5BE ?Y!$e>ka꿵 059GjM%jMhUQp. YȐ7/Si_Nf J(9seT5 &s@8zӺz]TPc@S:{ J N,E xaM騆K%JJӔ,g|#5_/ɇa\G߿6&(.p!i6Re@Y n],>-m.W8i*a z~~}a#[Wn? 9a 2AxYtڿ??hhٕURQwT?K}Gw%]d^67NeaVjˬ*)o3袪Np4m[`PX,@Z@_`ٚsr2ɶ^[ -艎nc|p_:l;.>"|yp㺏~~2JO'Pɰ=D΢}h츋# Zv[/4īnۊӵQgǀ:FSPQ|w ^0rQ_7;óm:Q:&w(F Q h4г"pW Pt7p_z$u\AM` 99 }# G[PGuBԌ TʤUp.?H;t[n_aC405Fy>CӏMRأ_ߓq:3ݾ E M`^?YtJrɔ\#cU>e> G˘JvjaVeLeq0tuxl3[39vEĽp0b@-˚(c1)3aee 9_/uN1m 3؝҄D6;LcPw*ULY <>xch/++kw~y+Ŝm΢1p/=w7a-*mE 0NǙvcFF~;LߘA'曍03Xiz>'jqa䟴O*x[Vz˘J+?ػLɊlh$=Ey!`pXeaFy>ytcҗ7ʇ R+b A*鈜8{ǮÖvdaԻL-/?Jt9Q7̍bSjzO:2.]'K )RO]Sz7b'#yU+WnʷZk/71Wd}lӑ7oΤwfM˗O}S)fIm'Oxp !~D/7/EttV>4:_smƽ\Xkxl li뉺ݑ9헛_&Ч͛f *S{G^{ꙎuԙL@j~ZgY뉋K[{L1h< P%JA s[qyB~kv' TЭTc[Kb6̯\X+xD * \<0 |9SV7^vlh5J1ݻs qRb&L6EGok#Ch? 6[Zjp\t zC!@'B<9zabHWnb!RS#I'xә=i *=֯ϣ8P,==GBNp#qބ|ꌩ/L]=*B%w(3a^q=(TDѐ?VL"- o 6^?@nZ1"O6:7mJ5Dy<؂*-(ͣQ=mRҔiay;Vxn_ƑvfHJ(qɊXE$a ^"%6>z,qlZn2]25mLRy W&K$Rct:q[t43F{52qa+eq*-j )(qXaVP?ǶV5f'Ϻ=|$*֐bCTQH9p\CȝaG%{:@y12Qd΃yV2!B:ᩖ\jyIpm ەh7hat$c%~e=BjGDc,@=+[])fyU^;>#i؉r>{Kz'ˀ%4KHKE1j0#k+ş83.gE)dYd$=V^pʆEM !8xFZMõi6r<2f-`Ѽ&G!VZKu0V%E1M&0_B"&IIjoU4E'9ֵ!ZؚcU7UA2:*!I"^%ɘ.JR\,`{n0ҋG(S♈Y frۢUz R_Ҧ%Rlc,37@k9s#7 Q qǭHԋ7-Z ͪ.16ZYl#nerrDx y|xInؖUGbc[=dѰWf\@sEǵj 'Qlk̖aIx-WmK:r0¢xNxhSI4a3i<T,Q4J  P$Nc "cYR}!ɗoh<COe5}%PmT+ʘh8sD%JάaP%^4aTUɽ$v6e/~{1eO0O;C"ԳIDa.#`oP2QlaƸN.&}鴬Jȋ2kzv"L)<k!yEQO[)υø 7Ý9N"6YZZr4l8SВZ4TPaJS"ST&61I Uʄb TzE:#WHai2A2a`}҅tqa0b2lFU7Tbl|;s;! ήUUU!VԼ6l3œa1ց_Pd#SB״2p<FIf,mϖP i~D0Ni[Q:h~vm. l@K> x ۑ_fXSrzԌ6Ϥ~SyS =dd1)N8_.9])|jeU?](c ̖SΠ}C;Q,mz:%  -~^l֗ nwNW9GfkB츊z5} :.a7XnUgo7Փ^pp6vؠf7H[)VQ(_`V ۭNܩҙ[yz!!*Vw IDATnPrIȢr jW4徛 fCPtG_./1 wOO'HBkB>kDqߺXC>!BrpǛs,!RېY|z_~v;:T(~{AA0V=s%YzҾjZjn-@ҝaY+kѕ'`F@Ď[u LUΔ3Lztc{y0;RʞL?x~a6ݎ67u~" 9J Dqvgl0#+02';'^>֑VsSww1/R1M_@FS}֋މUŌx=`V?8:gxR#;: .P{﷛W\pwVUW+PxyYQJ+tsy {:[L ŪϜ4A;_BWv̪.@v3P]t6]fMg7;c-Lݧ6OD,oP6DDB1m~@;WS` (TaBNGM ugu~ǘg;SOٻ'VUv9хr.{ B uapo@V'=}"̈kWS?~ີ]T75 ôX)kg$D'%=mufgRoS%ǰB鈨iPĕ6yi_osmg?<t:ˊdSbğJ1߳0"}3@ {T8+պ}#`p<3 V'_S~}s\>tGN<֊ҡr"ԟ-);%g~7; mmm{Wnt܂7]CڡUY Fl  8_U9_b[7L7zoFμp>(qt;hu̗m\3FS_s"Sc>{ W%4e^U/n,[דU[faV6>Y7G|7*Rj0TD` C>}#kW;^qla7&;ϼ0jXg.eLf?[3A`ljd&j89IjaV.DO\ 8T _@_xFqTz MÈi[>Y\ʤ!Rp;WV6sFwMx3_ 5cLcϬw{vw7i~UX3z0}yڕwcw)#Z_=Cb҂{`N+ͣ0#L-#O4RWO¨:LYZx>E'CXlDqOA2zn5_2D$oPjDV*W[^ bY+$J  yldvdc\ n,LLmkd-$JbԈEܖo`Իk|\tZOy?% PEñ} ^ ,,e!E QTxs''6oW#zңҔ7Or&a(|Xg@$F$ Z}UٙgJ rzT͋1>}B,V`/yNܗ{ChuYB] b 搨R|Z[|- SɳnSBdY(Ox%*#?u 5`W)3+!lz&,>Mc8O ĖEX%|BCmWI>bY?NVU'v0H+L`ݮmȻh= ȉR~8n ߍ㢁,\B֔H;h8eBj%Gb^\Aex<(zDWHoѹ~lY2]%~/}؋>fD=U8M{n=vt0aı %m _y¢%djU 5Ne5<>N \D{_\n2>Xy'5.Ӡt^vҏ+%o:Y]xʳnE[΢Q%Ӽ?(.m)5xϣ4NNpZH{"~%١.{S>|ӤJev֭69*'׳]ld$ $M HM %w[X !Eh<ރa|%p8&8aN`֍Vq)ʤգlM\8/[$UʘP6H$OX ,*A%c'<ʕ%uE)6K(&^7yKD}U7J|3vkdL԰Q֊y7m4 x1Q L\NIRj "b,^wx&<[/๡M)4l6ڣǧ}B7ھ<еvg+(Bik.$LՒgq?9{NqmR̂΃ẍ́JsZq"{ygcDeD0rxHjD.b?z;R *C JƉevȊhi}/ɚEuE:&}=YNוg,Le~[1g@8-`K*y΋(b 'Ά9thxt3CȠ&ظ@Hg*ls I8CL1yBe(ד.Wa{XăX<@!/y!V j֚`mDKQPS"Z7qy+r qI %lK$lSS.k\-t!$rQ!k}Wt191=b_: Q MDgk[YfWbQ . s2`K5qga G5<,BBȺ%}g;isCm!P Yr[^ZKeKS3}V}앂], }kZ] nV#xe" a!EiR9#zlN&6=.BWL(Qtub͋ `ċoڋcE/{#QBR^Ƥ8eFxΏ*$Vm2'>F3zYVy''.+_{P uF͋E$qá!xCd`E1e ZǡƦ_N#2ƣ62.ӹQm_]jX,AJj_D^p^N6qVި;h6̓G?(, f$TfqAÖ4+ȢMB(<+й@ B!O0+/ |<΢>ɒ{񎟈 50,[RmXS2ɽ?{\׾Q;pggxrknt~fts:3=+V67Glu֞ɑZI^w9fQ5% 5DMԮ,0aЏk294?4?5;&ƜAaUa'f M)[}!8޻&΋~ b jhFќj[YWmqeg%Wjs+V󙿽\>_~doaҗ?Ë`w= քߏV'C'+/+یT7,lڻ/({vC|nOp&Ps8=3(eXڠruF6_M!R:](aQlb?2;h%( p:W0.ycjr[mW̩~\9p2R,&ɡ+9j9*mHb.>E晶#{%.AJ ڰ*vC&rhcTJAF_ h 96CC a} ¹\-e&a1O6nRomh"mʴU^~Z4`BqK9='K` pa}?l>_]q`>ڞ]Q@(3d>ؾQ j#GMj&r(Cl"#8fA(6-v/>yĕR[צ+z:bm 7/}Ĺƹt+W o.  3s.Oхj\n: مȅjV\g_J'ԟ º!ɥZyqBy*(R I47c\sMMJ}+#Ԕ^I_.{dCpe,kJb-SL\Ζ㵣2 [-^ bC)\HSӔG m|Y+~&`m3^vR:v=\n@\Gm$k'ez6a<-Μ5Zۥtwc/3OSȚ6t9toݻ d UdL~ѷ-[HjcvH[;ӵYt[ۓt[E Nyk=~'Oɽ^8Vߵu !5 IDAT{ՄO=r^eV#|Gg !u8|.w6Eȧ$pO|߾C/3x=) 9~|H;C>kDg :>^@13?:G峏㡝J>{wBnuur=GFQfQN3{D?Px.הg(nG;b 9#O|{Dzo>Bb`6(oc6Bx{aRAvgÝwr.7[toSx> ,;ur"En+rxlᨫ|#Z{!hhEڻ0 e^n+{#ÊkCX!w|G/CG6L]NR'mԭl} KFN<8 =10[wn4>p8v]ݸ.gG/g@OJq ¾w6!-OCep+71"Rcv V֎l 뿫A@e]P#/@@>e3H܅H5N\yt3;{w3Wx  F-eS+zfrXpH`~ӻ.ӞBLVݞʨ bsP@`u  J-6 'L oOotQ'2PiV1{"8IfT2Y5un0:Si7WRI/Ākַ}Ч44N<5 [{fc5ALF|w mOjKݘ mlD KۮFau5i뻛P$wq3#bqlzRg"G8lؼv~+tkSz{K^mҞMKwx(j\2T^R:B컫ۖX\v@=g;& %# n ZK+&f>p.EvSBs u=綺"4dSnwέv,mZ=Yn`&˔2Uɂ0Ht9;>޳0q0ӳw#BT09Gh3&a~ؤ#hWf<Q~~&wpE~Wa]@TLaKv1IU}P'ޟ윬wYh51ω8Rkyꑇ"_zؓ;w~sЗZqNsk4Up7v@UGʤj7=] :}RI404䂱'DvљL~ vBcYc>[:/G:6]ݮ654צ̐Z .:}P oA324͇g掓nX~mHrV3ev3M7 pl{c JEbU=[]ldgB"Ͱj\ Y\]vȮRX rJoH"*|rNZ}qb't>~F<}}4UyYwIPձXKZNOG:+` 0ola[P.\=:~>ۺ)[s槱}5ccS{!94K9ר X X^2r:_=vp ck1]2nR ͪj[Wo!PoTozREEE5EsW=ݜr۶u ܘr[N;j#kS"4#j]Vm,SA:&l55-n}Me腛Ky؄hnLӖbWlY `j[%ӷc{رЪ^]^ )h+;ѿ2S%k\/Єŵ[waxL{ h۟c+dWɶ2'01jmՊ>9>{yTls,ٓ)]p>xZ4Y[\,(kjmm=GnSt1_tcdpa=SHuBRu],HRΉoE}!K.㋚3 -n:6Qy&Vu]ug󮍪Ӯx"Q+K$.,#-=6Iu?M[gb-8> b2^h,.)4wu&ڪRqcpqdr_W}b}|͉K!J3XMb.䷡kaxym'ŋ LV)ovq A[Ӱ6bl@6>9&YH??TX1h܂f~Ǖ?MZnY}c9癡՘8:9r;1̬ry~H֋eIםase8]qם pAO<aͣ$|jؤt.&*{l𥃹U0טP.D[ ݲFFMkBDPidxsȭRbcf(_:K.V=Rwzi詛:uK.>&跠qw< tfh2/q75?6Cz?e18vk[΃~"AU(M̅T\\}aY{Vջ{@;S,N!``M%Yi/F{|ksǟ;^i܌g2kMEM;; >rkr}x?gޜ=Jk'K/ K&rnI& Й&`7&'r*x؄ݱC55o7z}{OLk|WҥR[mHtӾQM8 Jfyh8npqc_Z$閼Uɥ?wtoQi2'.#V:A3i-YHO$BFH&cXS_:mWZvuV*U0̧r5>na+y84[(('H Fi{%N!KtA`&qmc FU!%*xʚc3^bZ6dmOtips3&8U8|N9[;Cu~7VoWC&ET:ndOyX 8% [L mZG+sNZ &rTX <0SѢ'etQţ@zYz9(_+Ő6Oiח%Wc=j9 @8X _-PvP"H\x獟v\sGi xue^'UiMDTOO[f_^];س%hlsGBH@V{&x=R,'R\Ȯ:\paL9=Aw;^!J<ߨbEXS;tD9&49Q,h4:>G m벍7޹.ŭbk62[W7w hE/4ӗ2B-*{% w9PXBWHfi"H L!oC4x0OMf)~M`'o<2wb2֒~a髲 `^3*Tv,(i#4-pENO)P(yJ?a+ss{^?QW?G_P|JTߑ߹!iUzgGw8籴䙟hxXY9D6t$IֆZ`u`C\~Hs8-mC Wbkj"^&`N[-&+C}(ʯHgᲆ:O͔ )I{y2oa:T67>e4]X~鷇.K̃g]߃wW8z*'i)*}bKɤ+ l-v5(B/^D(ߢ{fS&&<ч?\_XsWVW-1730/'a۽"!IOVKh* WKEj6؜JJgCʏA PQ!P&eh$PXY'?V*+ $АKni~}E?C;&Q%OKp$bZVeaZTBQ,ooSNzF!(=t Úar#@ +n= ݁CP۪v۝ruEE(_M1;$Sl-ra9F*"t@P>df=2yQ}nG=^HweyDɱ4M[8/zzYy0+GU52 K}39}sߐh_t5VnV]lq+Ґ:0s(rJe qTghr,U۠R&!2"]Ny>:Z^ lg G>9@ ej7҆ }{%Tc{ ΓK'H#pp| nJ^ 69 `bJkFsA0FJyaWYcQoXP0o*(sv|\+kR~[mF}]D֑G[l/rE?J]z≑;KP 6~痯weB39EHBY 𸗮?/x"8K`8#^52}rzh7w~o-6\{ɥ]p{@"E Q>@?.˺ސtmGL\R!4|Ubg>,f"*yP2 盬*I(آno~@u;'y_!%iܮ㧀rb9HiAϾ@,@FQOqY!;i \?Ky,k\$dse_`+ PB0lhp !>Eq3(Je'T&}DhìK>2MkY&Rp|6k- >&1+9O3 ـ=M zūIF}KXa YZ>۶#;S)%Bf_㲃dx&(#(;} P*ImQBU*+i^I %vՐ6dz,>P% 0FPjvrv}{G7}X'au?7=Y?Įx6{ܠTpYq#丿"<K9MT!8hh4$VF /bLPT*4;ֲ[ l_k|obw׸쓹M,@ ;^@k>(#J@hmHx?)"DʩdS9{-> AAI4QTߞ@X%)WZb\(YmLC90}~ڋTJ{59U`DY@T@,Ƕ#~Ǟ= zâ9ZnC]I%i˫@m^Tj 8qk̫dbe6W~2L^W$ExXʄSGNd2,IͰF!UR9} +C<'ٞ5iEvnnS]}{E}#pjQÖ]exȍf3q=29`d )>A9UPWU(~y!Zh%}B w@6; A;#Pwl@p8WHF|JqtkK`6Hxr8@Q9_nGh'V`HdQL[gC[h걻&h1ʪ$w-\ W@]%aD**%# /1Vx~]QE|*R@T IDAT4 nIH[P$KH$Zb| >d{90/E`+!-,jWB#eP2`3@s(Մra]J`>7r%B=D"gDٮ 4^`H$#"Wgh II@<GpҢ |UNP9W}(6e}aIcJ^5I:,ƭ=}{>ˈ&c]UV5!@%,!`GYdz!|4 91jv`1 VZ{#8 VlWc޽Ty¨=cDw@tކn[*S9,V"BD<b$Ǔ~M$ F.ӄQ_wo `Z vge?'q"3 qi L 7qcwL*ԏ B@3vf_8,-#X E+b!aCj!#?{Ԧ´wi~}ԼY34o69?pJXؑe#$KpDU>r+ rW^  %I:V8b@"r;q< |;Hܧ {M2yp.e7f*9e@ UFTTTlĪ DXNXVl4Ȁ蓏čFҟ!aۄcJу* J$N:m?b_[->1@(C#Y9-PnjXI9 ~FIܕ8 PipU:I`T~ pd&UA-KdHMa ]u2&'G7OK`No5я 7J/ޕ8Xi\| >LKݥo΃3`و$l (:#pr+~ca}8r~#A8%ɒtj'#'`oE-US 'qe>D5W!qҕ5|(:I'AsS~^,վ珺%s>ِVtĊ!ĿOeczCʯf๑?%|0Z'm^{Fv4} f,*# p:gL<  ku2dU+z A|w ,Z)WiLonď@Ē] mHQ f"~/4ח-XxU4 bui.@\h (:-9 JyeAA8>ߨ%awߝ߾d;Dhw؏VFHz{,٩yv̊+JLȧiԯ<w; *|PgF"22`2YȃΈ8 C} e jN10A>2" ;kp]U,#J}!;G~Vc^E od){v:'re@{_OLrU0 }ف"3+j`B 67XPc@<b|ygt-F|)>^'O ehgTvh~c0b}VR^CZظ `P>"{ @`'5~90o~F-SZ!)杯eE#4jUuA"U )L\DuzڅZ/%5^M[-Mh?0^F#@>'0pR#Y)j2N)! F]hlT6QEJjM:pPgF;-@qBβP ֈ 808l(15 ~rxPCo+qk.a{yM1|-j_ %lq# mA%| qR`X.aμ;yސ1\-@yJ -Q2D7y I7>t`a9wi: /3f d3F922m$grYx`U/(FIS$qXCHΣT*=sB0|sMAh(ܚqM&R>`ȅ:!Wy8n 8 F~Qx ͡Ӳʌ:~݇=2#j/m&*lVD*|q.K.MqOTA' qQ @mTb$`@(yU2ƁAJ0~:lIb +3V)aPG"\;+ 4#tW/awUpFY+kg.ZhZhF8W!s(q9\9 FYq7xoٹGX LŎʩ騆3Se~>N K:fyyGK+Wjjkd5CfstmmxLcL_=/zUxN_#eՈ p\gI9 lp$,bP++`M2 p+%-*Y•1멢LYG*T>M2Id "oGb+~ȅގ3b< (#G U萨41HMϠlvlAP͡'Ad_:Pk8]C|ȑJb r6[;c07`bfLXhZX0t;{sM Z2Y h*@QOP!HYxe)d0 !i;_cjVֻ]fWoQƦl*Y8F>YuD:`)aBch?l5E@Fmg69Wx-ĘU2Y7%p2\ ÷&DPEBi9ZI%Gw 瓔U30ٷpRK9]+Iɷ `Aiz:(ނ)hdE ss`lʙRxfހ09-]pn?gEw-O"95Rzhh2,Efv[p wa_ 0 n10 uR,rdKQ*,ٵuTv{u2uD۔|(`ch;-T-7V"gXB y6aT7U"EɮI ,{ו̾t%1`~,;wkES,S`| cf 2Mnt//#%Ř wHۃ%Q]gDDϔcvЛ a됱3;|i~%rð@gW%qoWq4QA(pHl|/x]c!:̻ &Ppe \X3)9nRcFW(/EkFCW85I3,cq$vGkwJMl0,C/vOew.ÑyAE#O"KT3?NarukfalZXI'؞Wⶋ7;Ugtۤ16J5 ;JʨZ:*)lePH3F[ [Oa lgwm&mk۟bw?@I4DW29m46kk0 L^7|{aޢIjbq]q%-+6K.bE2QYv jvv=B14 DTUiܿ!\ n֘+ G&*+L6tP6d:BP~cqp*Oh. Fs_3Ui.Dfgwɯ$];8QeVfOo]~y>%df\.iσ7S}3Qh8o4|K|N.Y].ޱ Ւ=¦ŻoзD?`Rӳ$()@IيTatb' *mșpHrj5wr@y{=O nނpzjfD!jz?gkK1 p7f7dۈ S0Oɤ6F\`綟(jNI+i2|7Pˢt=,Ԝz)gOdj ĺpISe̍^sy79j+>܉u =} BSJoWL!c3ݻ`RpmU܍;Qû8 qR&\ulVJnfI5=>/` w?g̑KL:Rhk$Q:T=~ؘdKTs0^XfϷAS(єpW51胐TNv̓=gL E_30kh7mUcUU)"`&s.n|/iq!u諀J$gحYӭ[ӹŒdYbh&Srs{  *怏<qtwm0 3y#94A%{I|-xGtA{; s@Qw EA92kJ̲ڒxTP|#S,]bT($lM=d@VX׿"67OL7Jm,`ֵhZ1(#1ш2 otuv͌I" PP KQѧp$&@ q}T 7 gmRtA0̑J:@wx)+4=y2Id8O;LG0MfTrkE(̞壷dQ#K}:T c%tʚLN1n3SY),VBLUKZa\T =ko|Qt,R[Md7HByNSF2@y+hӎ!.XѓN7JR\h<@ T5V@a#ٰ}&8{6v3GU % &f=";)a_݄| bSKא>^܎{E%ǛYoae3Kȗ h^6y|c}!7t0![=z %IE~| e3KXKȗ/!_650Gϰ7t?)=l"r[*[y3䡝om5x{R(˦7ZWJqR&w/`;k> ? rRqWqZi´5\س|{E_![~hyR{LWI{*qAGv=Y{mvW{χMp>J:&,jL{_Ã~f-L҉aM?uΞS;Wg>bkq6Xg5b|^ 7?1&,c!$Eb}HR6^i|F1];Jt9d́OKg=o{ g ),`dykdf-w- LݛuN'iy=2[",oeDVC ?Y`b>,I2u?#Srrgikl ٔKGڥ7-dv IDAT[?Z'Ck- SW_@;!Ji{9 ֪igGSž[;v׆^l8q[0WOc)šcG>DxT*1`s@)hzM*q.aޠx_|S(Py'2E'&n>A8(1Je`0LQ+i$.JVS\TX >X0ʺBEjSՋ>H7>9(2&kP zWq[&j$OW9z#Z=>DMg8l(<*tw#IL[ࡦ)`n+Xi(Y6Ɗ]ҪRt^ŮvDu;O]L/6lk L])dRLve> /: GYDַIDKOtjuXRabC͟|r4(Ek8~3;8 B Ȧ`TdEEܒ70h0Y/*ҁeM5V lr,VŁ0WB;YGվ31d<5W6ݒCzhمS)&Z 7YYڢ2n3ۀ.h\nPژVܚ-ݸ_9|n?e"4́gSW\iO~HL=)`r鯗ObJ65žU>όƮLa {$O"ژzYe0b{U슼LCx%s[n_}l|hI-EdSgB-AkyPU\|1Y"#0̴yruݢh6`Ŷ_E2`3n*wT|3_ڲz{- `js-KoŴZEҤdGPPsE'Z>46 loE --g= Zw%xIE{d9,=~ՒsI\/. RlN?EԒnX׻li) IS.& s撋?y\!x[[RU$)-;fgøPx&Kލƌ-k?ԖK˱[Jb3@6ʏ"Bjd k8^ 5XyG ً&FJK&>)[(A@ȭ.J'餼(IWbx/̷9%\D|,&(# 4Z%U?5bQV) r,[LV`x~ wJK6{_&qaAvHkm ^&L!?I1U *8xU^[tU'Y\Ի7 ?yz5s{e4-oplTvzjmNҒ26V=_U`=c_`{ȓsBu~4]߸{ q8o-o=|`?!MF/!X$.EYJS\8+[:?m)a S0hRCWZ[\2-:]SOK  ZZ˘:lw5>\rJ7:Z֠ /Zn DT[Ln;15ΐIEa TgggnMWKq_d5ϵ1v:{IM'5&גnqUm^ mŚ4hjZWw dr|̾yq<5o6ٱؽ&B eXό8P[VLp>,+ ҺbkJ=mP<\@&O=~Fǎpu,- vF|ftqƭ;vW+vyֵBMV_ mhhϒe>Ha&T$?{R\]j+m#b> H\OYU%.QGɳ~9*aU U` L#tah@{dm3.=`RD]~&Jj|AtW=H-([(x?4}uyJ۪+`~ع\ᝯuhTd(tb̸Pg8'gHhtX ^37*x:]ys <h!X h)NyaTs|ݙ)7etmE>NMdF^;6%@SbuBQh@@]'ƮZعmIV-&@T#fjE%jzm V)ߗvuVfxW^DxЃl֡_Ǧ.wAL^mNN^ņ$%[#O~ٕ,z0(WfhR VKn@[Mr #j烈w͆ ̭AZ3@e*:]kN۪յZl,gJ[ 1WCp&6*jV+I %)݇M/clf-y;MlڕpҫE&^lwd ^yM ɞS3G^kIKKiٝ7Qz(T(g(kOSeamB{HLw墡&/´wgL=:oQ2Er"!a|g~pbVm+ZZMc~Df>MxdV5P ÞFkDMm]x7)`Y~er鯀f;*!vYwajg$+ӓj V-D0}jLX2j(٘p[ ȵU*ŘUOٽyXC6wV5%I:4Wn]xwyg'hD0 -kQ(퇱g::d5bse}'2MTlżwz KZ1f+_:tvZN;|2uزLT2tdvMvr/zAEE\ KfX%6yp Wiw T ?EyP`jF1Ԭ~x·/^]=W U'V+ߞ4tNiM)^XH/G=a(j%庫ϬU{cg#)^)1m2BLپ-J61k,i7IT5=m_D c&sn^;w-ע&B\Lv<7/߼y~Dc-3^ IɯܐbJL%L~mp;O|mY-v}cؙcWuމ 7VΎ7`usSa_ƃY+ę.ڔAlr|'L1c%c7nX˽%UQӃwhO:}iwɺe3%G̓G0o]La촱 ޽QmSXx&W]ŕқ պ|ry7|`8T'uy ;#uQfr F oz N 'l(pk]_ov%qs& "4C@vheeCO4y[-M u'FY(B[ϔmQcV~4x 酥4v-~Uo7+dLCg,K & ::ww|w5'nU}ƶZYJ|}k@7GO__=_ҭ{E_Eh+23o&0EϚ(b _ò΂y2Y/>xڵϽ;riR ;[%/|VV5~3S2z^zoC zCSMNaeǏ6 ?z^2Sfk&Lc=1{/~}EE5_xy=oI\[i+ߝ2ڗ6Tx[s'68}~*>1M=]̂Zlknǣ8;SoYmi.Q\[yb;o|݃v wagZL8֞@e.\7Dra~<[0߶9ސ?(|yu:}'kE0q1v+on`W4ߌ 幹:=׽lV&}ΗT;{Q@| ZۈMQqIǷg`ҽ+۟u|#R۳K$J;ֹIeݯ\6 $yH`Fgt IEq!Lfbń=Kčnuao[c#1V8:^]z|Ć,}ʕ˟37kS%SH7'fo՜N߻9@ѕ?`~^sjjG|(vJ ^a"so| U+o){oqQ, sFLJMJ{`򵣘t et<^$ EbIY eŲld 5>zުH IdqNqB=[xdGmCcyWb:qz0NL,Hge?|8sg:pd Pw\_g?}9o6U.~u͠+췴 \Zwg)QL/,誽`IIaSll<;~B+>}y]Ti<9XuRdR1+k"-+*qƥ:CZxYp8>^Óp*r{"ձSC5î:\': q ØOKG x0rv7^;y{ནw,/^*\g=9_o^ovH۹ 8l'8ڟaA[|%Fu0B9C'4MEd`u;AzӋ˟w9g{;jyvlmPŝ{ذ>q :bUњh5KQwTYEzY{Li|&@ @e͎ߟݷT呣ߑ]?Y0FJng/]u]:\z7OB -KJ O,= #x}#Y&Cp=͇*:\il^хg3`"qf8[&vZYإ0I IBV:{6%D3l`sϗ'mjoϫgL`ٙg~ms7*OdkpB! ț[\QMQ Xuj& EFn"{Bl_pz]o3 }=ӹ V#x6^q|%䥃9/_qR+`OVW?_X8rK%/ajVdulyGl1\n-YLƙw@[b{@ȓ,p҂mSƫ4;?=޾V^ttu<ɛ"7/p磌pYIo]x[I0ipa@X,;.-Sՙ;型ZśX!qN2]K]M \]:۷SՒe}3T_K.{{o:}p;Fr O={3\tw_iOMHżWaBxȇ1&b9LK̐dZytK/o CJ*iD ٲbOo B=w9ٜwY^[S!ҫ:7rW% !@g 0 7΀nw8ZM"ý= 1i|>ųk@R/?x/5%da ]{,d po޿?r;˥?>{i\g!Dn֕ SkݯaME6mYov)~޺WHB!yd!#4f=()9XwSGEi_ё8NKFQÎ$oR..fmQ,Uߥce 1w*ZTu(:0`ahtg#&:Y ٮ̄~. Si g]^fzsM?k;/^?׎ܿ;#g><0س﫮_];={hCkK{jw E˽۶|:جpn IDATؠ<׽<7=Ayl!#)(Bzg2-0a #9˟-).nTMtt\l0$$I!.'`7x$֤PP`HfF'c)wu(EVt.ZΊ {}y5w:ySnȲkcpׯ*GUӿ8C?ts"^.{dRw>Yp37)jmfyM.5K0c>VIA<}x fU VG~쁑7K2P~iPmGO4L[?'"䈫n܎ڍ:?04٬7.,EL4Y5BJuV8v>^fT\00Qpت9b$ "գ{ *@«40- 摓@flbL]oXhl ^_>GW+}ng\yc=QiǮ?8uAVAKA|>ć!8X^+2Q2Lhh!v2=ߞ8sWJ pv|I38ۖߌoHl`aY#oCiI_@Is)!ed%D"`։h x)AP^?7Υ.OyT-`2?JLtVƱiѣ vtv>>:;{2Bҭ^ oӔ` XTӯ׽UNn`bKqxbHK`픕 &?H2CSv ߾ /p&6gUUWeRaIf_J ;wf<;]z;Ucmgx镇Vlۭ-.kqt`!{x;ܻk/1Gk^m\>squ55[RPk7x*<ôO26uo,sQIZ(HɜD SY'+C;5gÁ+r.lPBSYpGEJV>@-fFZz+*$-&vVhan1XXgtFETњ7 ꚙɴlf}XK8pmmLpo8'9{]{/̮SV]U3Џ=@<ƧwRj<.nlB  0B :;Zwyyu/Zi8Mrҋ7oqhJxX-P5 CF:-x, ܴ&RasχhG0 LytUvL'_p ۍ'jkKK P=ʇk}kbʎܸ佁W-9ku]z8PZ⬥:V{Sflnx´_G, +j&VD!S 0 {99za~wdߖ箖cDtK,+\géz&MChcT-.4g6E'Ei1,pUST<tZEXatZθU `pTqe#U]+;;J%S?uךS[;{S : .;'&g[x"t˷/d M!XQd%H~(R@IeLR᝗ΞumC}#[@Ŋߐc`lHS#dڐ(KHgA(..R`d/-UHK 0p]RX<_愉0$3qwƺˏ_ہm/gQKg^+k8׌uֱlSmؕ\䣛;lv:@-B i#Q|3Õ6Mzݭڊ Am1z7aKenJAtYJR:giC,JEv,B I'+ZP3 ԇC-2ZKRsd zJ t/) r 9X9rZb!~Pt?x޽W\G6mX <e=S'&17-,"Divɑ.{Xojj ?7R_Tr=ںȎ5c \: MbPW7*f՜{:1Oz[yE JDHQU^DYyƿ W󎶭6lNŐ7S_ *H/qtQ:?7QV{R12z& ; {A,Zc[ H1`$Ӧę &51'"+iYI@glBX/W#]*0-Y~#'BxȪpdt4?mꯝ>umXs-I^ w\8*OShلNH2 n7g>@tv{lk=_vNς^6YWwFp'fHy0͕gVl-fs+FoU5ue"&DAٞ my#GK^TirXhxB8Mۮ (뤅4Rh*miIY4ZYb'h0OɅ`$3b$ HIKLLE=).4Ku,&+JQ43h9-53xs4dء}s>qCEOvO1FǷY{sA5Gr:4u7~͛[:ő[oĽAQo! "єnfGE& <#lu{/( p,{"}m TƂWIoϫ͑5_g{{u0rKnkL`Cl%)Z S}e aM#鲣#w_wNÛn2CBf(&"t:Fk(d5BU(ip.XʊRQK(8eQ" .L"RahIih ^XMK I~@'b\8 d gPb^~ep }13|Ol2',\>:{pZ,o끀1||`2뷃 ӭ)3[(k]v5֟:Ͼ.B$zL zd5Z OHb*P&{Y,T&.{"SHvv`bDnҬg,'``dC,KѪΐlH MJ2n]|pS8S[>RqWeK'S%s6kk9#SN->듚ֹܞWb잸h(AU#͵f&]Lu:)0Af dtVW|>ǃa0.C\(u$,kI":FQ˪QTGJYAa,UUJ$d-L4ʭ/} 0^G|T[6ϵ^GV>ig2)L0;|*ХF(d<.O. GVz]mefGtk¯+CH4ӠRX=6*r;h  +^4/eSU$J=&huEQҔ(3 blNO[Tl%4=Ȣ$c0; Yza(˄Sl&sf׮MӖJRVN哘vw7(|7s1Qߍ"&7c}mM!_h &m2CAxq(P >JTb^Hd::fx4!i)V4 |7jiDРh`Ek8~H6mJCɒ6, ^&i=๸Qi0BnW֮\ V]?zujyug>18r qpw[}7qFuPY'Q|5;ss*V}mO4яBΦżH_9rdcVWda(UDMZu>@*QƂ. Ia“[« YPeK\+WiiBFiYb|Ȅ`S>PD9MR&eJRєA7N lv x@u.igvĽ;M|b%z{{l9^x^œ&IߗQ=yJQT}eEw ^(DQi/M!Ӕz/);&ɔn ! p %<%5r3)XTATBmBB&‹!)M|iBK#xp[*I<~i{__0?~?\’킟H>\m4(%Sry㱛')˦U|#=s2Ei|x`$]iqRJ 2@$l@Hp 9t=Qɟa>7hLЁrId$.Zy ,)K vEVd\!듴! yZDQl&D/{|3Z>Sؤi_vmuѻIU?rgzG]۱QXP<b߆+Kk_Ԁ9C̟gҟ `'!#(м™@RK ]&!̐OYEV^PK@ AP (p^0<jH b7?|׵Yqcyre]ym6Qn;q}[ X]c/GcH"0,OBJK7NfoQ*$MlI;$ ܲ@$hIQ6`ʖ-yYhQXT YQ[N2(F,[Yd[ E ̙2 @ " 6}jյ]u{Wqk{b&_%~K<iK?މcb 4Zg(1.,oIv PoB5d&CX!;y4aT焅#<6 &.:>)GUsV(I'AɱX X(2 7AhFDD<JmXLұ_-_wk苵ߺs?Kс Pw>b%8;- 5 -\+جJ$Dn'&@},}4!ip)Z<IUGD4fZeˢ[2깚"B."t1 ;h -6+`e nE(Mh.Upi۶slY}mֶ>n/>F{1,G}xNF(DVEЙ"%P|ܞ#Y @X} 4oM1E51b@(O`uI%Ҥ ;IB>K0(y{ӖkX*B4c~#xui)$$"GfY勸ǵ¸VWJ+[a)x#^RwˆW?;LdɄ@# h Ӡy` D2>EOj<$  )ͫ)"c-GήW-fK iMT}`Y0giD ]ǡH{]zb^vq%Qz>#n>6&8 IJ4E?OwvWsOn]4wp8TZUa IDATb!x(2]()Y0e1dMV 6f%چ$K(v1vF+<.S#XAmol~7bUpZ@J/~yS>7Ѻ}M)T6%+gxg6KxOVL>4p{N XNzaJ](/򗻤ϟwI܍r_\ $S0)0 ,S|v"f E1'`t&+ $|ΰH'[` Q1ŝǬCai"|FVƤ&߾swM\]mNܣ|XbGw)xw ߘ:Ƌ)irC[zpfצ7&io– t@1!sY'HD_Y`iwWl}%XZ'X5(x15ĩ$LWe7M%=;/1uNIc8!)40h`lb׬p/&x8 6b@h~à Ƈn؃ 5/U~ hӖE~;$S)NgT9x yrY穤FX{metR%ζdAՊ B/c9U}G+f|,D({p%il4lNPى_0zݽ˲1VSbi*qBҦBphp(f.k~)W4ZQ#঱|1_|~䭃k^v}omqw| >DƆT Xw?) /.Ah">lĖ*|>=iݮ Z x?/^w{Rs`YdXn'e3TA\aXĚ5 ,!4wIU=K$ @oE-I*EC$,PiExapu- ̋Cha,;< AQ)٬6EYXTG?ޑ}e}Z܅+ 8R=A(Ŕ==f7fƭq6 {t7*-[p8m}T(3%Y E0ҭIF\KudX'&jݲ ʒzP(@XGaYH*V!Ii" Xm ![kُ}E uHSgǷ~HW~jHn$wGt#uW yPD1n!"mi"_l&U<"Ozwf&$;,H%4 J qE#[NdLِ1=)4$/TF "z'vwc SjWDU/ VULˆi-`m'#mpDj(ާ#0N6|&mYaprQQaXRk:-PXബ`yٵkhHLD {lA UaMRD/S=ufOkALfCB`V҄^&>R2 0J,_/~NۣoL.H/ dP(4e^!?̦yɐqN)w8:)nKwԪ'OXUUpD|2"&!23)K()S&P\lkghT0I%i+UH(H%s>yO~B lCix:'k^Zy1z'hX,(+ChuL^6MiD (ޏTcނ?ʸ&d.)-q*}I4(N}!O1nwEU^UI@z/d#ʄ-okip@Ɲ ۞.;C4 <11s5KQloLP.B "<90@2;{Kʹ>VWu18|W蹟0+Ip" `ƩPVB&C J3ݩ< !$HqS%٥[+nw,6H24Xж U CFQEøFMt) xչr02B>P & u8rB&*}o5h[5"@j4(/e$%=DB RhX){ %ZW=7s E\ӃXYJ<C0 P(c8xӧE(UD 4m;ȘETWWEf9f5r>9o;?+MjĖ b3|Bflh~'|m`3€Q D8P\>wgggGEvxRlɟA_]Xp `JV&~_YJ4m%֔_W7Za@ə;']zk}0@(i`Hcd)^31# IEHVH4t6QUDۆu9O&NPutsai=bѭDABR8a,t_RhY:PvۚiW!g(3{Th&U?9QGE/NWD"wQtZmM:Vz兓!YJ T P IGXoB!hMqk`?d*S`EkZsjwnIZQ bS4fѤsTI˄V  ,ӄ,ܓ_)xrM @5w)>X2x *7<.~Fj쌧-+d6P0mS;hX6ݯy J_eM+ݣvc..ty5b޸h%w]X qW.,,,ARKE8h: )8)w'/x#c0gh;u4x"І{")6 F9@N| 7FYFbSY ##R9Cu]JZaV2$9D$O8.JÝ0f5vɳ oN]V;%IwwozD^ S_p eu MDHZy.bL L$%" ځDS* `l[zLЫ0@pFlʲ`SxDHG||Yw{ns|ixxt{gghC\ggnbU=:';BxGm S`= j(lP! 8܇ B[~ yHuNVRq2DJ8aȝqo{ܽ8pvT+LS]lCeםY҇@b5xXu]-Kc6)~ bK9}݁o48ɂx| r E|9쀶s?vyz7pCXBiuAl -{?V[ ^8 #7ļhRu7hq3=sXWOYIa@` C v1ˀeKc@x!]Fdg+mT8ps(X[cc fGD *gfӔzHA*qV@(iMu vOk2&zylϝFd "(p?3qyv,->HEMo"w"Rj-ʍМ5#x.1Oo g}hZ*狆g¹ey}#`m=B, Mb$iΊQYD7HBu;͊lnAr6T΅*TrW1+w! Vr赿[SNԤ&Z-\]к發ZPۯinՍ3Ynf+|ܧAH>CW#qƶG-iVYnG mR;K"́MyW#B؁,F|(W ˆa+"oxN& ٶmglY[qj;c6Sfس3(x< cyCjZ׵bֵ_n u԰9- `\.n$Ֆ'^֞ ;熈؟7VT2\|'G"ҰQ3>LŊcC#B1BQ@aktaIŰ6EQRP@&l P^v䵩"ΐ1NULb} ڞqsEjﴣ}`Cf58%d4 19hMLLyrD-\K"gtBy#G-í;aS*N,r. >ƹpUTOj/ \ j1&{eW%CPo{>&L&fWH$XU!a/W3ڃ;WDyw B]&S<U(:Ҵ53 n:&ګD)+d>^錒':h -Մ8b 7p2ScSh2V9Eow@^>¤?hrS%{A{YPG"C9H7ڂN )H*nIލqR׀VH zPk8&+q3>B)eǷf_^>c|DZIp/!fr22zIpϙ>OdAeSFr6 MFu1J?t~)nM8\Z cźSIDAT@͢eL;K+^Tk}ekB9(Z$\Gp@ xw֘ x=Kodzǰw|փ?x&ܴ+at0  AP laj9*%YiC!#.{`TQ.r 9M"ᗷ mu?/Py&p ]jq:8u^;dhze%vZ{#g6ȴ޼``lڞЕܢ;e.Ғ57+hA983łM6>6 A^183lpkrF2eF|>i8N Jl5Q43 `i6s Vf};" VvVE߼.pE9hMWRIOզ37۹|2&uTjƾDn'^R͏[u/ Adbk?=MROc]nlZ)S &Qj61rmP5~<. ,&k׿)ʿ3-~"TBkaCNVB2)o;w >om WZVOrGh;{ \ϙOXi Dz@ ݣDg}zZ[[9YDWd:P~OmQGM!dwR[r޺3 `#ΐP; bdF|F2vsw?O 9McVSTdmyW`SYz#eo?u׋t? uVHM /NړT;N.#&3+82տUo0x Y=wiL=d9ǘ S˒sCB8RahZ-\s{>,S85oըw?%%:L@*a!%tg_7&K2YhWwqan~E<&H)L}:;SsW,Ϊe$Zxx z-K qtDV7TԲ٩![n3ətB( FG+-М2$eB)01N=)K"RV(iq,)]Kڴ9ͻ5QKa;*_\"wo)TV! V] vvLK1c]wR`eJb+ /wQg\V&|#|6=TxskzX-Sf$L`VOoS S`+ #ɨ8 qwEfb׬Z&kO䲤A" rIh]| B_B]a/m`Iy?ɠ4\,!p$c-s2c0q0bQҸ(Ww^[L+Z@j ~ȥp2.:=",y>49zv5p[A8b<i,Ĩcܷ0mh*'hKE-Ϊ{ |c%/@sl)?-Qu ZwY3UJL'R޹eT&ns*GYUV).4 ̪noD1AiqoN]߫g<k.Mܓ'j9vrJP&αhuAwGot:pͷ`N; >!a(?_/ #,9S+(4U{PmK9,A86)nǂ.M E>cx+kE@kh{#e9םZhM&4:\bUk#WvIr3(͐Vjr/SJm޴OYUg7뒁Ȱ6GZ=%o.a$ 7]cv,/MړdkHorjģRxhNAibzTTj>9SՁi޹[ ;W6RGǷf>{/I59NLǘC G^VΝj1I==dn>0<83Iachm8ܛ8!*zDo뭱 }9|2oqfԊ2!ߎUM;U5x}1a2Ka/MsǾ)s$k;af舡 4*Qo8l,m7:e)\O"\~0HۉDד``צ'*zRIT!R,ג6!ȇ <"JHJ!VXJ̢$%t)2M+_7|k~]Q# M'v>[.$wh< R׎~. ~zJLzyЗbL6JH|Qkⅿ3r"/jb._e+ޏcC6Y8c{hNŮAE{:m!2VQAR+d$qT{+[dh XK3!di߈AM# ,w0||r8زFd0eb0[Q[ݴr'P22nn`u-!e ,/חD7!Ƥ{*HʴB>#7߭ܮȽ<"JusesTbߨ3x(eL_7Gsn{ny0[MLo/<`nVIENDB`perfbook_html/img90.png0000644000175000017500000000054211672746100015223 0ustar paulmckpaulmckPNG  IHDR& M'0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDAT(c` `2`A(@L,``ce`])2fpX6 L PE!|`[c0L A r%3| -Z! 0a`W``d)l@0.20H/` %T0 YR~XLԠ @R f$Ly2IENDB`perfbook_html/img227.png0000644000175000017500000000372611672746110015315 0ustar paulmckpaulmckPNG  IHDRXbU# WPLTE DDff"̙3''ݦD33U@@fMM33wZZUUwwffssz~tRNS@f-IDATx]5Hq ǦR&HCA"DiIuYlBUخPs-5L -R}lVe;c,ٮ;3~(S񷬪(ZƢ8[ݎۮT=n6lkAD9c CRSE6NFm:`ĚqvۢT+>F&};E Gc 6lO|`E_qn16^e]C`yCjZV}7U3vXnk'zB≻GS$ZK0Dnv\M* [.-Y6w&aǁj >lWYei~[q "(w`eZ3Mȱ64T3vnq [ &!~۝Ctn79=&nےn[Y Q@{)/ SO^=+Yh [{:"֞OՍbN%Lx7a7UV,M,9p38[2+ϝ٩wyɜTUƄ˜`U#bc>^1]|]r!$w0_M{b4^0 i^V,zetuޙ„mkCCd+nxՋua-1'Y:WHIZ`a%@, {*n[h^,\6,*wS zEz"ڐJqL 6k+fGҬkI7C*J8YnP5EʥD ڇNeVk,[E&}])׋B_5J+]zX|X[q&Ëծh0urnȒKf8Cxb r3 '-V2!޻vۇ`=d]XZO,ht/{X(kObτ X Vq.NQG'Hg[шSQDx$ %PFmmc<>-7YlDVITƀ*ע-Yí_90XDviRp4rb/|v=;OdVcyIZ m6QI<*u+ݲPXu4O,|b0Xe$͓6'LOܡm6ؖsLꓗNJ>]bf< D"$389JG/0AWQ9a"7`΂{&IE~W8;/sP.NV (_nE#`ffaIRF'^"8WLNFɘ#%B.skĢ,j$w d3Y)b26A lm_=DHE`5نW24IQ!fa .VK`3Rf;= ' D"|b?z}@,L^] 8=biD X ؃oc^0 KcAz(&I`KtX7 L  Q^:'>@Y'3oy%ˎIENDB`perfbook_html/node181.html0000644000175000017500000000436611672746162015655 0ustar paulmckpaulmck 13.1 Lists


13.1 Lists

Lists, double lists, hlists, hashes, trees, rbtrees, radix trees.



Paul E. McKenney 2011-12-16
perfbook_html/node272.html0000644000175000017500000000562111672746162015651 0ustar paulmckpaulmck B.2.1 create_thread()

B.2.1 create_thread()

The create_thread primitive creates a new thread, starting the new thread's execution at the function func specified by create_thread()'s first argument, and passing it the argument specified by create_thread()'s second argument. This newly created thread will terminate when it returns from the starting function specified by func. The create_thread() primitive returns the thread_id_t corresponding to the newly created child thread.

This primitive will abort the program if more than NR_THREADS threads are created, counting the one implicitly created by running the program. NR_THREADS is a compile-time constant that may be modified, though some systems may have an upper bound for the allowable number of threads.



Paul E. McKenney 2011-12-16
perfbook_html/node244.html0000644000175000017500000000542411672746162015651 0ustar paulmckpaulmck 15. Ease of Use


15. Ease of Use

``Creating a perfect API is like committing the perfect crime. There are at least fifty things that can go wrong, and if you are a genius, you might be able to anticipate twenty-five of them.''



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img187.png0000644000175000017500000001277411672746075015337 0ustar paulmckpaulmckPNG  IHDR@7HPLTE^\\\ZZMJK# b``mkkcaaa__XUV856KHHC@@:67wuv.*+ltRNS@fbIDATx] e.\tdf ST6F^}rED^`S*ҠUQTm 6+95@)Uv<wj+,ߘS^KY}f4w*|&gJzHz=Dnu g%˳-O,nn, VTz>PcG&XP2$*fv**.U5&V>V&jԧp:i$⓴NպPmqjL.mOkxuy2dmV=Qn6i2R󽵘 ,;z:PVsbly.%atCbs`;hC?fb%k|WDsO( Bed 6<-ihe^ksXixQq ;wB=~5z*c`(;?Z?G / }zo.Hf" j\yp$IХGqy.RՉ&Kqh^yJ8Drq 2ga7n)Hc~/:z{U%nnk% "ՆT[S7@ hںv?CcGßt Xl 18ҫnG7WaS#|QZ*d!iQQ]>ux.EJ;bHS<=8EUӒQ5I%Z)Pdsah+o}/ʹRF왴)] KiEVsgs>ϐ0e]5J4DT;`pltCΡ߈J+H7RFYT)1KcLAɈyˍ+It |cH^ v7x뮻i'7>U)Ԭ*ME7|)iV*eˑ3O\9<_vQj9^;u٥G"rs*wybg;ևlHY8E*͘!Q`UΥwd[+_Nj͜.Ĕ#j =o's޲mrǻ!Ir'I%QRe˓(ZuN"fBuDan<\X}ܣ6\u8WQ ᠫ<6)'S7?ZMŜSoЋ3O)^v<'%/+f0?kȹ|J7K4ꪔǭ)A qbO*H"m1ŨcLE+(5tއ3mG{~3&1`p}O5< 9J"d}iUrƊg(y񣄼qy( @s6qKolsmVEH|ڶM];[^hs(wM)W<2OFZq=pJ*xOs&˲UsZʓ'n@ִb˲ b1YgR5ЉLc>fr-~+PU.CPCD &~ojSzh)MO~S|7nv־ Oc?CU)RYד Him90Fun{3l=\rTLNt?GP(-J@?+yK+o%`NeiNw\wtU7FYy$LK/[3|WkΟϣxDiagrPD;2[UɹhY$Ծ<<)Njg0'G;+~ߏ~|ƗtW;՟2_E_DhhUZXvR8P04=0J!'5سm9fSio[!-Tr6efw:`,t}/upձ~(u4v%ڕCw|4.M_T?ꧥ͸R9Cxi6߶jUE{%'1b1KWpm<Y#/*;L ~f!wZϋ^[aW K.2y]x Y!W'K%;ˇ?I 9 Z4s4)WQIN^N݊/hwJ_?,O >2O$'okqNb)N^Z;rKf,v|=ltۜ,=Z<o9DH-tL)N:gSϔyUrE(@lDEnZ:̾!d[vA@|zg"b3AfvǨ} 6)l2{1M`FK5h_d:>}8M~ Doc'V9_|* a˅mυP:… ׄ7ߩ]pF^×^$|Q[\[Caofj*BK4AVժU5l$"I.[h%vYkbPDr΀/jre-H8hj:SUG2۔\ʵ⥯sCɐ-@Mh 9*:J8E~)?v"x2.ܞv7K$(qg3YѠ &*9O6&$4`wp8yZ&lj"ΓNܞR$,ĝ1yo|w'*;U V q4GPv"$9QvOgL;›IXV҈ rO(,dR4[d&3e#(P>u IB;9:328K#F) |@;S (O[~4dW/LZ$oe@* ?[靪ZP]o>mIC (k-ӯzSV"GV(ҧ9ddY"$|$'3.%}D/"ƾ-FEe'98J0XO=}:M ΄:}:3}Z0|38g]pY 0;T6¢u"$NI/_+"ދ%k] W]9K=NP]k.u"8WGKet7ʯMiZI$%!ؕܣ#q9F/\ 8.1.3 Unfairness


8.1.3 Unfairness



Paul E. McKenney 2011-12-16
perfbook_html/node111.html0000644000175000017500000000444711672746162015646 0ustar paulmckpaulmck 8.2.3 Beyond Reader-Writer Locks


8.2.3 Beyond Reader-Writer Locks

VAXCluster six-state locking.



Paul E. McKenney 2011-12-16
perfbook_html/img302.png0000644000175000017500000001206011672746070015303 0ustar paulmckpaulmckPNG  IHDR;J9PLTEb``MJK# hffywwmkkXUV856C@@wuv.*+RltRNS@fIDATx]ao"x{=Ii:׷ک"b+S?ѿˀhH_g V&f1?g^Q!鯗qdxtTWKLCzܭ~[K.LBwsಣICv0) pn=,`\ xjߔNK}+0=4yN?{TX HYnMaݷ<B,EOX(ѥfD)O<#sl(ǒ<5/#m^NO/8 \ƊA dhԙ훸} 飴,tScŌӤ},X҂Gh'e"&l9дWE7Bk&Mk`LԘ<̭cv SS!RG:Oyb2! ;} wp)Xr`f/6cz:tyylqeb7licmrt~Ga=!z^ ;cu,$'f D'Z7-.8Ya5-NϬ)~*-m:Je%< t{x8ղ\$ekvՄ )Ze$UȆ *hE zJdu^u՟w6G2.S$ҋ(߾,'ṱ usea^Œ,&+Ƙlip9?d@Yyo]"i Z-گ0Nfᧈ-4b7m'sӿ(f d߃"q?jy7-~ߐEV "#˷b{^ PZ4Ҽw2W+UOсJȋ}a^lq/0R~Ǟhb8 A]9iEI|#/ i &nL'B^gqTl]>T'<ᰡvPܲMشԵBn{H݆!'=;iDņz/[8/NBd&8't @v&9qMϤ!I\uD?:%Ǥn>(<[nEr}35L &X(әV=+%YM<;O>94.6 osm,q8{$fNU;=:9Ve|sm7skn Bm}CuSx\ cڅChys?n =-!,$+$rՊ_{' WFngs=7Kk@7^p][na{,p hˁ#;͸ >J *sBs1|JI5 ~f,w*?( fEdHUUYҘ'c=ݖP4cpصRn;LYd~7joB"$҅ZGKxȴ넳u^&_mqj%֨|a%w}E"LbYY'& 0eEX,YrW.E$ݱUb"T@V#u٦qDdQ1Ds$YtMīQ~*m6FP"}0kw,Bziu9e*^<.ubr)͞!76,W!m]]dpX,9B~ (ݤǧ s.OC9x,Ip;1&Ƒή9|;-7cpWD:  ]u- I4> \XfV :#]`zXMk䯺@jRQjp=`k1Q0ٰN%iy+\&Mlϭ3n\TX#L$'mH#[:·+V&]3\|`k,^lD-%y3YG*}#o i=\=j. ܏9્(/[b$6\H5@D s`3~nuX+iř,OZDUr|ϜZN'I$Ɖ4Ki`M׮uNcۍ1~k1v}>}`vI~/Ly:9n'S|C~b1,e!pXXO% .i[ef6,-V~gkq8(jG y>}f3" \ϒLy l i(bP,a|h.Z.(]ɵztk xtYBIi eA>;kRvtΡ s{)SIʠ6V蚼.'o=\tfWh7 TP&aĿ)'΂oY֣kQ=B=y֣[?+v ,>[ Ҳ~̢~)ܺGԋGW.c@ݝ3NLܿţX=g_M{rgɝ(cj'I!#"Vguqsv[WbQpcG7y4'̡s~+[,d[ Xr9XrnN[)￀_m ݮh^X؜^ w8{]KnC; fuH#e;@7z#Cva9f8F-75Ͼ MU""hҘp{5~3nAݫEǼb<"OxfH2Q<;Zt: Ԫ %vovEacv,㮜ƕv-통*bvoedKӕxs[W톰9;r0ŷ\a"ZUǷa8ݲ|BX2xd=0d!_c 1,ۂBۄ~4VWEg\晱Ka)[fZ<ɃS2HP8*'=D-iFLvlL%/{M, }oI>'թ5~5Mƭs^ зVab "8-ztz %+>4EݸyKNb ?1KyE^evwf8Vvy|4iv#Ҿͯ]YvY-lT0`ǡpؐh@]H][_Nڔf)|qܼt's'ZWԎl^8'?FaYfi8fZ3瘥*ǎ%]k} z  ޔv<; Jŵdç̇ےOά>n2JSp7D-2hrF}=Z}G/K?6d1WȰD'C۵Oܶ7 H%m4]rB iNBva}j@i em8d29CIsMx򇒪Fqvu^ våD`'ki >q \DX9 Ek3Ƽ?8p6{'6M KoNc35vnI$}nMҽ,6vls_HQ oW.MK`Ģ9y5VOXWM,Cv=/FB9k>$+9U qp]DvcIJ9X)UXkNX7X'dyeK')X/{9wC99+9V>v}4:p6)[ vU &ݬ^oMv7rtk>G$+99ka?[l$+,6]dNjRRNМ]M$F{lbKNlhOKstk6G.Gה$k9u^^pjBtiۤ޾9G7wcƂ^19~=KGKL,l\/@#X& qCG_GqH*F攗aaWz&E~QxvU~;x*r\ԯ`w+M2y4])Plk@W/FFV|2S'ovذnIENDB`perfbook_html/node21.html0000644000175000017500000000614411672746161015561 0ustar paulmckpaulmck 3.5 Guide to This Book


3.5 Guide to This Book

This book is not a collection of optimal algorithms with tiny areas of applicability; instead, it is a handbook of widely applicable and heavily used techniques. We of course could not resist the urge to include some of our favorites that have not (yet!) passed the test of time (what author could?), but we have nonetheless gritted our teeth and banished our darlings to appendices. Perhaps in time, some of them will see enough use that we can promote them into the main body of the text.



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img52.png0000644000175000017500000001220411672746116015226 0ustar paulmckpaulmckPNG  IHDRN緜B?PLTEb``MJK# hffmkkXUV856C@@A>>@<=wuv.*+-**|zz`tRNS@fIDATx]EЦ6o}T(Nf "Sͥ'Qѧ?v4dǺT~ Ѩ,oD[xtV `GUD#4,_ zS.i!gUĻV´B#K['cNl/]}`|f'ȧPÁ:U)X 2h}x)E˾>.-8R^EOZ+YV3c<*y܋V,ƊħɚؘgXxbНcB'j !j1$[s!: xNZ})10GQ?&-d֋a&LWYUD?hb tbll)ײrw|$Mˆ豏^(e,d딴@CkVml +{Xm~t0:f L0wθX5$ f<<$ۻ FMu[N2[@c˳9>p{ϧ4=:GKW_$On*3K]۩ĥ1RX։Ѣ4xk]} $-Y\[P%D\ q] ~["d$BYڃ?u| -0@KE/=4NVI\T+og֚P%K%wdθ{~% [pO@"JR(/kAI|[8yUkB \)aQ -*9șI|*" HJ.TF\V . C&>(mqϣ慎^Wk:DbO;`N ֳ_'TD>g;h_ y}˚M/t8G*7l𧥑 zntnF:s?E׸_EZwHDDwzNSX|O3ws\ێwņ cXg҇P/U0m e6$iV2`Evs[3&t(j )K/X-nEhIPؔyOB6*ꯧϙӁւ tI:goK7?P-3&ulU'߹ɘrxdkV{%P%zodҟ`}Gdh|C}~E?soŘ2 <+5)B5W6 NJN2*n/Um)ެ~'("no4x;Ss;1N=^0 EE!_6bz^!n]R= юA齨^" <:_WrD'>? .F=l Lr3F䵸REd]MȰrbd;ɹ^ͮ{u\ԯ̤Mە*21,ܽ"Gx]>!DuR>dp|24ugk93Czwp#`qM{nXw?sYagzG_prAm+5~y19O.IAX=(^D  Z=>.emK8d5—{gp*TN;2!qJ1'܌5vS$d~qGHK!~t `GJ]Τ?1uNtZ%h%r b;87щfߎ^ʹ0!k67unA^~V"'B/;Gg z sXq#}LpNk[=Ӌ6Q`ͳw؝^74tuJffp uR,Ey.\+ 3EbkB}l!kJ }8{νUP,5v'I|5J^0Kg7&7МNpXIEon DCJo/( \ߦI/gMn.|Q;po z9/Ws(rڟޕ+vRfGWc'ĠqÆ|l-i"l9M-\[Y#;Ty}'`(  8  {1BnJ0^dw[s>e{S C6%2$l GOja4lao4+"N`ɁVXvMY!彭Q;{,KQ!_RqPb æq#j LYmm 5|0R>8[N OFqAbp?lz.c (S]ud[CLG!QXGGqHAP祐 B\׸ ((u A ')?;P칌皤b=lM)+(5S 3CV~4TkQV 'J'xolt稯aft%p_YDWRC(W.Ag݊PI*v⃾^J}= =>V 78uNGTp2! I!$ ]z>),mT67 ? B =D )s\LT8Jn!G9`wnv,ԝaE,-U ~*滉~ jd,K0Ngg 0 S4R 2Q*:B![E, "I&==|"AJeCDS?$xPQ[.1M?vbɪ vt0\V/m09rid`֐D }oYoU$s=?GDށ8םdl^Ʃ.%)[eAŅoNU#X"'bWU{8@ڳ3sRh);b/((u5;(@ww ,~Ф$fn|")wFUa>0zC*^]z254ddbg;3W U IWR3? z$X \CcAT(߫UYe?lj]=ƎTA^w_tM8W2eW~{x~0n6C@ΧT>1wDkGŨG7]e;[1#Z;f%1;^,dZ;#_0&M1bHY/kWIENDB`perfbook_html/img10.png0000644000175000017500000001675611672746003015233 0ustar paulmckpaulmckPNG  IHDRW%suuPLTE$8Df6Sfl*3-EUQ}}wcU3/HY"HoZ~ ?awfu݇D"|tRNS@f'IDATx] (N* x_C>啄rz\Y^YWJJ)^Ф62kT& /+2DkIIևQAy!(ռIAP罚<Ѭ@OA@znW|?(ê[$d1FJ;B*ѝQzz!㾰u%#-lK2KEG{(izFz4MT{\y&{D=+`b^'eWo[^qb-jчx~dW$kZMkVQ]o1j!8K9Z1VZYMzՖ< n(<-* V;^ԚC^ǙpH>0k mnoKeGY`R rQăzZ6>:}RSpv]= fc9rXoN+vz_hg+{Z/-zPk řPmiX(Z[jRrsi6e٭pΚ6٬ΡV65CRSuTi)5)hF;S#j- $f_00@Ϋu UufKJy?LcER"zVȕ5ڞK#L8е7zjI.@ji qt |?9ґ%IcL!Iڨ(N([VdfͶ׫nI^Azi(Tkf$ Jl~وtlў\8kt|K R8$bZqӰ,d7,=1mgtثP;[LZ"*z*$-fKm{amz5n]n'=g>6tY<@}vǒ lsGGw%/h52сT3OFwZXKb%6AC*ݢKEF`wj=?hvvrIC\A` шUj`;2el'F U M؇_:NThpqjmICDiZ9ûQe  i:cB_Qbp^M2p1K%Fnc@lviUVR}\lIS} +wPe_p&ɇ22ar /j<ز, C{ zY~nF8?=sWoGNB+0QI_2r#[%МiU%'7XpF2( (%J  Q"X:{ v>M0uv.W*)˥Im1d׆``%3hG|@A[V̨\$Fp6Vc]mkWeP|08-!_`вSš[kvUoV`>kv ZFBiV+/XxYTojo(X]om:1}؈9 hF_yd~n`uh@Yɱ `a5욓H-  ֆ_{@x˺,h:dEe`*Kbt" i_3c:̢ ع0~ Y;NC;eN/إd.틠~!L`WhBF!ucȀv? ʔaNa gf~l ߊf_wˬ[@Boů BUX#9jآN-Q\򱊣,2t,.we@T7S+вn/ ZxBh}d,V6d#0#ZkXi;:ksda?oڇj8=牝fgZCx#vͧcc/q;q,Jt4ay,ݞE7<Ȏ0R>}E{xОaC?/l>|ѓP+\|S8+pfz#!Z!bul㮑XA7"d{VOVȓ T4Vy&uc]4`NxĪwb }p1 V^gu L'l#ŐHoVneD G6 olCh%'@r`XlX'ppiV7;+I`^z@'aG/֮ގ@1X}Ѻ' sxu`5wP?gZH_=gj)e'R t*=r5 ^6֛kEpb fQZ쓞6(`-X*bM#ѿ{§BC`NJ/ Vs~Sb1`3^z5,#/=`yyT-c*ivհNjwcudӱN T]J E'UW͜mXV)XPg֔;7 ;{@"5z>@־mm;>*:&VměwCU⣽6Xg]snr`u4Z5b{{C1/*fbR~Yn?6D,UL gp1 aֲevX C/ [1jkyaeXҰ]Xw܊˘IU2;7&I|1{aKKz"^ X'E, MǪ/A6\,b嫏HTm"X/>ou㗑/cCCs6vq;P`qɽY'LAPy]Xv&V"2 V1 vby63mZ~ޯ^O}-fl F7Fː~Esw`k{\uNvuؒF7aI:L|t:nOjAkXX4ƦEb7|ܙ~&`-k')<:P>BٮkU~AguWcqBSVac7@#?b[ٽ1 WBճ~3O #bX92Mgω&cy˸kHva [pFu*VH̝(X@b`A`eg1'e̲+$iDHꭾhRxH/S̲+$n2^QjO2<q V+sL;yXñ:Z묱dKc3lq/XX:Ϲ}&m_: I2F$|eOLAWJum$+.b\~:j'<:X'lz-$`|o&4]WHǧH~f49ϫs!"eҺ~7m#o؝RqVfWF[1K4ә}}܏+o\lBv1iM_VsSmÿa w,MɊ*{EK6uAk#?In(կevq^N?E?WLdϣ3W2C!`TR9˺o~g-K`2;!~D(¨HAn?3,"=!c| vajOwi(^QCY+Ws~}śx'^mkeu>.u^|^sQ;Wsv浬2XÀ/:Sy8l,y E^eI{Ė@^a. {ʖ3C}vE ֗Wn^(O[R.wyl@/M~CcxR^6/^]yW-`U^3bCUש: 3V)c-}Oxl?CT]uZ HIij;elqqZga׼.jh @3xf{xgwl'UN*k:| ]Q?W"f{`uVבk~JEz0N^G6؋.TXTwfƲe_RgM[:liEX{<,FcAe=Ai Y6kcNbLʲۗ'~Nݿ|t ֺ#C :jwEw^]2%OڊkX5浢4Սlэ$)zzui. lqou ^@&$JO2̕7_ÄD \ ꒚@Yټ26qV)J+i^{^O]HGƥA(wU4P6oU[(>WO n* JZu[ŋWbż u6 Axg͍4^*5ݎ0 +xէxΚK;~ -gQrO@= 9l\w߅ Z`x}>]>V{}E=;k.ϻw9׍e[8=Uɫ67y5WeFݓW4GH`|zc|ହˆ/-n%6D{S1o tϚwf^2UE9Or7Lv9|`0=4xu`+ &!2f! :jM[8R7Eꀔ\LY .x8)Dreq6r^&WrM-b75`*1]U^+KϬ j WI059Ԟ iIo7m*J (t+<+wJ;S_qXOwacR9 xeumҷ —@51X)PzEѻ + sPXy6z 1]azbӨN:cƬ\E|l8ˀ!6|YoEZ >A=}ߜ)v53y|9s *\eԄ o3/V^k2%NĞYړ/ yS1%ڱ?W$0{*#c?$|60yU"^O@F$4,Uo/KYϜ/0yUw$҈GtY{3+yUw$HJa"bBe-۟ƫ#LE[FUN(a"b_$ H|Wbk^RpT_&b:X19ڹUޑW9캉$wUaT;ײAjQfĴSm_̢>5~m%}r˛K69G^gu'(o{Ee/_^.#okv{7[ş?r=E]NXgO-w>}uNnӘ3*)3%.\O>*\Z$g#ٝO{sSԕNފW|OKg>:cW c'06VN_Ej>7m/IENDB`perfbook_html/node109.html0000644000175000017500000000435011672746162015646 0ustar paulmckpaulmck 8.2.1 Exclusive Locks


8.2.1 Exclusive Locks



Paul E. McKenney 2011-12-16
perfbook_html/node388.html0000644000175000017500000004336511672746163015671 0ustar paulmckpaulmck D.3.6.4 Reporting Quiescent States


D.3.6.4 Reporting Quiescent States

This hierarchical RCU implementation implements a layered approach to reporting quiescent states, using the following functions:

  1. rcu_qsctr_inc() and rcu_bh_qsctr_inc() are invoked when a given CPU passes through a quiescent state for ``rcu'' and ``rcu_bh'', respectively. Note that the dynticks-idle and CPU-offline quiescent states are handled specially, due to the fact that such a CPU is not executing, and thus is unable to report itself as being in a quiescent state.
  2. rcu_check_quiescent_state() checks to see if the current CPU has passed through a quiescent state, invoking cpu_quiet() if so.
  3. cpu_quiet() reports the specified CPU as having passed through a quiescent state by invoking cpu_quiet_msk(). The specified CPU must either be the current CPU or an offline CPU.
  4. cpu_quiet_msk() reports the specified vector of CPUs as having passed through a quiescent state. The CPUs in the vector need not be the current CPU, nor must they be offline.

Each of these functions is described below.

Figure: Code for Recording Quiescent States
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_qsctr_inc(int cpu)
2 ...
...p->passed_quiesc_completed = rdp->completed;
13 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_qsctr_inc() and rcu_bh_qsctr_inc(), which note the current CPU's passage through a quiescent state.

Line 3 of rcu_qsctr_inc() obtains a pointer to the specified CPU's rcu_data structure (which corresponds to ``rcu'' as opposed to ``rcu_bh''). Line 4 sets the ->passed_quiesc field, recording the quiescent state. Line 5 sets the ->passed_quiesc_completed field to the number of the last completed grace period that this CPU knows of (which is stored in the ->completed field of the rcu_data structure).

The rcu_bh_qsctr_inc() function operates in the same manner, the only difference being that line 10 obtains the rcu_data pointer from the rcu_bh_data per-CPU variable rather than the rcu_data per-CPU variable.

Figure: Code for rcu_check_quiescent_state()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 rcu_check_quiesc...
...rsp, rdp,
12 rdp->passed_quiesc_completed);
13 }\end{verbatim}
}\end{figure}

Figure [*] shows the code for rcu_check_quiescent_state(), which is invoked from rcu_process_callbacks() (described in Section [*]) in order to determine when other CPUs have started a new grace period and to inform RCU of recent quiescent states for this CPU.

Line 5 invokes check_for_new_grace_period() to check for a new grace period having been started by some other CPU, and also updating this CPU's local state to account for that new grace period. If a new grace period has just started, line 6 returns. Line 7 checks to see if RCU is still expecting a quiescent state from the current CPU, and line 8 returns if not. Line 9 checks to see if this CPU has passed through a quiescent state since the start of the current grace period (in other words, if rcu_qsctr_inc() or rcu_bh_qsctr_inc() have been invoked for ``rcu'' and ``rcu_bh'', respectively), and line 10 returns if not.

Therefore, execution reaches line 11 only if a previously noted grace period is still in effect, if this CPU needs to pass through a quiescent state in order to allow this grace period to end, and if this CPU has passed through such a quiescent state. In this case, lines 11-12 invoke cpu_quiet() in order to report this quiescent state to RCU.

Quick Quiz D.46: What prevents lines 11-12 of Figure [*] from reporting a quiescent state from a prior grace period against the current grace period? End Quick Quiz

Figure: Code for cpu_quiet()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 cpu_quiet(int cp...
... cpu_quiet_msk(mask, rsp, rnp, flags);
25 }
26 }\end{verbatim}
}\end{figure}

Figure [*] shows cpu_quiet, which is used to report a quiescent state for the specified CPU. As noted earlier, this must either be the currently running CPU or a CPU that is guaranteed to remain offline throughout.

Line 9 picks up a pointer to the leaf rcu_node structure responsible for this CPU. Line 10 acquires this leaf rcu_node structure's lock and disables interrupts. Line 11 checks to make sure that the specified grace period is still in effect, and, if not, line 11 clears the indication that this CPU passed through a quiescent state (since it belongs to a defunct grace period), line 13 releases the lock and re-enables interrupts, and line 14 returns to the caller.

Otherwise, line 16 forms a mask with the specified CPU's bit set. Line 17 checks to see if this bit is still set in the leaf rcu_node structure, and, if not, line 18 releases the lock and re-enables interrupts.

On the other hand, if the CPU's bit is still set, line 20 clears ->qs_pending, reflecting that this CPU has passed through its quiescent state for this grace period. Line 21 then overwrites local variable rdp with a pointer to the running CPU's rcu_data structure, and lines 22-23 updates the running CPU's RCU callbacks so that all those not yet associated with a specific grace period be serviced by the next grace period. Finally, line 24 clears bits up the rcu_node hierarchy, ending the current grace period if appropriate and perhaps even starting a new one. Note that cpu_quiet() releases the lock and re-enables interrupts.

Quick Quiz D.47: How do lines 22-23 of Figure [*] know that it is safe to promote the running CPU's RCU callbacks? End Quick Quiz

Figure: Code for cpu_quiet_msk()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void
2 cpu_quiet_msk(un...
...cessor_id()]);
26 rcu_start_gp(rsp, flags);
27 }\end{verbatim}
}\end{figure}

Figure [*] shows cpu_quiet_msk(), which updates the rcu_node hierarchy to reflect the passage of the CPUs indicated by argument mask through their respective quiescent states. Note that argument rnp is the leaf rcu_node structure corresponding to the specified CPUs.

Quick Quiz D.48: Given that argument mask on line 2 of Figure [*] is an unsigned long, how can it possibly deal with systems with more than 64 CPUs? End Quick Quiz

Line 4 is annotation for the sparse utility, indicating that cpu_quiet_msk() releases the leaf rcu_node structure's lock.

Figure: Scanning rcu_node Structures When Applying Quiescent States
\resizebox{6in}{!}{\includegraphics{appendix/rcuimpl/RCUTreeQSScan}}

Each pass through the loop spanning lines 6-23 does the required processing for one level of the rcu_node hierarchy, traversing the data structures as shown by the blue arrow in Figure [*].

Line 7 checks to see if all of the bits in mask have already been cleared in the current rcu_node structure's ->qsmask field, and, if so, line 8 releases the lock and re-enables interrupts, and line 9 returns to the caller. If not, line 11 clears the bits specified by mask from the current rcu_node structure's qsmask field. Line 12 then checks to see if there are more bits remaining in ->qsmask, and, if so, line 13 releases the lock and re-enables interrupts, and line 14 returns to the caller.

Otherwise, it is necessary to advance up to the next level of the rcu_node hierarchy. In preparation for this next level, line 16 places a mask with the single bit set corresponding to the current rcu_node structure within its parent. Line 17 checks to see if there in fact is a parent for the current rcu_node structure, and, if not, line 18 breaks from the loop. On the other hand, if there is a parent rcu_node structure, line 20 releases the current rcu_node structure's lock, line 21 advances the rnp local variable to the parent, and line 22 acquires the parent's lock. Execution then continues at the beginning of the loop on line 7.

If line 18 breaks from the loop, we know that the current grace period has ended, as the only way that all bits can be cleared in the root rcu_node structure is if all CPUs have passed through quiescent states. In this case, line 24 updates the rcu_state structure's ->completed field to match the number of the newly ended grace period, indicating that the grace period has in fact ended. Line 24 then invokes rcu_process_gp_end() to advance the running CPU's RCU callbacks, and, finally, line 26 invokes rcu_start_gp() in order to start a new grace period should any remaining callbacks on the currently running CPU require one.

Figure: Code for rcu_do_batch()
\begin{figure}{ \scriptsize
\begin{verbatim}1 static void rcu_do_batch(struct...
...invoke(rdp))
43 raise_softirq(RCU_SOFTIRQ);
44 }\end{verbatim}
}\end{figure}

Figure [*] shows rcu_do_batch(), which invokes RCU callbacks whose grace periods have ended. Only callbacks on the running CPU will be invoked--other CPUs must invoke their own callbacks.

Quick Quiz D.49: How do RCU callbacks on dynticks-idle or offline CPUs get invoked? End Quick Quiz

Line 7 invokes cpu_has_callbacks_ready_to_invoke() to see if this CPU has any RCU callbacks whose grace period has completed, and, if not, line 8 returns. Lines 9 and 18 disable and re-enable interrupts, respectively. Lines 11-13 remove the ready-to-invoke callbacks from ->nxtlist, and lines 14-17 make any needed adjustments to the tail pointers.

Quick Quiz D.50: Why would lines 14-17 in Figure [*] need to adjust the tail pointers? End Quick Quiz

Line 19 initializes local variable count to zero in preparation for counting the number of callbacks that will actually be invoked. Each pass through the loop spanning lines 20-27 invokes and counts a callback, with lines 25-26 exiting the loop if too many callbacks are to be invoked at a time (thus preserving responsiveness). The remainder of the function then requeues any callbacks that could not be invoked due to this limit.

Lines 28 and 41 disable and re-enable interrupts, respectively. Line 29 updates the ->qlen field, which maintains a count of the total number of RCU callbacks for this CPU. Line 30 checks to see if there were any ready-to-invoke callbacks that could not be invoked at the moment due to the limit on the number that may be invoked at a given time. If such callbacks remain, lines 30-38 requeue them, again adjusting the tail pointers as needed. Lines 39-40 restore the batch limit if it was increased due to excessive callback backlog, and lines 42-43 cause additional RCU processing to be scheduled if there are any ready-to-invoke callbacks remaining.

Paul E. McKenney 2011-12-16
perfbook_html/node101.html0000644000175000017500000000444311672746162015641 0ustar paulmckpaulmck 7.5 Performance Summary


7.5 Performance Summary

@@@ summarize performance of the various options. Forward-reference to the RCU/NBS section.


Paul E. McKenney 2011-12-16
perfbook_html/img58.png0000644000175000017500000000711311672746030015232 0ustar paulmckpaulmckPNG  IHDRѭp\>wuv.*+-**|zzg-tRNS@f IDATx\( E%]uV[ޝs IEßj`x>WFp0?L׀ =XFK#Ǚ*T>fZ~.> )A#l'df'vg6l$c~§l?`.>``OvFp$@)$~o۞ijp(;~Z'̩thX *uAai+8 l(0eZlVLf1Zwd_ި /HZaN)Xcz_/}-ÆLM;@ECݾ[t7@ǐǠ33iI(zLձuxnDG)e {n|m AG]r$)[Ӄ8t9 643UwfU: rj8 D48~vꃅ30Ff]ي~ h%; +E4]CJfIpc qAS،C(ipؘfN[Ƭ3E~,ܚ^iJ@=%c^3$6<ҴVS5b8ЗxbOBYm9gV^kqhAì0qXCE GSrx=lX_ޙ{ MNvLSF]7Ne_ 픡F sƇ<ݤ#;Hàz0j18_Go6! Kr =X`&g!kG"ߴ8kzֶ1u5^,0u6@:#NB(Hӡ7ש^$&`uAރy(qzi#.[hE3̀f6 yV$dn `;P論}GAv(:dO:Pc>lJ m[WQg^wq?(BZ94O6ZPyzp}J\-M})Ȱ),5U4B'c'h"vv=N aFǁ*HͧVS!AG {*/FTSY~U@T2{W oȜf^cFBkEVp كOPsy~ajոj M%dU@ZQ9nHbIhJ&ڐziwk(9^r*( XVu2}CId czHK⭅x%`".)FBH| 6֒{.Rs!wSc`$.>mc.G?%W^<(|K䤑sn܅X]ΩT y1 4f9#zQd/᜖Nl8h8_[pφzs `+'$׬oYly]-~m2m&S4T!cߖ:RBlB5Hf0-bC.S.HdC &N|&DVx[ /3'@Կkwrnbpfj( ^|@7ŖDZHSd*Zy+h,j+%$pQKZɌ0]{5H(̢3,pGߝrIHQHIk3]@톚`sDt`# 31N ȑV u΃TGr -m¥ ˊm@}zpm&缎RJ(7}ZO Jp}ijŴ<4SS\݂bc}l_F)co{ P[+8XZ@L?[yRcBi>eoPZ̥\UFT `f>s \\*MrŨN ,C3y% Xrb {)KH72Ki gf |)K@S>2|V"x{Slg, M\ܔtZZ;L{g .-w1M~ho⨬DZ͝u S/x5]e".w~+9HK.HTqJߤ_(%Y!)U ?:+|'$6)L#2=40ڮN.m5ҁ$)yy|`Rj DN2d-MM-4h[Н'Bu&lSއ$&?~|T2Ï GLޱcE <@r~2/@Nj[:N8C̡n?GExn;qWC)j1dV}fF t~_|q⑭$qk_,J!F#85XE/8vwq m9k#ݸEhx 0F6KHG4S[^ZhV:dURjg'r_Stc2"PNPcn@.|@f}JbuǦePA@}K=Q nL'6u+ b~>LcP 2m+x'>P7V\̿L(E*bZ=wn$;*#[ƅR#Mݥ [/'Qw|FsW}|_igh4;GZ~DxIENDB`perfbook_html/img132.png0000644000175000017500000001646111672746160015315 0ustar paulmckpaulmckPNG  IHDRW%PLTE "3"{{{̙3''qqgggݦwMMMw'''D33U3U@@ fMMwZZtttZZZff@@@444f&&&D" tRNS@f7IDATx] J.e3i@<=~ƒ!kྍm\. QT ӦDzxEĘ?!Ⱥ6ֵV:薥J~5Ngxu%j 8蘞W*/N3!/Ҋ¡N su35!@7K^I+uUF?_\>4Uu_*e|iCU!n.Qug뎸8~}|pqtfFfM)GD'hmZN:;n;Nzʋ >FBSuϛ_^3n'[κeݗ/.+q4N"i4"yf:L![k Ms˛l6O,z]-n$"ԟB8g8H}no\ Mh`xpAru?ИǿCGS2VTx.lHSA6]6 !ccQd C<5P^u=M+P H*#aX?%sV!EN!,JllW-$rY_eңU4F E=cD}MN"%xz-}({'W6[5qalN8}lgoxd_流S`Q 2LLEr9&'!]B nL ;el2lJiص3NS-9!'0D= s> iZƲcC@mL Q|Ti%|Z ے5:Aq]yfxǣiBNr18TsD!O,ޱ]&b0&i(=#Tʅh:je{WoF"Z } D!rvglw+PlU20ִئGq }5k]SES"`؉έ>`yVAZ LjD~S [!xJU5*=or? usw-SwǑ.*IGu߲ ^6[з2@{= yOy;Yw=z[ZxGNb6J[-"f =nY*Uw=dhI)4G%Q*Z/me[R'\n, d+ĝd^ŋK6veȹ6b,Ėۢx)mV16}0ViBoƶc步Cy%gךOG?yk _0]3O C:}?uM̕:..i+\x۠ X5 {g۟z`[[֟[g蘕lU6r^L|F^Mh .UL-/%UڣЧޯ H#=;IŔs4uOm+p=35tM #( wj n2$.eX&ЙU 9Q_a@M~bNUJTOM+[ w BИkjp![ /v0},=wOvImJHI&̂?tL?va\g(d>m~+iK~Ձ;Fe#JV}:1%62(3N"a;|hE~K{R@Nv9j:Ex{hsq38 f0a\K#u7"_d\NU/UavaEwgajxŨu 3v7j4/5Ž`UaGPnn7immwKDi4I|ZFlį!iM6䒰eu,ʉ C|J,,,ݡe59Y7 &𳇰/_h ;tfʷhIJM4hMm >cN>Rae/oݔQuT,o+EyU"<*>7媕 o}~6;[עh؛UYԶ&o觕ꇚ1홹|]/dtأb9-fQ,PRXQTmE~H9+2!;ȄM!‚ȋdٯXXaxxP q"eey92!,U£nH K.Iʢ+BbWta#ۛfz, ߃8?Bc[ h$`u…NG0bBHK3.谚tE?)PY?)< ?. 5Ѭ>F{O,'?MQ7pԨ&"xab%_Icg*H65/"aW888x[GL;/rdGYaWɥA ]F3-uĀ[(%\'{I\au0a#ƶ^iM#?gM1`" Q|` ΣuPgvyЪq]k%$9ޡQ[&?OXGg鷥.|'Ѐ|Yr(7u.YUjXs%e!݀R+Aj( k˯_UelގcK?)~VNZ'7EYq4b„&bO P'ģd=`'ӁL>ڂ$WΡWtbX\Y_ Oi 8R"\)Y_H8=\V]y 5 6]J%Rm]֯/?^6_md= $끷ĸ8+vqbY{,koL=*W,,VL\ < ~džf :V|1| _3i h׆`5$VYŊ(O-^0oUY *jL歋uho@7꨾o5kemO-뽽0^ L=M:|r'{c`Ll@-Az|w^7mȀ~ʢn!O3J<'*s54e"`_6/*h#QO%0x&"wS l)63)XdSb{]8yy/YΛLEqgd ,).: YcTzlGYVpDRPO\2h/5KJ; 2"̀i[!+;* }H|[xze Med4ƠyZn%T219H֚OE YUNN4Z7"TeS~KQ3".kCV99UdDqRԤ]|CV}̚eifi:鶶/#VRT[!AlYnsʘD:Yӏ-P;¯ǭWQɻ`?59qiGiGMfJ)[r9E~ר)jRe3.ڑ\[a%dU7Xq,j,Բ{ɲy!ٔa^c'DOF[A~ݩ\e}Oir3vSHy>/^ȸLdK֧bwVoHtnގ/n5Odb?V?8Q@\#o@b+ gi %DgE\MS5Q=*sX) yO*NḞl~X~m6e;OJ!\ |7ڧUkWWnVgŧm5Jɧg3JfxjnH1 xpiqv~bĵu^Klz1o8p_:8:yMlq/85zucjʂS5q@WY|a{l^a;aVvWU 0OuqWU*u= ҫG#B_sG qAp!9V֡˽4b@JϚF8O=uw\;:ӥԣq]j >tqc7Zَ@\lou`&PA|abT?o=7`)JXj3cok3ŨJSLbySL Sll~}^KjbT%mfSl8([p{7-fQUesI[0Ş>V)b)4;~ coõFlguqF3hM͸޸>Z' uB;A; \J"u ~BMNUSXsv:L7t\ԟ=2k\ǯ+OmZ׊++%mǴ !NB]?9ࢪKW _uZ=9ź**{ k V@k &a5sҢ6%cTScyk0O~R= FcR\ y+h(p`kY6bvuq%dv86IgbpŗYyDi=usb۰_ƫ2|ocV]җ~op{Jg GGi]Sb^^Αpl_~Q'$;9@>UnGebW =zkŪ7;C_׏mh$Wϸ^:pm2llQLgŵd95NRis 'RyTƵd95N׾_x-Z|+kk14P~V\KS'lB-rv=pe9@zuh:qe7 ќ;L3uh:4:L34N%O< j m 6#Z,bauNXq̃jk{+%d"õ Z&%\EZ)M,jR3Mpk{+%d"\)&S,_}31/˗mAҐVQa2ƊoM{}|(Wrd[Z\7Px Io|7Hw併z\ %Yɉ zSXq)niq͓ar2޺ьG' 0bVrd[5NDuqd| N]87`渆iۈy=%-#k.;uzt,z#5̂=mU\EHiYs񓵧VgaQiJy4u.`ʤAnd8 \)qqE%ژ5W?Yz5vN }؂(rmvhK;d^>lu_O=aXkiFCî:̯Z0ŵ4 UC~Uc}X!bg F~$\g@ j=ܕޖr)U޲ƿ%UT6 -+ah"o͸J6gPYVʞcVf\%3 ;=lWI=@c,+e![nƵ+1b{9 -?挬ׁcq?kl9ns gzt׽ ʔBf踦9UA7(pON>6fɦ W᪂@oC)TVkzujjvcqFhbzFz!T9K>\@-7)Ͼ>4`:f,oٳ>Բi Pi4= R~e;haiN{ PCEOcI(K=+;irñ*5=_(~ }/9g_ X-V}zghrM2IENDB`perfbook_html/node315.html0000644000175000017500000002230411672746163015645 0ustar paulmckpaulmck C.7.1 Alpha

C.7.1 Alpha

It may seem strange to say much of anything about a CPU whose end of life has been announced, but Alpha is interesting because, with the weakest memory ordering model, it reorders memory operations the most aggressively. It therefore has defined the Linux-kernel memory-ordering primitives, which must work on all CPUs, including Alpha. Understanding Alpha is therefore surprisingly important to the Linux kernel hacker.

The difference between Alpha and the other CPUs is illustrated by the code shown in Figure [*]. This smp_wmb() on line 9 of this figure guarantees that the element initialization in lines 6-8 is executed before the element is added to the list on line 10, so that the lock-free search will work correctly. That is, it makes this guarantee on all CPUs except Alpha.

Figure: Insert and Lock-Free Search
\begin{figure}{\tt\scriptsize
\begin{verbatim}1 struct el *insert(long key, l...
...}
23 p = p->next;
24 };
25 return (NULL);
26 }\end{verbatim}
}\end{figure}

Alpha has extremely weak memory ordering such that the code on line 20 of Figure [*] could see the old garbage values that were present before the initialization on lines 6-8.

Figure [*] shows how this can happen on an aggressively parallel machine with partitioned caches, so that alternating caches lines are processed by the different partitions of the caches. Assume that the list header head will be processed by cache bank 0, and that the new element will be processed by cache bank 1. On Alpha, the smp_wmb() will guarantee that the cache invalidates performed by lines 6-8 of Figure [*] will reach the interconnect before that of line 10 does, but makes absolutely no guarantee about the order in which the new values will reach the reading CPU's core. For example, it is possible that the reading CPU's cache bank 1 is very busy, but cache bank 0 is idle. This could result in the cache invalidates for the new element being delayed, so that the reading CPU gets the new value for the pointer, but sees the old cached values for the new element. See the Web site called out earlier for more information, or, again, if you think that I am just making all this up.C.6

Figure: Why smp_read_barrier_depends() is Required
\begin{figure}\begin{center}
\begin{picture}(213,160)(0,25)
\par
% First CPU
\pa...
...45,25){\makebox(120,20)[c]{Interconnect}}
\end{picture}\end{center}
\end{figure}

One could place an smp_rmb() primitive between the pointer fetch and dereference. However, this imposes unneeded overhead on systems (such as i386, IA64, PPC, and SPARC) that respect data dependencies on the read side. A smp_read_barrier_depends() primitive has been added to the Linux 2.6 kernel to eliminate overhead on these systems. This primitive may be used as shown on line 19 of Figure [*].

It is also possible to implement a software barrier that could be used in place of smp_wmb(), which would force all reading CPUs to see the writing CPU's writes in order. However, this approach was deemed by the Linux community to impose excessive overhead on extremely weakly ordered CPUs such as Alpha. This software barrier could be implemented by sending inter-processor interrupts (IPIs) to all other CPUs. Upon receipt of such an IPI, a CPU would execute a memory-barrier instruction, implementing a memory-barrier shootdown. Additional logic is required to avoid deadlocks. Of course, CPUs that respect data dependencies would define such a barrier to simply be smp_wmb(). Perhaps this decision should be revisited in the future as Alpha fades off into the sunset.

Figure: Safe Insert and Lock-Free Search
\begin{figure}{\tt\scriptsize
\begin{verbatim}1 struct el *insert(long key, l...
...}
23 p = p->next;
24 };
25 return (NULL);
26 }\end{verbatim}
}\end{figure}

The Linux memory-barrier primitives took their names from the Alpha instructions, so smp_mb() is mb, smp_rmb() is rmb, and smp_wmb() is wmb. Alpha is the only CPU where smp_read_barrier_depends() is an smp_mb() rather than a no-op.

Quick Quiz C.13: Why is Alpha's smp_read_barrier_depends() an smp_mb() rather than smp_rmb()? End Quick Quiz

For more detail on Alpha, see the reference manual [SW95].

Paul E. McKenney 2011-12-16
perfbook_html/node342.html0000644000175000017500000001747711672746163015664 0ustar paulmckpaulmck D.2 Hierarchical RCU Overview


D.2 Hierarchical RCU Overview

Although Classic RCU's read-side primitives enjoy excellent performance and scalability, the update-side primitives, which determine when pre-existing read-side critical sections have finished, were designed with only a few tens of CPUs in mind. Their scalability is limited by a global lock that must be acquired by each CPU at least once during each grace period. Although Classic RCU actually scales to a couple of hundred CPUs, and can be tweaked to scale to roughly a thousand CPUs (but at the expense of extending grace periods), emerging multicore systems will require it to scale better.

In addition, Classic RCU has a sub-optimal dynticks interface, with the result that Classic RCU will wake up every CPU at least once per grace period. To see the problem with this, consider a 16-CPU system that is sufficiently lightly loaded that it is keeping only four CPUs busy. In a perfect world, the remaining twelve CPUs could be put into deep sleep mode in order to conserve energy. Unfortunately, if the four busy CPUs are frequently performing RCU updates, those twelve idle CPUs will be awakened frequently, wasting significant energy. Thus, any major change to Classic RCU should also leave sleeping CPUs lie.

Both the classic and the hierarchical implementations have have Classic RCU semantics and identical APIs, however, the old implementation will be called ``classic RCU'' and the new implementation will be called ``hierarchical RCU''.

@@@ roadmap @@@



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node442.html0000644000175000017500000001560411672746163015653 0ustar paulmckpaulmck E.7.1.3 Grace-Period Interface


E.7.1.3 Grace-Period Interface

Of the four preemptible RCU grace-period states shown in Figure [*] on page [*] in Appendix [*], only the rcu_try_flip_waitack_state() and rcu_try_flip_waitmb_state() states need to wait for other CPUs to respond.

Of course, if a given CPU is in dynticks-idle state, we shouldn't wait for it. Therefore, just before entering one of these two states, the preceding state takes a snapshot of each CPU's dynticks_progress_counter variable, placing the snapshot in another per-CPU variable, rcu_dyntick_snapshot. This is accomplished by invoking dyntick_save_progress_counter, shown below:

  1 static void dyntick_save_progress_counter(int cpu)
  2 {
  3   per_cpu(rcu_dyntick_snapshot, cpu) =
  4     per_cpu(dynticks_progress_counter, cpu);
  5 }

The rcu_try_flip_waitack_state() state invokes rcu_try_flip_waitack_needed(), shown below:

  1 static inline int
  2 rcu_try_flip_waitack_needed(int cpu)
  3 {
  4   long curr;
  5   long snap;
  6
  7   curr = per_cpu(dynticks_progress_counter, cpu);
  8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
  9   smp_mb();
 10   if ((curr == snap) && ((curr & 0x1) == 0))
 11     return 0;
 12   if ((curr - snap) > 2 || (snap & 0x1) == 0)
 13     return 0;
 14   return 1;
 15 }

Lines 7 and 8 pick up current and snapshot versions of dynticks_progress_counter, respectively. The memory barrier on line ensures that the counter checks in the later rcu_try_flip_waitzero_state follow the fetches of these counters. Lines 10 and 11 return zero (meaning no communication with the specified CPU is required) if that CPU has remained in dynticks-idle state since the time that the snapshot was taken. Similarly, lines 12 and 13 return zero if that CPU was initially in dynticks-idle state or if it has completely passed through a dynticks-idle state. In both these cases, there is no way that that CPU could have retained the old value of the grace-period counter. If neither of these conditions hold, line 14 returns one, meaning that the CPU needs to explicitly respond.

For its part, the rcu_try_flip_waitmb_state state invokes rcu_try_flip_waitmb_needed(), shown below:

  1 static inline int
  2 rcu_try_flip_waitmb_needed(int cpu)
  3 {
  4   long curr;
  5   long snap;
  6
  7   curr = per_cpu(dynticks_progress_counter, cpu);
  8   snap = per_cpu(rcu_dyntick_snapshot, cpu);
  9   smp_mb();
 10   if ((curr == snap) && ((curr & 0x1) == 0))
 11     return 0;
 12   if (curr != snap)
 13     return 0;
 14   return 1;
 15 }

This is quite similar to rcu_try_flip_waitack_needed, the difference being in lines 12 and 13, because any transition either to or from dynticks-idle state executes the memory barrier needed by the rcu_try_flip_waitmb_state() state.

We now have seen all the code involved in the interface between RCU and the dynticks-idle state. The next section builds up the Promela model used to verify this code.

Quick Quiz E.9: Can you spot any bugs in any of the code in this section? End Quick Quiz

Paul E. McKenney 2011-12-16
perfbook_html/node465.html0000644000175000017500000005163511672746163015664 0ustar paulmckpaulmck F.5 Chapter 

F.5 Chapter [*]

Quick Quiz [*].1: 
Is there a better solution to the Dining Philosophers Problem?
 
Answer:

Figure: Dining Philosophers Problem, Fully Partitioned
\includegraphics[scale=.7]{SMPdesign/DiningPhilosopher5PEM}

One such improved solution is shown in Figure [*], where the philosophers are simply provided with an additional five forks. All five philosophers may now eat simultaneously, and there is never any need for philosophers to wait on one another. In addition, the improved disease control provided by this approach should not be underestimated.

This solution can seem like cheating to some, but such ``cheating'' is key to finding good solutions to many concurrency problems.

Quick Quiz [*].2: 
And in just what sense can this ``horizontal parallelism'' be said to be ``horizontal''?
 
Answer:
Inman was working with protocol stacks, which are normally depicted vertically, with the application on top and the hardware interconnect on the bottom. Data flows up and down this stack. ``Horizontal parallelism'' processes packets from different network connections in parallel, while ``vertical parallelism'' handles different protocol-processing steps for a given packet in parallel.

``Vertical parallelism'' is also called ``pipelining''.

Quick Quiz [*].3: 
In this compound double-ended queue implementation, what should be done if the queue has become non-empty while releasing and reacquiring the lock?
 
Answer:
In this case, simply dequeue an item from the now-nonempty queue, release both locks, and return.

Quick Quiz [*].4: 
Is the hashed double-ended queue a good solution? Why or why not?
 
Answer:
The best way to answer this is to run lockhdeq.c on a number of different multiprocessor systems, and you are encouraged to do so in the strongest possible terms. One reason for concern is that each operation on this implementation must acquire not one but two locks.

The first well-designed performance study will be cited. Do not forget to compare to a sequential implementation!

Quick Quiz [*].5: 
Move all the elements to the queue that became empty? In what possible universe is this braindead solution in any way optimal???
 
Answer:
It is optimal in the case where data flow switches direction only rarely. It would of course be an extremely poor choice if the double-ended queue was being emptied from both ends concurrently. This of course raises the question as to what possible universe emptying from both ends concurrently would be a reasonable thing to do...

Quick Quiz [*].6: 
Why can't the compound parallel double-ended queue implementation be symmetric?
 
Answer:
The need to avoid deadlock by imposing a lock hierarchy forces the asymmetry, just as it does in the fork-numbering solution to the Dining Philosophers Problem.

Quick Quiz [*].7: 
Why is it necessary to retry the right-dequeue operation on line 29 of Figure [*]?
 
Answer:
This retry is necessary because some other thread might have enqueued an element between the time that this thread dropped the lock and the time that it reacquired the lock.

Quick Quiz [*].8: 
Surely the left-hand lock must sometimes be available!!! So why is it necessary that line 26 of Figure [*] unconditionally release the right-hand lock?
 
Answer:
It would be possible to use spin_trylock() to attempt to acquire the left-hand lock when it was available. However, the failure case would still need to drop the right-hand lock and then re-acquire the two locks in order. Making this transformation (and determining whether or not it is worthwhile) is left as an exercise for the reader.

Quick Quiz [*].9: 
The tandem double-ended queue runs about twice as fast as the hashed double-ended queue, even when I increase the size of the hash table to an insanely large number. Why is that?
 
Answer:
The hashed double-ended queue's locking design only permits one thread at a time at each end, and further requires two lock acquisitions for each operation. The tandem double-ended queue also permits one thread at a time at each end, and in the common case requires only one lock acquisition per operation. Therefore, the tandem double-ended queue should be expected to outperform the hashed double-ended queue.

Can you created a double-ended queue that allows multiple concurrent operations at each end? If so, how? If not, why not?

Quick Quiz [*].10: 
Is there a significantly better way of handling concurrency for double-ended queues?
 
Answer:
Transform the problem to be solved so that multiple double-ended queues can be used in parallel, allowing the simpler single-lock double-ended queue to be used, and perhaps also replace each double-ended queue with a pair of conventional single-ended queues. Without such ``horizontal scaling'', the speedup is limited to 2.0. In contrast, horizontal-scaling designs can enable very large speedups, and are especially attractive if there are multiple threads working either end of the queue, because in this multiple-thread case the deque simply cannot provide strong ordering guarantees. And if there are no guarantees, we may as well obtain the performance benefits that come with refusing to provide the guarantees, right?

Quick Quiz [*].11: 
What are some ways of preventing a structure from being freed while its lock is being acquired?
 
Answer:
Here are a few possible solutions to this existence guarantee problem:

  1. Provide a statically allocated lock that is held while the per-structure lock is being acquired, which is an example of hierarchical locking (see Section [*]). Of course, using a single global lock for this purpose can result in unacceptably high levels of lock contention, dramatically reducing performance and scalability.
  2. Provide an array of statically allocated locks, hashing the structure's address to select the lock to be acquired, as described in Chapter [*]. Given a hash function of sufficiently high quality, this avoids the scalability limitations of the single global lock, but in read-mostly situations, the lock-acquisition overhead can result in unacceptably degraded performance.
  3. Use a garbage collector, in software environments providing them, so that a structure cannot be deallocated while being referenced. This works very well, removing the existence-guarantee burden (and much else besides) from the developer's shoulders, but imposes the overhead of garbage collection on the program. Although garbage-collection technology has advanced considerably in the past few decades, its overhead may be unacceptably high for some applications. In addition, some applications require that the developer exercise more control over the layout and placement of data structures than is permitted by most garbage collected environments.
  4. As a special case of a garbage collector, use a global reference counter, or a global array of reference counters.
  5. Use hazard pointers [Mic04], which can be thought of as an inside-out reference count. Hazard-pointer-based algorithms maintain a per-thread list of pointers, so that the appearance of a given pointer on any of these lists acts as a reference to the corresponding structure. Hazard pointers are an interesting research direction, but have not yet seen much use in production (written in 2008).
  6. Use transactional memory (TM) [HM93,Lom77,ST95], so that each reference and modification to the data structure in question is performed atomically. Although TM has engendered much excitement in recent years, and seems likely to be of some use in production software, developers should exercise some caution [BLM05,BLM06,MMW07], particularly in performance-critical code. In particular, existence guarantees require that the transaction cover the full path from a global reference to the data elements being updated.
  7. Use RCU, which can be thought of as an extremely lightweight approximation to a garbage collector. Updaters are not permitted to free RCU-protected data structures that RCU readers might still be referencing. RCU is most heavily used for read-mostly data structures, and is discussed at length in Chapter [*].

For more on providing existence guarantees, see Chapters [*] and [*].

Quick Quiz [*].12: 
How can a single-threaded 64-by-64 matrix multiple possibly have an efficiency of less than 1.0? Shouldn't all of the traces in Figure [*] have efficiency of exactly 1.0 when running on only one thread?
 
Answer:
The matmul.c program creates the specified number of worker threads, so even the single-worker-thread case incurs thread-creation overhead. Making the changes required to optimize away thread-creation overhead in the single-worker-thread case is left as an exercise to the reader.

Quick Quiz [*].13: 
How are data-parallel techniques going to help with matrix multiply? It is already data parallel!!!
 
Answer:
I am glad that you are paying attention! This example serves to show that although data parallelism can be a very good thing, it is not some magic wand that automatically wards off any and all sources of inefficiency. Linear scaling at full performance, even to ``only'' 64 threads, requires care at all phases of design and implementation.

In particular, you need to pay careful attention to the size of the partitions. For example, if you split a 64-by-64 matrix multiply across 64 threads, each thread gets only 64 floating-point multiplies. The cost of a floating-point multiply is miniscule compared to the overhead of thread creation.

Moral: If you have a parallel program with variable input, always include a check for the input size being too small to be worth parallelizing. And when it is not helpful to parallelize, it is not helpful to spawn a single thread, now is it?

Quick Quiz [*].14: 
In what situation would hierarchical locking work well?
 
Answer:
If the comparison on line 31 of Figure [*] were replaced by a much heavier-weight operation, then releasing bp->bucket_lock might reduce lock contention enough to outweigh the overhead of the extra acquisition and release of cur->node_lock.

Quick Quiz [*].15: 
In Figure [*], there is a pattern of performance rising with increasing run length in groups of three samples, for example, for run lengths 10, 11, and 12. Why?
 
Answer:
This is due to the per-CPU target value being three. A run length of 12 must acquire the global-pool lock twice, while a run length of 13 must acquire the global-pool lock three times.

Quick Quiz [*].16: 
Allocation failures were observed in the two-thread tests at run lengths of 19 and greater. Given the global-pool size of 40 and the per-CPU target pool size of three, what is the smallest allocation run length at which failures can occur?
 
Answer:
The exact solution to this problem is left as an exercise to the reader. The first solution received will be credited to its submitter. As a rough rule of thumb, the global pool size should be at least $m+2sn$, where ``m'' is the maximum number of elements allocated at a given time, ``s'' is the per-CPU pool size, and ``n'' is the number of CPUs.

Paul E. McKenney 2011-12-16
perfbook_html/node261.html0000644000175000017500000001446111672746162015651 0ustar paulmckpaulmck 17.1.12 The exec() System Call


17.1.12 The exec() System Call

One can execute an exec() system call while holding a lock, and also from within an RCU read-side critical section. The exact semantics depends on the type of primitive.

In the case of non-persistent primitives (including pthread_mutex_lock(), pthread_rwlock_rdlock(), and RCU), if the exec() succeeds, the whole address space vanishes, along with any locks being held. Of course, if the exec() fails, the address space still lives, so any associated locks would also still live. A bit strange perhaps, but reasonably well defined.

On the other hand, persistent primitives (including the flock family, lockf(), System V semaphores, and the O_CREAT flag to open()) would survive regardless of whether the exec() succeeded or failed, so that the exec()ed program might well release them.

Quick Quiz 17.1: What about non-persistent primitives represented by data structures in mmap() regions of memory? What happens when their is an exec() within a critical section of such a primitive? End Quick Quiz

What happens when you attempt to execute an exec() system call from within a transaction?

  1. Disallow exec() within transactions, so that the enclosing transactions abort upon encountering the exec(). This is well defined, but clearly requires non-TM synchronization primitives for use in conjunction with exec().
  2. Disallow exec() within transactions, with the compiler enforcing this prohibition. There is a draft specification for TM in C++ that takes this approach, allowing functions to be decorated with the transaction_safe and transaction_unsafe attributes.17.3 This approach has some advantages over aborting the transaction at runtime, but again requires non-TM synchronization primitives for use in conjunction with exec().
  3. Treat the transaction in a manner similar to non-persistent Locking primitives, so that the transaction survives if exec() fails, and silently commits if the exec() succeeds. The case were some of the variables affected by the transaction reside in mmap()ed memory (and thus could survive a successful exec() system call) is left as an exercise for the reader.
  4. Abort the transaction (and the exec() system call) if the exec() system call would have succeeded, but allow the transaction to continue if the exec() system call would fail. This is in some sense the ``correct'' approach, but it would require considerable work for a rather unsatisfying result.

The exec() system call is perhaps the strangest example of an obstacle to universal TM applicability, as it is not completely clear what approach makes sense, and some might argue that this is merely a reflection of the perils of interacting with execs in real life. That said, the two options prohibiting exec() within transactions are perhaps the most logical of the group.

Paul E. McKenney 2011-12-16
perfbook_html/node423.html0000644000175000017500000002631611672746163015654 0ustar paulmckpaulmck E. Formal Verification


E. Formal Verification

Parallel algorithms can be hard to write, and even harder to debug. Testing, though essential, is insufficient, as fatal race conditions can have extremely low probabilities of occurrence. Proofs of correctness can be valuable, but in the end are just as prone to human error as is the original algorithm.

It would be very helpful to have a tool that could somehow locate all race conditions. A number of such tools exist, for example, the language Promela and its compiler Spin, which are described in this chapter. Section [*] provide an introduction to Promela and Spin, Section [*] demonstrates use of Promela and Spin to find a race in a non-atomic increment example, Section [*] uses Promela and Spin to validate a similar atomic-increment example, Section [*] gives an overview of using Promela and Spin, Section [*] demonstrates a Promela model of a spinlock, Section [*] applies Promela and spin to validate a simple RCU implementation, Section [*] applies Promela to validate an interface between preemptible RCU and the dyntick-idle energy-conservation feature in the Linux kernel, Section [*] presents a simpler interface that does not require formal verification, and finally Section [*] sums up use of formal-verification tools for verifying parallel algorithms.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node176.html0000644000175000017500000000460311672746162015653 0ustar paulmckpaulmck 12.4 Probability and Heisenbugs


12.4 Probability and Heisenbugs

@@@ Basic statistics for determining how many tests are needed for a given level of confidence that a given bug has been fixed, etc.



Paul E. McKenney 2011-12-16
perfbook_html/img167.png0000644000175000017500000000376311672745774015340 0ustar paulmckpaulmckPNG  IHDRXmuNPLTE$8D6Sf"DgggwMMM-EUQ}wc'''U3 Z~tttZZZ @@@?aw444fu݇D"tRNS@fIDATx]kc6[vk2)aTF.dM`@+,7:IW''W%D"$"SÿHi @l-6 :y/IG@2@[vNc %,̔w7~V3)uOv2~6 >cΗ'JY4JOh, hI6 Fe¨f@5ey8!Q jF+^KȎg~ȖixWO֝pD,kLd)1}#HŴ Qf+2u %+ԞjPǏd y3Ϟ*nA3~:(82 É F5QJ;zmgxd_Ȗ;Ӳn`$!kpmݔMBVĊ)P`*(zf|i%lWaѸxBT"a"I SJ$ zjM$*\7c,޲q:bEEfN k.gCf˱ "ؓ} ,;9'KEm^AYLθ%G^_l(yo d$c+d&)*  2ٷO*Q9+圴yIּY7lEy>y"@KV.&o+ g_?" u,;#16R#ۼ X곚g60ͳ"-d/t㕑 "ٿHjd =Y5 V#$F}^U9z ـ nnz߈ 5877%RV11 MX 2'N[<)u/y"T0'VwrNaE-*QwNL)f -g7eэ\%$LZvψxװ$] #d$ R|-w{ w>bs(48GQy͡~JX11rdK\IJT mfvqDɡwh5 .E!+ zAXGrD9OruWMJ2Vx*DLcZ4.Š?۲=2RPGNHV%Yܯ|M[h-od6I"~";3?=. #,[DcT #.[.꧰^abp<SX/cS,{SX/c0x9B&11a_)_/^BNcb  ^ {a\@+l/T1 b!d׀VT17#XYMk*dAu&p"qwNX#3LJJ%_fnm9'kFr!NIENDB`perfbook_html/img239.png0000644000175000017500000002035011672746157015323 0ustar paulmckpaulmckPNG  IHDR,`A>HPLTEb``^\\\ZZMJKKHI# hffywwmkkXUV856KHHC@@@<=wuv.*+/tRNS@f IDATx} *%Nbo?B1$fdz7'׍@U-B-~|A'Zii50XɝSNDwH!$LoTfn5i !`!BPxXa>xLUkS';  Pe4w[խz<fi۷WZ3Bx[wRorǒOZAi{2ڛG 8ѤdۣJT/#+7dJui 4YloҖM/9F b6ҽ<@"aӄ&J{ƭd e?1JquƞWIOFo:WӶ 2;R(k_9_d zX2V Эjc}M{CA9N#ja7rqv-"^ÛhR{,4tM Mc3t G }XI ~1z3zk7ظ@n56vN0Ah~,Ϣ×E"KaRfeOھ80aEvTX}vhIKd^oavmQ䤋֝х^na=47[ik:q J4:,P8[ Xvao_)&y?e \#T|ekMC1!AKqO?-46LU`Me鏰n Z}\$WAi|D?1 2~A/3 0`#K#hu /z}Bk F`@=^H ~A?vOz/xݯ@耧BD;%xaX AOIu7yR: -( ɞ("a'FmS^ S{5tdU;Pijhz 57[~==iBҁ/ЧAWz/GKq"Qd~ ۭ'+[Cu.XQ '> u*Ԃ|-V_)hOEĥE}(2p_Y>֍&F6C;|LPd=o'́y O럱It%[BZe(0sGTO,aE$}\H*O`_'Ց=݄39$mtHe v^uA>__.vAM6aGn cjkr(6@ݍoiruˎbdsqd{gn3[wl)ˇG 0[͜D+֣[16.43k篩s2_M/ .զ^-LwܓԊ6am8Zs45nOE;b筼ٳn==x9Q(T0kpCWV[\F#| XBhjp-h?84?c:֤Gm$o:.PhrN< 1XG$~bzaWHUt+Ҵ?&ћaUgY&XqebPmHj55zo_=.Ml'\ |E4wD%_bŔHZF5>9VXjm3k 02+ p(ҩ1_bq{Ya]Qߺms׬fj:-DazQvzz3W.h#_|akv{i/>'G-e8lG>Z[֎=>(w&10B@?\\]+} ǧ+"j][5qWض犕9շ&б@/IrɞsWw[tX1M"k<ҷ GT?7AoH/\SJlBo+UқwKXm{X;ԣh'+~|:Яmo9MZÒ3T1|.Ⱦ4Qb\e{=uj=^d眃=e`4zԞeڂUv_5lW/iWSUUtwK\Ǿ9|a`'}_=4"ˢ;NpAJ~}= mLݬk/"GδU#~jVZ\??-Wou](-DgnNF\5'({.k1dm47V̮+ޗszEdw,(ʑ|=*qJȡ"M>GJ à<GOM{zp}R}m1-Em|_VY*6&&_ȨP._6/(+s[~lAM |t2j >oO*@lȃT}\y?^ طB OkU/}u'Խsme ETqbˠ2RsGZx DTSv2=^$᮰Q0x4U)\,M[W(/]#+ox-{ %8}VﴭWTې&mٴSي%s+gD9G7Eҧ0r>7DJvM)!%7/֬S /<-Pu1 [@c>دRǞ-qp *1[ZKRcژF8BǙvCKHFi5v΍6`Fz 0ڐVŀ/80mG *LF3 n[/F-lsSiglsنyv;~jxO3 ܮH찣9V17E.IHqK.]1nLO!㥻0,V*oJh\FCA]# tu7Tpuokݸ(VnBur"v)?a2w@"ϞFb}J \S梺YedOx8E ŋp8B(o[ :q5QU.E)8U6PJ{N5)B2:{o eV\vt@cΗ'K;4+=a rFwHw;'܂y`UEMl0 XmO{ Iqd kYplC{Y&h Z>,X~'e'[“?ʗ>,֑ۭsLkKh9eLnkRעFzn[ٷ](p7C~b3n;oA3n.gU15r5W0GJjdYi&٠ԏD.\[eRd,٧U/Exz o֭z zCnc%Sôo BB+ JU:8b}2{06]tTpѮb~y|ŊѨ6g_7-LD' Mg'[GoQ}uf$~ Q`: pozTff E9oǑ\sDD6avbmglV ;m:}][k9vH6kU-4O \Ez؂͏(p;Q6ͺ^uc&CV} s-UvbDCXoq$<7½ әF‘ji.X7:;ވIa7Z&C t͓? } \eUQwfg5IV3Q}뿵(a zz\ akb9ɭ|Fh嵄0(&{HXUfh.SRk"GO2{g.g{ƩT)NHӹ*D?;yؙl}qKGR۟۬<8swsza]VѸ/%1,2B/;xd&QOں\]>]O oYFdal8[koAjM,tDdOG'm\n%}sޓWNEm* C> ͉Іeu _ZVGVpq\~a;Bn?/n׾dC0\sôD0@=AA%lB:dYl2\*޺퐗uz'>Q25iUY-^eBE}"vyBra:˷JkINr@eE@ϓ㬟ldq.SV2XWY{Ҳō^ l>n40z[Ai!LwC[?Vmc0 ަjMrXh`peMbieBQ0GMP7]YQ;]p {L;0qL+?bP.s KʄXhIiP&~R}xkdheBQ/5"HԳ+ߕ!,462l8GΠ=>s!?3}CϘN4 V]:k%ƿ.Y2-ڲv Y_^ w,Nt~0PQQQq9&rUo^#fE/.9ӚӹܚW|tyMgLkNVw ~KLkN2+.ּ߳-9n>Y_&c5;](-Ua~#aSאrŘ:glBHؽw*Z͋GvvZ< =k(«8߼gIǷ`E//rƺ]f1MwiT3VY4N~QY20z>µz3tزVQIԃ,VXL b*dW3E\TI[>YGa_A]<e?gT  y>Yə1J(RW\\h4Sʆ,&k]\j0d3Hq4X[YQo&?o]Mr[URRVuJ2e\έ" *+xDe"?o!&4[dHۋ櫇'g rzng\g٣|YOΘ+_;rG߃,ȴ 1a]ZVVtׁVV "JiϪeC(^z7n B6^[ Yl cim=aoEXf}7kVndϷqe +f<׾KH63u1fU>E2gs;ʬqkټY)A*~VE dHgUrkv uYM+|MhҤg_#STqsS\{c-천ǪY5vx4鹄I8dn*<qϾb޷ps PUICk7=s5o#-Y m!'=J`WTT< !!uLhhrNcJKX[x##Ŕڪ,&{90ۺI28'=qY&[/)J>cQ4fy2 6 "rޘ,s: p욘f,ci"`e/6u6--fwx!'FoIEpӶ0~| /1 N3kX%3`ȧ XHO^ 5WL%^-&ſdTKHVTL.7q?k7)i9ɌTY.Ւk0.Ȑw"c1y7"-;xqfc˱Dkaf2u1v%Eϗ?T'r|tI+*9lzoo glJu !y'~V8#sUb^ܼ8zj^l#~V8ʽ֕&EV}{hȓo봝PpY$ [6?Iw d/7+aI+ks~ WK ?HL&qTUQ:[y5 rN/xٯ۱B_EL0T&}!m|\y'JY08\(S) 9>|ymslqlgIuy`%>3rʒT(rioZTYN|Tq",IIgH-˄U\+/Dsժ(tY|^uy &W綸y:~VcJ1qxt^nYe%WQU^4ʲgeo,u=?Kv&Zܫ^]9Lܶ]'!/^>*KҐpFe]Y_Yi-$ g'p|>[}+#Y.y=no}gYo'gy`>z++k2,M\Y^NV T6w*l =Ǒ܎-{&Fy`'fE#p-{PƱ5-+>(ؐ.Zj4%o/'K0PEşG2fK\"& ]UvLFZU3ٻC27+krXY}%WK,TYRUQQu4ܣ~e s_.ei< 0Te0lʦ67ݸmQTݩݰL`CzW1Ŗu]=H"$̈́ӭ< +f'Khe,bUK"Hhnf}+w[{嚞"~kַʅ{ ?&F97וV,>ңBIDATksBj}UᅣV7u&~, ͊`( q8tu7m4Vjڍ6:fmY0=IENDB`perfbook_html/node368.html0000644000175000017500000001405011672746163015654 0ustar paulmckpaulmck D.3.1.5 Kernel Parameters


D.3.1.5 Kernel Parameters

The following kernel parameters affect this variant of RCU:

  • NR_CPUS, the maximum number of CPUs in the system.
  • CONFIG_RCU_FANOUT, the desired number of children for each node in the rcu_node hierarchy.
  • CONFIG_RCU_FANOUT_EXACT, a boolean preventing rebalancing of the rcu_node hierarchy.
  • CONFIG_HOTPLUG_CPU, permitting CPUs to come online and go offline.
  • CONFIG_NO_HZ, indicating that dynticks-idle mode is supported.
  • CONFIG_SMP, indicating that multiple CPUs may be present.
  • CONFIG_RCU_CPU_STALL_DETECTOR, indicating that RCU should check for stalled CPUs when RCU grace periods extend too long.
  • CONFIG_RCU_TRACE, indicating that RCU should provide tracing information in debugfs.

Figure: Determining Shape of RCU Hierarchy
\begin{figure*}{
\begin{verbatim}1  ...

The CONFIG_RCU_FANOUT and NR_CPUS parameters are used to determine the shape of the rcu_node hierarchy at compile time, as shown in Figure [*]. Line 1 defines the maximum depth of the rcu_node hierarchy, currently three. Note that increasing the maximum permitted depth requires changes elsewhere, for example, adding another leg to the #if statement running from lines 6-26. Lines 2-4 compute the fanout, the square of the fanout, and the cube of the fanout, respectively.

Then these values are compared to NR_CPUS to determine the required depth of the rcu_node hierarchy, which is placed into NUM_RCU_LVLS, which is used to size a number of arrays in the rcu_state structure. There is always one node at the root level, and there are always NUM_CPUS number of rcu_data structures below the leaf level. If there is more than just the root level, the number of nodes at the leaf level is computed by dividing NR_CPUS by RCU_FANOUT, rounding up. The number of nodes at other levels is computed in a similar manner, but using (for example) RCU_FANOUT_SQ instead of RCU_FANOUT.

Line 28 then sums up all of the levels, resulting in the number of rcu_node structures plus the number of rcu_data structures. Finally, line 29 subtracts NR_CPUS (which is the number of rcu_data structures) from the sum, resulting in the number of rcu_node structures, which is retained in NUM_RCU_NODES. This value is then used to size the ->nodes array in the rcu_state structure.

Paul E. McKenney 2011-12-16
perfbook_html/node217.html0000644000175000017500000001265211672746162015652 0ustar paulmckpaulmck 14.2.10.1.2 Data Dependency Barriers

14.2.10.1.2 Data Dependency Barriers

A data dependency barrier is a weaker form of read barrier. In the case where two loads are performed such that the second depends on the result of the first (e.g., the first load retrieves the address to which the second load will be directed), a data dependency barrier would be required to make sure that the target of the second load is updated before the address obtained by the first load is accessed.

A data dependency barrier is a partial ordering on interdependent loads only; it is not required to have any effect on stores, independent loads or overlapping loads.

As mentioned for write memory barriers, the other CPUs in the system can be viewed as committing sequences of stores to the memory system that the CPU being considered can then perceive. A data dependency barrier issued by the CPU under consideration guarantees that for any load preceding it, if that load touches one of a sequence of stores from another CPU, then by the time the barrier completes, the effects of all the stores prior to that touched by the load will be perceptible to any loads issued after the data dependency barrier.

See the "Examples of memory barrier sequences" subsection for diagrams showing the ordering constraints.

$\dagger$ Note that the first load really has to have a data dependency and not a control dependency. If the address for the second load is dependent on the first load, but the dependency is through a conditional rather than actually loading the address itself, then it's a control dependency and a full read barrier or better is required. See the "Control dependencies" subsection for more information.

$\dagger$ Note that data dependency barriers should normally be paired with write barriers; see the "SMP barrier pairing" subsection.

Paul E. McKenney 2011-12-16
perfbook_html/img123.png0000644000175000017500000000330711672746106015310 0ustar paulmckpaulmckPNG  IHDR5G&[`PLTE$8D6Sfl*3-EUQ}wcU3"HoZ~ ?awfu݇D"@tRNS@fIDATx[ {*UcMvm_. dۮvU9goFQzKEZn(J;+^K6zQbAw{YJx"n,`TeL[4_#If[Sk`݌h{h!> iE|JN!1Ѿ]sdmčEf$MIP$V1@!-YL p P!:9đč -}-'`mkKoBamiVtD shS#}g9-Dvfd۸6zFʦ`A0趔sKBp3n׸isoo9XJV~1FWY 7ōSnTuncܞhÎE"e,ӛI1q*exM@ͩaGU3 lPRѿ/t!)/2fHs"07t2B,)TSM|+V7t OdIL[4),T|AP-ݞ“j #lXY \ R]&e7_г\|apu9zIENDB`perfbook_html/node438.html0000644000175000017500000002323011672746163015652 0ustar paulmckpaulmck E.7 Promela Parable: dynticks and Preemptible RCU


E.7 Promela Parable: dynticks and Preemptible RCU

In early 2008, a preemptible variant of RCU was accepted into mainline Linux in support of real-time workloads, a variant similar to the RCU implementations in the -rt patchset [Mol05] since August 2005. Preemptible RCU is needed for real-time workloads because older RCU implementations disable preemption across RCU read-side critical sections, resulting in excessive real-time latencies.

However, one disadvantage of the older -rt implementation (described in Appendix [*]) was that each grace period requires work to be done on each CPU, even if that CPU is in a low-power ``dynticks-idle'' state, and thus incapable of executing RCU read-side critical sections. The idea behind the dynticks-idle state is that idle CPUs should be physically powered down in order to conserve energy. In short, preemptible RCU can disable a valuable energy-conservation feature of recent Linux kernels. Although Josh Triplett and Paul McKenney had discussed some approaches for allowing CPUs to remain in low-power state throughout an RCU grace period (thus preserving the Linux kernel's ability to conserve energy), matters did not come to a head until Steve Rostedt integrated a new dyntick implementation with preemptible RCU in the -rt patchset.

This combination caused one of Steve's systems to hang on boot, so in October, Paul coded up a dynticks-friendly modification to preemptible RCU's grace-period processing. Steve coded up rcu_irq_enter() and rcu_irq_exit() interfaces called from the irq_enter() and irq_exit() interrupt entry/exit functions. These rcu_irq_enter() and rcu_irq_exit() functions are needed to allow RCU to reliably handle situations where a dynticks-idle CPUs is momentarily powered up for an interrupt handler containing RCU read-side critical sections. With these changes in place, Steve's system booted reliably, but Paul continued inspecting the code periodically on the assumption that we could not possibly have gotten the code right on the first try.

Paul reviewed the code repeatedly from October 2007 to February 2008, and almost always found at least one bug. In one case, Paul even coded and tested a fix before realizing that the bug was illusory, and in fact in all cases, the ``bug'' turned out to be illusory.

Near the end of February, Paul grew tired of this game. He therefore decided to enlist the aid of Promela and spin [Hol03], as described in Appendix [*]. The following presents a series of seven increasingly realistic Promela models, the last of which passes, consuming about 40GB of main memory for the state space.

More important, Promela and Spin did find a very subtle bug for me!

Quick Quiz E.6: Yeah, that's just great! Now, just what am I supposed to do if I don't happen to have a machine with 40GB of main memory??? End Quick Quiz

Still better would be to come up with a simpler and faster algorithm that has a smaller state space. Even better would be an algorithm so simple that its correctness was obvious to the casual observer!

Section [*] gives an overview of preemptible RCU's dynticks interface, Section [*], and Section [*] lists lessons (re)learned during this effort.



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/node210.html0000644000175000017500000001241011672746162015633 0ustar paulmckpaulmck 14.2.6 A Few Simple Rules


14.2.6 A Few Simple Rules

@@@

Probably the easiest way to understand memory barriers is to understand a few simple rules:

  1. Each CPU sees its own accesses in order.
  2. If a single shared variable is loaded and stored by multiple CPUs, then the series of values seen by a given CPU will be consistent with the series seen by the other CPUs, and there will be at least one sequence consisting of all values stored to that variable with which each CPUs series will be consistent.14.3
  3. If one CPU does ordered stores to variables A and B,14.4, and if a second CPU does ordered loads from B and A,14.5, then if the second CPU's load from B gives the value stored by the first CPU, then the second CPU's load from A must give the value stored by the first CPU.
  4. If one CPU does a load from A ordered before a store to B, and if a second CPU does a load from B ordered before a store from A, and if the second CPU's load from B gives the value stored by the first CPU, then the first CPU's load from A must not give the value stored by the second CPU.
  5. If one CPU does a load from A ordered before a store to B, and if a second CPU does a store to B ordered before a store to A, and if the first CPU's load from A gives the value stored by the second CPU, then the first CPU's store to B must happen after the second CPU's store to B, hence the value stored by the first CPU persists.14.6

So what exactly @@@

Paul E. McKenney 2011-12-16
perfbook_html/img67.png0000644000175000017500000000327011672746063015240 0ustar paulmckpaulmckPNG  IHDRq/d~0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@f6IDAThAhWǿR(eH=JJtUaV0R(eA"c.줘DqRJCfyͼYJb7|fj@l*@m Бv@hs!M1il1{sy0GI6? @ p :2 He^(B'nW]p'{!Aop-Zx;o51JPg VD LU7 :IvWòinpsH0ai ?ʶ+}XJ9?:Eٛ /%>O֙mYg<(Ѡln̅獋>ڔa4'ke~`jaFx=m S5?ul?&E8Ʈ58](ӟ 덵[AF,?'+PdkY lq|N0ú\%=VxYi3Z=lMH );"oVi?+ޟr~_[#vհg{sB#Dmm8fp*̊䰟tWXlVAh{"$!kg$#˶xQgn{JU]:DŎGi:6Kc1)-+_|R# VvvNk:ξWJ`8Y1& -ٺFb:uOUL4+j'bvʊ?; V>j=daw]6ZDz{*z{),6̩u0t,6UAo61V/X٬YV\\{LBzlt%^Ԣ#IENDB`perfbook_html/node347.html0000644000175000017500000001302411672746163015651 0ustar paulmckpaulmck D.2.5 Towards a Greener RCU Implementation


D.2.5 Towards a Greener RCU Implementation

As noted earlier, an important goal of this effort is to leave sleeping CPUs lie in order to promote energy conservation. In contrast, classic RCU will happily awaken each and every sleeping CPU at least once per grace period in some cases, which is suboptimal in the case where a small number of CPUs are busy doing RCU updates and the majority of the CPUs are mostly idle. This situation occurs frequently in systems sized for peak loads, and we need to be able to accommodate it gracefully. Furthermore, we need to fix a long-standing bug in Classic RCU where a dynticks-idle CPU servicing an interrupt containing a long-running RCU read-side critical section will fail to prevent an RCU grace period from ending.

Quick Quiz D.9: Given such an egregious bug, why does Linux run at all? End Quick Quiz

Figure: Hierarchical RCU State With Dynticks
\resizebox{3in}{!}{\includegraphics{appendix/rcuimpl/BigTreeClassicRCUBHdyntick}}

This is accomplished by requiring that all CPUs manipulate counters located in a per-CPU rcu_dynticks structure. Loosely speaking, these counters have even-numbered values when the corresponding CPU is in dynticks idle mode, and have odd-numbered values otherwise. RCU thus needs to wait for quiescent states only for those CPUs whose rcu_dynticks counters are odd, and need not wake up sleeping CPUs, whose counters will be even. As shown in Figure [*], each per-CPU rcu_dynticks structure is shared by the ``rcu'' and ``rcu_bh'' implementations.

The following section presents a high-level view of the RCU state machine.

Paul E. McKenney 2011-12-16
perfbook_html/node211.html0000644000175000017500000002444711672746162015651 0ustar paulmckpaulmck 14.2.7 Abstract Memory Access Model

14.2.7 Abstract Memory Access Model

Consider the abstract model of the system shown in Figure [*].

Figure: Abstract Memory Access Model
\includegraphics{advsync/AbstractMemoryAccessModel}

Each CPU executes a program that generates memory access operations. In the abstract CPU, memory operation ordering is very relaxed, and a CPU may actually perform the memory operations in any order it likes, provided program causality appears to be maintained. Similarly, the compiler may also arrange the instructions it emits in any order it likes, provided it doesn't affect the apparent operation of the program.

So in the above diagram, the effects of the memory operations performed by a CPU are perceived by the rest of the system as the operations cross the interface between the CPU and rest of the system (the dotted lines).

For example, consider the following sequence of events given the initial values {A = 1, B = 2}:



CPU 1 CPU 2
A = 3; x = A;
B = 4; y = B;


The set of accesses as seen by the memory system in the middle can be arranged in 24 different combinations, with loads denoted by ``ld'' and stores denoted by ``st'':

 
st A=3, st B=4, x=ld A$\rightarrow$3, y=ld B$\rightarrow$4
st A=3, st B=4, y=ld B$\rightarrow$4, x=ld A$\rightarrow$3
st A=3, x=ld A$\rightarrow$3, st B=4, y=ld B$\rightarrow$4
st A=3, x=ld A$\rightarrow$3, y=ld B$\rightarrow$2, st B=4
st A=3, y=ld B$\rightarrow$2, st B=4, x=ld A$\rightarrow$3
st A=3, y=ld B$\rightarrow$2, x=ld A$\rightarrow$3, st B=4
st B=4, st A=3, x=ld A$\rightarrow$3, y=ld B$\rightarrow$4
st B=4, ...
...


and can thus result in four different combinations of values:



x == 1, y == 2
x == 1, y == 4
x == 3, y == 2
x == 3, y == 4


Furthermore, the stores committed by a CPU to the memory system may not be perceived by the loads made by another CPU in the same order as the stores were committed.

As a further example, consider this sequence of events given the initial values {A = 1, B = 2, C = 3, P = &A, Q = &C}:



CPU 1 CPU 2
B = 4; Q = P;
P = &B D = *Q;


There is an obvious data dependency here, as the value loaded into D depends on the address retrieved from P by CPU 2. At the end of the sequence, any of the following results are possible:



(Q == &A) and (D == 1)
(Q == &B) and (D == 2)
(Q == &B) and (D == 4)


Note that CPU 2 will never try and load C into D because the CPU will load P into Q before issuing the load of *Q.

Paul E. McKenney 2011-12-16
perfbook_html/node104.html0000644000175000017500000002615711672746162015652 0ustar paulmckpaulmck 8.1.1 Deadlock


8.1.1 Deadlock

Deadlock occurs when each of a group of threads is holding at least one lock while at the same time waiting on a lock held by a member of the same group.

Without some sort of external intervention, deadlock is forever. No thread can acquire the lock it is waiting on until that lock is released by the thread holding it, but the thread holding it cannot release it until the holding thread acquires the lock that it is waiting on.

Figure: Deadlock Cycle
\resizebox{3in}{!}{\includegraphics{locking/DeadlockCycle}}

We can create a directed-graph representation of a deadlock scenario with nodes for threads and locks, as shown in Figure [*]. An arrow from a lock to a thread indicates that the thread holds the lock, for example, Thread B holds Locks 2 and 4. An arrow from a thread to a lock indicates that the thread is waiting on the lock, for example, Thread B is waiting on Lock 3.

A deadlock scenario will always contain at least one deadlock cycle. In Figure [*], this cycle is Thread B, Lock 3, Thread C, Lock 4, and back to Thread B.

Quick Quiz 8.1: But the definition of deadlock only said that each thread was holding at least one lock and waiting on another lock that was held by some thread. How do you know that there is a cycle? End Quick Quiz

Although there are some software environments such as database systems that can repair an existing deadlock, this approach requires either that one of the threads be killed or that a lock be forcibly stolen from one of the threads. This killing and forcible stealing can be appropriate for transactions, but is problematic for kernel and application-level use of locking.

Kernels and applications therefore work to avoid deadlocks. There are three major approaches, locking hierarchies, conditional locking, and single-lock-at-a-time designs.

Locking hierarchies order the locks and prohibit acquiring locks out of order. In Figure [*], we might order the locks numerically, so that a thread was forbidden from acquiring a given lock if it already held a lock with the same or a higher number. Thread B has violated this hierarchy because it is attempting to acquire Lock 3 while holding Lock 4, which permitted the deadlock to occur.

Again, to apply a locking hierarchy, order the locks and prohibit out-of-order lock acquisition. In large program, it is wise to use tools to enforce your locking hierarchy [Cor06].

Figure: Protocol Layering and Deadlock
\begin{figure}{ \scriptsize
\begin{verbatim}1 spin_lock(&lock2);
2 layer_2_p...
...unlock(&lock2);
7 spin_unlock(&nextlayer->lock1);\end{verbatim}
}\end{figure}

But suppose that there is no reasonable locking hierarchy. This can happen in real life, for example, in layered network protocol stacks where packets flow in both directions. In the networking case, it might be necessary to hold the locks from both layers when passing a packet from one layer to another. Given that packets travel both up and down the protocol stack, this is an excellent recipe for deadlock, as illustrated in Figure [*]. Here, a packet moving down the stack towards the wire must acquire the next layer's lock out of order. Given that packets moving up the stack away from the wire are acquiring the locks in order, the lock acquisition in line 4 of the figure can result in deadlock.

Figure: Avoiding Deadlock Via Conditional Locking
\begin{figure}{ \scriptsize
\begin{verbatim}1 retry:
2 spin_lock(&lock2);
3...
...nlock(&lock2);
17 spin_unlock(&nextlayer->lock1);\end{verbatim}
}\end{figure}

One way to avoid deadlocks in this case is to impose a locking hierarchy, but when it is necessary to acquire a lock out of order, acquire it conditionally, as shown in Figure [*]. Instead of unconditionally acquiring the layer-1 lock, line 5 conditionally acquires the lock using the spin_trylock() primitive. This primitive acquires the lock immediately if the lock is available (returning non-zero), and otherwise returns zero without acquiring the lock.

If spin_trylock() was successful, line 15 does the needed layer-1 processing. Otherwise, line 6 releases the lock, and lines 7 and 8 acquire them in the correct order. Unfortunately, there might be multiple networking devices on the system (e.g., Ethernet and WiFi), so that the layer_1() function must make a routing decision. This decision might change at any time, especially if the system is mobile.8.1Therefore, line 9 must recheck the decision, and if it has changed, must release the locks and start over.

Quick Quiz 8.2: Can the transformation from Figure [*] to Figure [*] be applied universally? End Quick Quiz

Quick Quiz 8.3: But the complexity in Figure [*] is well worthwhile given that it avoids deadlock, right? End Quick Quiz

In some cases, it is possible to avoid nesting locks, thus avoiding deadlock. However, there must be some mechanism to ensure that the needed data structures remain in existence during the time that neither lock is held. One such mechanism is discussed in Section [*] and several others are presented in Chapter [*].

Paul E. McKenney 2011-12-16
perfbook_html/img308.png0000644000175000017500000000164111672746104015312 0ustar paulmckpaulmckPNG  IHDR,n 3PLTEMJK# b``mkkXUV856KHHC@@wuv.*+ptRNS@fIDATXX %DXn|ࣳٞq1$'![vbPy8nQꈷ, >C ='˭UX)?8vu8cJvCGNLӥ׺vyIGRw$ 6.Kb' 5⳼S^:/HMqB;&'Z͖QQZI%&j bpZx7::YdDwoh.u[ȁW.b= bCf5HĶ%K=V;޻|^\*1"2D)|DQWhwpT^z@~cЦl򖍪uohILk(GKr&Z NdZѺF_I`[C{.f__Lۛ+K3x};<[=_7+ Z<|+@N.B{WԆ:r,?ӯmj˓jȟ˴3*W_[ 9Cbnj}mh&C^T>49?ɱ>X\%GxD<F*e@R~6y t|e9sP cAGݼ|N5J*]7ΓnIX0]˯~$n̪em@Cr7?OTǝEWꕅDrYclYlP%#&>4HDB[Oʎ{Oj[퍿4|.X4\U6[ )!,L?IENDB`perfbook_html/node277.html0000644000175000017500000000474711672746162015666 0ustar paulmckpaulmck B.2.6 wait_all_threads()

B.2.6 wait_all_threads()

The wait_all_thread() primitive waits for completion of all currently running threads. It is the caller's responsibility to synchronize with thread creation and deletion if required. However, this primitive is normally used to clean up and the end of a run, so such synchronization is normally not needed.



Paul E. McKenney 2011-12-16
perfbook_html/node291.html0000644000175000017500000000656011672746162015655 0ustar paulmckpaulmck B.4.6 Usage Example

B.4.6 Usage Example

Suppose that we have a counter that is incremented very frequently but read out quite rarely. As will become clear in Section [*], it is helpful to implement such a counter using a per-CPU variable. Such a variable can be defined as follows:



DEFINE_PER_THREAD(int, counter);


The counter must be initialized as follows:



init_per_thread(counter, 0);


A thread can increment its instance of this counter as follows:



__get_thread_var(counter)++;


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:



for_each_thread(i)
  sum += per_thread(counter, i);


Again, it is possible to gain a similar effect using other mechanisms, but per-thread variables combine convenience and high performance.



Paul E. McKenney 2011-12-16
perfbook_html/node249.html0000644000175000017500000002117611672746162015660 0ustar paulmckpaulmck 17.1 Transactional Memory


17.1 Transactional Memory

The idea of using transactions outside of databases goes back many decades [Lom77], with the key difference between database and non-database transactions being that non-database transactions drop the ``D'' in the ``ACID'' properties defining database transactions. The idea of supporting memory-based transactions, or ``transactional memory'' (TM), in hardware is more recent [HM93], but unfortunately, support for such transactions in commodity hardware was not immediately forthcoming, despite other somewhat similar proposals being put forward [SSHT93]. Not long after, Shavit and Touitou proposed a software-only implementation of transactional memory (STM) that was capable of running on commodity hardware, give or take memory-ordering issues. This proposal languished for many years, perhaps due to the fact that the research community's attention was absorbed by non-blocking synchronization (see Section [*]).

But by the turn of the century, TM started receiving more attention [MT01,RG01], and by the middle of the decade, the level of interest can only be termed ``incandescent'' [Her05,Gro07], despite a few voices of caution [BLM05,MMW07].

The basic idea behind TM is to execute a section of code atomically, so that other threads see no intermediate state. As such, the semantics of TM could be implemented by simply replacing each transaction with a recursively acquirable global lock acquisition and release, albeit with abysmal performance and scalability. Much of the complexity inherent in TM implementations, whether hardware or software, is efficiently detecting when concurrent transactions can safely run in parallel. Because this detection is done dynamically, conflicting transactions can be aborted or ``rolled back'', and in some implementations, this failure mode is visible to the programmer.

Because transaction roll-back is increasingly unlikely as transaction size decreases, TM might become quite attractive for small memory-based operations, such as linked-list manipulations used for stacks, queues, hash tables, and search trees. However, it is currently much more difficult to make the case for large transactions, particularly those containing non-memory operations such as I/O and process creation. The following sections look at current challenges to the grand vision of ``Transactional Memory Everywhere'' [McK09b].



Subsections
Paul E. McKenney 2011-12-16
perfbook_html/img173.png0000644000175000017500000003573411672746104015324 0ustar paulmckpaulmckPNG  IHDR`6utRNSىH IDATx]lY#bLe62&XEj׻%S oIޱ p/@yA,!⑬bNCp{*35lSB@aihgHH~Z)V`]E`rpiQ&+E!>3>2#2#LU3s9w:I/s⛶q7/?<cA{`Y)6T*JiPiQxF7ͮ\0 D/jL6hF: CY>hl3Y {ƌ"ڏ'kZ5NNNNĆzHw埔ZLМE.4fl |V̽ @vHc+VZZ%Y/ϡmHT.ow2J Q,9DFi7''&&:w9^o2dǖgTvZFWlՒoHr-bC&h1/[*AK&XL`dm`gWFѸqh4|h +;ê3 SG1M=Lg0b@/ Y| oVT6%}6 #U,I=T*a*yTZ[q~*`k 96y'.3bP/&[uc1uS[dx^qĮ?T!] <[g)MqoQ Td3\ Cޜ.*(Oj)0n*3Ɖ*;$o )&XeɢX(vABg 0K\/lj MxҶqcMWb"םKmqJ{A;Wjɨ$5W35/q`׽P&ۑHS:+PpBuURҽ}Ez-*Up۷<ݲ"۾msW'AIlz@=H]\'bs[Cl($Kr Kr&ʭGJ~w>isTc𪗟+i_DUn\'e%7f?9d3`syU>4VxC(MNZyWȻ] e: TTꇩx*u!IFRE=XEmT֬'K;yuu }}'3>Ik+ )m(Gc4y=$G\hMrpD' HbKoۑV4K6X7P"1?1U_$C^dփo(e>˙6*h[ 1.I: "hWଘ/!y伌׽ 1YT*z]]˟Q2kx3N@#@M@4) (t\&،EtPE`bPQ= (]Вـ$#Q ߞh''YB+}PJӷAǒ˃'%h͉Q0Z@kt,n {v'β"蟄F<_T8:&G5pd(y~'owx1hOM.jA3sO"} nȌ-MӴihiitr(}P.ҷ,r58Lް2"Ȗ0{ r99{+06#/ށBV9)TBvPCfS1La(#}ޤq~M(WDg7R-`mE+ dRA35=T{H*b.XV(֧bĂ(;)fSLFFErȩTxZACU=V3I`H+ˏ/GL~/[1,Ryd!K 15X!L_^J~faw,^G(i9\\t=p'x_ +c)h0{bMaZce$QtTuƲSl01ؿrvxP>E,f,$/!8S()M37oGV,߻U_3”4'I@?, Dʓȶ ^Ifc|t4>BO.О?,?$8\GRxߓ @Lq ơy޼EVT.?t>8.hPz6ٿJk?WuG?zۯWAg*L7[к0>o]ߍMVz^C"!y諊$P n# ύ }&&`rܞ&!ylXs@ktZ)M''X@e(ݰ YQniywu{81͹AI q6̌3j Jɞ*/sOFs)v;G5-q$_2J Oر$;c4zP,WBHg9b?l9O%B&?nm,6^1U{S3P`jvktǚLzE /:(+u14VɁbWajbIoPJ]F $&b^L|4韜}'''ɉN%xvWQpx< r$"2'oOIc,D7Wg3zƁEŋp4'F%yLcJ|ѭSdsL^B&8ŐwI8b|LƐ5%8ns[Ix  "i7wY(^])T';iE.]j8!ӧ}>%V&eLd` }eh'Dczf+Jv* ,0l fʤuvb: Kko7 YRCް |xLwOi_dm#K~X',tsSQe46#cښXMGPV[ʐV.(|q}aaZ`:5 ھZ:ٶ1ǼdwΕN2K i @,l˘Z&*@&Cyr+C-CO ,˶QzE+=PcmAo')xRH*2n+KRw)9qgHhÌ *Zg뺒.ѵmrw}dRw %&s^Lna aIhآj9* W8rq^sh^l''yz0*ެbŰ I 8.aK*"t ds2bNhI:[ɦt2z:m! l?FSL޻+o<Y9:6UkD"hдsdL3ME*tbnGSrMcH?}μAúwKzzXyU9};Y_3m㳘m(2HٹrZiRfɊUwѡO$w3 @&gJ3+%k `ofZR~nSBِ:^$,NlFT тޒhZ6~YX1~%5]*(, sU-%KzZJUP4ө!6f;]?Pi2Z3/?oHu GeGus2⼌SYw00χ\{v7XLU;bY%pmRYaQ<<)5P~a(q`()m4VKZ1P3Kˢ.*XBJ2R!V+kYI}hz&GN9z 3rV8oީhUKKyR@NϤom׫W5Y~|CSB2Z4 CekLW.sxSpVt0Ji/gqtgJ.B~S?d!mQP;U: LN-Ue9n:+E׍'j Y`O\+<͇3%4;bļ#B%HiLjYՊ,!g7H#7V)\TPo 8xxyA:!gsXDtviŲK6|{=$ut)=E/'(Ê !˝Hމx8C%6ƵG$9ZϨ8!IW9{bQ,v)LcRFAzsXʃ\bd#뷍 m;^co$y.W =Rcm˭onC;g>y^avk_Z^0IjQ}Ǎ$]__$ 3*Y0,z@˅wGkb.d3Haf ?aki#MB v ;eEE\4S]'n%Rw/W³4.5Jf9FV{%a[").β$zVXN>L$~mD1 RB8s5I( ֨]#VI\|vSdt19Qd(Lq5nC|l_`ODe1: }La~=ZLr\(8v8aF]ǁC}pL8O?>8}[֓w[z--Owxw?er~ύug{px 8>ÉvrZ۟Qr?dz|~O~g_?|'hv:=UD^0M72=0j=G@*{_pp ?FԶt=u*~<;/h r^9xft Ub)[gu5s$':f]v8Ki &vřEcyAN~% =u֒FD`{HŃXfGc9qģw@t茤D, ]Ů1|B H74h{ѿ5[JfqsP(w@Q*5[G^G_a9.8DNO5x J"8ss&'b\lwM86X,璽zњ-V z~LPΤX,0cjj%؍ ΣbFCRlh8pܛ1TrҢ/!^wiajkҖ ?%_{&^(WKQ2aSODSl$ٷIK~we}e6mOfbĜˏ~VŇ>S"wk$(]c@č4מkSc5h5'p]˻&J U,]jH崹ڑ+s 2R9ЬWdrE|Әⵟ42lNKAsci$cdX+lfg1T+KC8t;(ctEN!yI>iP1=esUgj>#i*id@evm^hݹPJ^/\?OOl1u"QlLFqvm^>$õWX~19y֜>fȉ=--Z#8fsp ̝F]u+M1[;{`lp~lÇhRkT  1Mڟ!/nbNv)5oeG%s&U$jrvNh2Wm8s+sE(FT=qj99#6i}#^u\$1*s\>$[+"߬`M by;Zѐ5 xFhe+_-R{(r@"'aMKK& HmQ=J%Z+/3_} pӕP` Dd t*ggVH%)Z/Umo<3T.1Z9BLtg+5W;w1=#ݼI Cӄ%syX.w$(fBMhU윌4SlDudbgwe ;K\~t%e\Vb.-KY)?V+k`$LsXMWFqmɴTT@NB ZjTSwGsU9iL ΃ҡ%ұ:e ͢h|]|UN2;E Tz4N/wSYZ[*5 Pa \+#*`soGC pou%jh3*=αRWg؝J&@Q3;QPut}ej_ ʥ?r~`"4T0gD#ϙ\fP\S"wn^H3iedtJs)J-A:## U岡LWQGxLʋ_ 5[HĢ'C:DS7iiMqyx3F 7iiaF&]@#0!.'x:jNZ߱9B=+2y4 l-,OɃ_Ib L3اo/zGZ*]ȶϠ1ɃZ1@KBp۝\H^"Kdd~q5ﺓu^"-+ k;jngʮU21@3O8*/XrQo QsP^ n}Q{nBQ&j6c"i$0P3X?]F,#7dS⼀JG7Cԝ@~ v3R_Bd1A|d$"QLguR;GP%`7#xΒ 19y 1Q77:iň@NlH[pvYw7JyzZc>*cNmhΙ!(uUPksH2Zc>gr˗ZVBUk+LCf25AIjFmw4nf\d:{3Seoo<7-Rx}<}6 Z~;gf8L(A%CLV?o}k3_yQޏEH-e1@x%f|~&[]YP&!Fװ{wڏՇpQ^W- m9(*b @{qyU%t;{sfUc>cXg8/74. 1pK_oZ>0ns_)E`.^vDwX dAd|h%k}93ĊCdeoI={B $D>,)T$WÕn5: ޱJ"],dod [}Xe+9]J! жKh_v68l&? $|u|GMx&^;z-nemQ]e)Hu8pu,6U2!m$"Dl(L~CA[SAosޛ9AU2KDEww/`wD2`u2*\$k1™1xs&1t J%u?ST߸fw:Ag"]M@\+. `rz5zͼLޗWo^g`]Vf({3vgB@B21{"W/:/<=l:' V~]zeT{{ @uא~9Z$nV/2,2]>'RLf {,NI W33o']+ g.=FNL4tʌk@ƻ;_>˙j2pu}S-Μju\~|_yWީnlw3bNlVקVVX_Y\ D$ˏ+w2c1T{ʿMGwA.|$0I,(YLg٫a鿮b{}/vB/~ sЗ۶?{H̺ y^6.D!bx=\&Y"feגx/|:ULd]]/A3~'cգݿ+Iig2߿"=^Y?+-Nd4'-&+yq:fkj"VZ} ꣣xLUo>^?4gԟ}|WҞ^?_=)yu1Y!8"Ngb^]_Lmɯ~U1~&|jM1?_쯷\ީ%j&&{";'߾em~[ȟPg:&ygEjYA$Y`AU[ȉW2q P{CGz7"il:D`fl&+y1^;/ݼ0YNhN8K:H ۋ>0~,^< ɞC]"l+qa#ib_Krk&=a$c@H˲XͻW`pCg|⦚UyZwr,IؑTg a8ͻD0\;c&緭 &l;/9̻<>q싳mko;πg6!3:pZ<$,ӟߏ#}`Do[;}Nlpn8K|?H`lU( 52 -iY^XXN-n$vgNa9kH>}mzX0}oqƒ|Qnw;NsD0'&qe%"BlcW%R@߶m7r 1zzEkl-l咺.:ۯ' wYxz>wV&0$,DG>c,f̋f>~獽w?z)o=nkjr8c19x_+w1[+@ZA*Jr_VZ.њ: pM%js kaP)aB 9J>ZLq`W8 иᰟױ^1@Dv^sC;BaEA> 4&L=Vɥ`zX^10 ǿhN-|tyN. چ~^"{Eu~fkcC.J y}1c`|pnvqnvĹyKs޲F#=;Xr06&+*yq)jg3Pk4;X붵Scxa|kŸɊBj1֒eB0pezt:CmuJ:=Oa3Xb8rZmk aB7 ^GP3w8J;`a@o[S^:@qP]*RyK^ͷm6+3{,;Xh}ktrM7DUqkyfcQzv1YqCl'8]E+Lϋq8`ɡBW^Ҕ-wjy1u Zv~s9;E^;q|TR+jJSY:6 &nJ#0 qP<8`eA;Q VJ^N׌"r@Û 1ZńhU"kVf'$Doѝo:2B";~(pkP2rUHc`USBJDddՑ,Ɗޒ}EQ޶fKS\[(w l{{/x.2)!]b*Qᔝ"Nb*(|\{Xf3d(b ޛbӵi\U%,JCVCIb }d_hP]{  C=9u`"mHO֚iPU=V>4&Ōa%vDV*QQrbG8L 7?@<`I; k7@D|LOe̓q>|e#1ἃ%̓ @yG%l_Ê]dRxR8vɊB. ,10;a$4QrhIENDB`perfbook_html/img252.png0000644000175000017500000001127011672746143015312 0ustar paulmckpaulmckPNG  IHDRBvBPLTEb``^\\MJK# hffvstommmkkXUV856C@@wuv.*+mjkTΰtRNS@f$IDATx] ˂{Yq<@Q8{kBDI& oRtRH_AtpbSJ) \qV BmvJҏx&\&K#ܛ4Oa{7˵cT6XHpm7>*{xpa&C5xY!8|藰Y|gաRSׂc糩 SZMfd?". @eZ|*hg=<5Pݱ&:?A +VNd tBIeGhUj }vl wxLۖnqP=BA=,ێں +YCz#e_xd]n?!7B[7j1Ȗƾf`@U,YOHg@Ãfgxit潇G 4M# <#U᫥o:Q!áP 4V 4;y" $JfM'Au nTs8 $Eބ{bL^qG+`("՗Rחګu5CcIxA^;fZY!sN] JƂ>ϝAIƥ8ZN"MZQ#ɚp̡࡮k- Bqrv;6l 4 eXru|8N>[f-׌Aj8PTg=xnHUǤ͹aRN&Dpw zǦ+JI2(5 G8,ߡ`|?A_jLrzgǃz> ~&AقP6gxE:%gnh9x:u-fzY1ֵk@p剥XEWhVq๴vqĖe"\DPSv6 ;4ig;.gΦ#2c=wFrG8dǹ"۔M -|bi>*\i#ߦ:} 5xSiϛP]8ٜ#cϟMCH7c8?a4MY~V .8 U QA(Æ,v "۹M,<[rN * ޲F$ImM3QN"  8״AuTlhd[g93ȡBjFTb|esd/-:/K]22Sct|!Q#GY&f]fQkC=q|!~7bc0̅ëQWae͵tɐsЗ~t%(CtH |~]҂h4dPh GdC٥㊒eڑҒ伻ߡUIxY @7"a;xY `]M m9U-P{ټJZ9=?cgXdo]ċ& [vE9?@ߥswM6SXr1y6]O%Pӄ߲Cg%-} ]-,vIБhdomWid, D&49(<±#5b2B%39R:r6"9tK*LUХPܓ.) *|`]]vq>,/>F}Ywk$SSwٍ7nܸپgGr-!&su9r\Qu=* Ԍ¿jwY>ߥ Ū{y~5eıjv#i!p=>`n8k*\&I7M(MMQhKk jU HrAUb&x""_?ɿ^H{2SS9Jkbm?b}U`£g.p0Jf1//f}_GlZZ-,WIGg_D0_mɊ*=ν%ՃbLt|Bff%lom !> NdNOI:=IzsrX;fbE!Olo, k^7IUIyxSeoaXGh_  J6$ @uy-Z`b,߆00Bs/ş=޸+ak\~[qoܸ8xYz:ZZUZq\/9]|!7&y++?3nhen9]q$]<gON{+^T6LbI2e?bø۱؏W;~5N^l {oc|w`,vƍ_ޞ-'Gw GHs *>"Ko=mqy@TPKk7@0>L B@O-ib28MJ+Ҵ,?38ZDm7z\˷VP:O7fZP"zC.7c} _Fa}v/!@Y7pt^`k[A>HlO|6 bQ D Sh\N[g6]mG& Pke;n\Cg6~KB%Jt=nGK` wn4> ѽg"~a?X`VXl\f X S8cL=.2,7YƃBv,Ъ<~)O;{F9P[*T'LAMK5xݜ#jZb:l@M ًsz8ދxV@mҜ[B+BיUkUl:jIU7TĦ|޼ m\i!wŧWebWOBJ܀wHxԅ޲Jqm[#^li3|t[ -,ye^{yWlo?>Λ?;j3N{=),?@K/(CXH*.ge{1ދK_2w迾+KXc* Up~[yHwv8r!m\AjAŵQzyh.0 NYv|>to#ՕӸ~ÃovkM_~kw%SQF/I2u_[0(/7 ;B\˿ҹEgiM52=k!=`.uLٺѩ9@i tcW@)a eX!kL1'e i.H/C Q}7e ~ 7-$[UզE;-_GK4A}bcT#425 V?)/|'m>5\oYеhH%ՑzY,JYcE>m؅K|mej8dX6"m6:$6JDSiZ6N6T7=X};VEk(/r I#N a.-jטfS^"nT@]/cP4 U #f/7lbI'L~J*\&ٌF-R{m{w 9(Bë<ɥ:`JG3a)QoEr[dR4\G 2{1:PIlk҂ė\nkkUԥFKNJX.>=W|VXOf+GnI@PbPL5Ʉ~y[wQCM7]%Ҁ dmFnR]/cZL@OYhz5 k&-@Pd"b䅚8fX&{2L8D-}-4o#~Wgx@ I"i_\n_{.|Nt˟ױ~۫0;a!z A`'{đOB^ ӯxmU&Y_}e[Cؠ WtRI8S .YhVW ¨xgc4]/mAo\_{ήey*V*Sgc=T˭k]$ ·Ǚ+)q&J({1Pv,˃.~P]|UAZck?cL+э7\$L@$8;+hTTEd1}~s|ˍ%e$*5r!*c$-:(vu\uIGMԊܺjd\Ʈ87c۳V]4t?BƇ +SltzA+\c}]y֧igtR#@eJteXeC?bwV# 5MR/=&!*hsiuf^+Tɓ(:a0 ,@dx'AH$xoX/P󳉭+jyP)H* B*TG;:I0I{Ը̌J0z>ݜP%Wr]/XvJ`+ g(J-g`ө[[X'9 4<|%POS`M7, K%Y=RJs cJbuGwtcׂMlj3V([?}Icť"dwzKfϢ=Ap?=Iߨpڙ z?o+=\6q68V!`7l;AP'AXH1jT_K47ƲPQMJw}ֻ/x%)tvJEz@~{B=U NY|'[VqBfߝ.Te+p2|%[a;щ3w//{QVgF-찺kb)萛!>/lKͽ/Lp*V-wݟKCqH稣~@eĘu?wTh+ˠ'r;Kf'b!+6ѐ&bkIUt"献>aV]4HLLo2U Dֺ,~J3#xm7yu&e$h9cVpO@r#6Uں^.M2dީNzA)x4T΄9h~֧9iM<hxKQtVZ$`zfe%?|lm RX%FZkҮFwUD%J,/Ɉ?!^WĜzز?$ {jg/V@eK8y5G2DQwWIQ$s{щʥ{>`ipP{LdgZi$F"< jz`sϒ=pDO=R [X$|ttg 9=i Nf]iC Xt2AwqI}2Mh(L<j-O | n&LZ@tS!qY4gfJNjfĬSeӕudElvfhltyd`⼁3f7g*Gԃe;MfS0ial)&AewzJRJUϗ2j9Xzts[NrI ]33Aˠ$ VKjo&n7f)ʰnߩ'90oōM|3x/oōM|J~PnoB׋(r=nEn}M-(g"cZ\py{5}D="x״O}P&,z^kHWE&Zz:{'uv[m`O2-H;eJլUve kD{_Ud6 7Kƈ0QeExWk]i*`4W+jmoH+|=\<;O5_51b'ZUh8nR J]iG`m nVGcW;2|ߊݷq{ӄ7n8 [S-eyruN:eMwhU8-}*+w5uP.}+ t/-Ў *O7nxj^ei~xV$l܃/\z[*{VC4ՈF8|8ɂC.TR5+:GVWR5#dJ^Hlw^~)kp%3D;Δ)Sblc4ށoF&GCeb=Bx0S{r?M5l;b j^&lHORx>~%JVt53ēX`{u5|Vե?9/꠹u8/sm(ɡx#цr[s f 7|ܽğx! d,nxƍ oH1)JO #V dh͙cJ¨DdF5AK6 icn5b(!7aoieFu' m{dĈ;;}GY@^q%<4{xץ|J0dfzUl#eG+sԷ*/2NQ˕F6cTO</6xtUU''Td|aW# ȝ̾cyds1njBd2p |~ć0~d(ߦ5,r1-fU7.FGfY6~bә.gܽ{Qx{j 2MG@gMoׯ R=Q%`Q0n_A+BlaD%=Mj7Ơ*9<]l¥'?v0M>G5Rͩ".v(^txJJV::vKir0P͂nhrK]y⸵8~.҃dSir4 aM7C9KSJi ʡ'Orqv5S17D܉X%]2/KĂw98k9 Ǹs:CȰ&;d]K0/'kR&ܸq&W3AlETQl/sDEYT}թVǓyom^EvYyb8:[з?vfmrxXW3{]Ռ޸q/m3Ś3>Ц߰N;ߑsi#F-SD? to&Qe؃jtiU]4RԁȘ ii?ِ3}(c-E6I A E8p|N:^v!w`눇g}?z/~Mp܆X{taށ;#c>/3,h~7.ED>5ZsuŽ`Ie% tp2djdEwb1 gc``nfHsM>hcMJ? YCọX7[p|*Gľ- o= :+'lb(258&<9wo`sAn:~)7@%V+K8n%.>pDK#lۆ8H[˼dۦbO»[.ۙRec[T< Ƥ{s}旳9Z%gŞ>cpۜ2tG&n\L;$>_$)9R$IY[U@!0**,$tFZ!I?r F. Answers to Quick Quizzes


F. Answers to Quick Quizzes

 


Subsections

Paul E. McKenney 2011-12-16
perfbook_html/node5.html0000644000175000017500000002063011672746161015477 0ustar paulmckpaulmck 3.1 Historic Parallel Programming Difficulties


3.1 Historic Parallel Programming Difficulties

As indicated by its title, this book takes a different approach. Rather than complain about the difficulty of parallel programming, it instead examines the reasons why parallel programming is difficult, and then works to help the reader to overcome these difficulties. As will be seen, these difficulties have fallen into several categories, including:

  1. The historic high cost and relative rarity of parallel systems.
  2. The typical researcher's and practitioner's lack of experience with parallel systems.
  3. The paucity of publicly accessible parallel code.
  4. The lack of a widely understood engineering discipline of parallel programming.
  5. The high cost of communication relative to that of processing, even in tightly coupled shared-memory computers.

Many of these historic difficulties are well on the way to being overcome. First, over the past few decades, the cost of parallel systems has decreased from many multiples of that of a house to a fraction of that of a used car, thanks to the advent of multicore systems. Papers calling out the advantages of multicore CPUs were published as early as 1996 [ONH+96], IBM introduced simultaneous multi-threading into its high-end POWER family in 2000, and multicore in 2001. Intel introduced hyperthreading into its commodity Pentium line in November 2000, and both AMD and Intel introduced dual-core CPUs in 2005. Sun followed with the multicore/multi-threaded Niagara in late 2005. In fact, in 2008, it is becoming difficult to find a single-CPU desktop system, with single-core CPUs being relegated to netbooks and embedded devices.

Second, the advent of low-cost and readily available multicore system means that the once-rare experience of parallel programming is now available to almost all researchers and practitioners. In fact, parallel systems are now well within the budget of students and hobbyists. We can therefore expect greatly increased levels of invention and innovation surrounding parallel systems, and that increased familiarity will over time make once-forbidding field of parallel programming much more friendly and commonplace.

Third, where in the 20th century, large systems of highly parallel software were almost always closely guarded proprietary secrets, the 21st century has seen numerous open-source (and thus publicly available) parallel software projects, including the Linux kernel [Tor03], database systems [Pos08,MS08], and message-passing systems [The08,UoC08]. This book will draw primarily from the Linux kernel, but will provide much material suitable for user-level applications.

Fourth, even though the large-scale parallel-programming projects of the 1980s and 1990s were almost all proprietary projects, these projects have seeded the community with a cadre of developers who understand the engineering discipline required to develop production-quality parallel code. A major purpose of this book is to present this engineering discipline.

Unfortunately, the fifth difficulty, the high cost of communication relative to that of processing, remains largely in force. Although this difficulty has been receiving increasing attention during the new millennium, according to Stephen Hawking, the finite speed of light and the atomic nature of matter is likely to limit progress in this area [Gar07,Moo03]. Fortunately, this difficulty has been in force since the late 1980s, so that the aforementioned engineering discipline has evolved practical and effective strategies for handling it. In addition, hardware designers are increasingly aware of these issues, so perhaps future hardware will be more friendly to parallel software as discussed in Section [*].

Quick Quiz 3.1: Come on now!!! Parallel programming has been known to be exceedingly hard for many decades. You seem to be hinting that it is not so hard. What sort of game are you playing? End Quick Quiz

However, even though parallel programming might not be as hard as is commonly advertised, it is often more work than is sequential programming.

Quick Quiz 3.2: How could parallel programming ever be as easy as sequential programming? End Quick Quiz

It therefore makes sense to consider alternatives to parallel programming. However, it is not possible to reasonably consider parallel-programming alternatives without understanding parallel-programming goals. This topic is addressed in the next section.

Paul E. McKenney 2011-12-16
perfbook_html/img216.png0000644000175000017500000000627111672746026015317 0ustar paulmckpaulmckPNG  IHDRCJaKPLTEb``TRRMJK# hffywwmkkXUV856iffC@@A>>wuv.*+w^tRNS@f IDATx\ c +[gd2dW`qIcN.!l@%Y]cLݬ^!Zp>jolK,jNq<ӆzBfdxv9V9OpɅZ;Ů'0.胉H*3s@}NT׻f1%1A\_ >ˢJQdvGb0 [!,Dk绋|h=ʲl#J{G!hMh1P.zi ȥAy#?]/h,Y:WVlq;._[kzrQGTDIo[=q1 [DS] -6-r6&EqY{2CmleҾI+%9ѽ.Ԣ5Eu~) ղӹ7ܧϚU4|҈0qo'  Pj5l ´[%tУaB!|ځm U9qeg6Bf:s%H-M.V\Sp!1d 6M3h͒iBkhqy6P̈5r@F$WZc#+x10 mrIG)fO1`>`:y- Y'/:H㾞_Ƌ:-,rW g4=ZW-n肥UĆWJrGznQF|q̝v3 M;_p/umJ7 tc@'Im:?H“!߹G #|X'$en'm6]J-C:\҂Y ??^d*b,(dt]H,{/WՃPɭ6La9:dm;ơON"pn uKq1ejMm6[ԟU0>@66MnsnWd*Wd@{$;Z-|0jy Hl%?B\0G bVd%H^Z{""1PZ!QF@y9ș tUH\#ed=KS1|ޣ(_H,ԀRiKdѯĺd;DoY&!RBj:!qGv(Z`9YmB Zsƛ| /ʑ"_OnSIxa^& P Q0d[n=CMxj&ǣaݸLG2z6L^ߋdxpoxX&y 1&;:wEzAZLۿvI! /z},3 "K.=`OE8;!Jhj嘭#jy V/, _`}=Y2޻nhIW܏O)Umw+#$FW 6 GT[`sqCLئ|6mfkߘh~v=xç'`\gtQHVrr} bb+w;fj]fr!>hr.軺0zZjSX*&6aQqtcRz7;aDP|N{6J ل@tkaZ~F[m<5\8^܆1heSd2>d ׊~ p:~ކ#^]>_s_?8HpNjR.闷FTIJr)7v__0G< \װ26+o@G6,&5wFpMi>Ë0:1ʞ2Gk]3ku.Y]!?)81yNq[qdA3l䕡TK`W}\j+|I%5wj}ڌ9vjmqЧOE,l+5eB ZHƀN^27܍kKcX(pK~:&.X'627܍kSi89)E2^5'> >/s#`&ۻ)fx 5Bac ?~`"N_حݳD~Mb)@ =уW}# K$_CyЦ#C!VIFV8r= A(i@װ$W]_;iFD5jDd>8܈B4% c o{c%:wb Xgf^3zPӧ+PCVޓ5 H(P[poe$Ψ(#P6„ݗ/vF|v{ፀ(-7LJ/bAOMga;#yj5O<ۢyr^Bo+u]}[KZ;)Ӟf;2?]45_ݝ]LJhE$r6|]VH"Eu!RCҒY}WaϷGVYC:&a jf˨ڸd6[ Nk6F͊jK932niyɨk@S@e3cڬݿWƎLe{.#]PlpL]D#]2rG D#3f:T#=n55 Et'A[qFjWƙ~dfl@y*dY1;C-R 3W렍?Z6[kY1֥Ψ:4?pX__O7]un{X#||fc+5TmK?tgchk'j#4*^VO+уΌ]k1Όם%Gma.|HnQR ]!AYn<=;ez{uETD^gU4ruF0l̊A4{1oBW?Mkq@Pmj3N>b:+ZLSYtU7EEj;]N4{o#Mآ,DJk@(S`ظ#=@d¸~{lWϝhs\2U 4<:'LP8m+ ۟5G㤫hQD.f%#SKz 5HP%ylLOKŻrQh[.X.f%i!/ ^ϞwBU5 "D#P(ؐ++2;DL(v[HIHth{Ity|ʓMՓEPݟ}߆ 7ō] [h8:KYGۑŒX ug̈M9kȨLwdP!$i83)v $wG5NiͰшot + +b>Vs֤Z]5;sV}VMsA[wӱ<__0եm[vX.f%vx!،46~ΩX3FSX☮g2]IB^ym|l߃r`>l7ao;Z0BcU_;bY`>xNǞE(E"YFqy.cyͩ꼿ᘚ<| %]qKdy7 =vi\EMfj9lW">h9o8zmsҪ+yc9 ʨ\_wrE'*86Gae@j}r^aO!v(#`{;|'iWl\yqƕfȯ+:M7beTA2 Pc4h&˨ξT`؀pz/ >,41RFuC(!/o xx,uˣ兇,v8y<+6<ظ`ʃ+6<ظ`ʃ+ S1`ʃ+6<ظ`CO\vN`]Ih3p3<(%jB6}EVo5y<|[?ZlSkyIPy+|l_ IW`~궵3vL.`ϡs4:Q0L6 9FcBNs̓GsY~Uj3)mf+6<ظ`ʃ+6<ظ`ʃ+6<ظG)<IENDB`perfbook_html/node341.html0000644000175000017500000000500211672746163015640 0ustar paulmckpaulmck D.1.4 SRCU Summary


D.1.4 SRCU Summary

SRCU provides an RCU-like set of primitives that permit general sleeping in the SRCU read-side critical sections. However, it is important to note that SRCU has been used only in prototype code, though it has passed the RCU torture test. It will be very interesting to see what use, if any, SRCU sees in the future.



Paul E. McKenney 2011-12-16
perfbook_html/img313.png0000644000175000017500000000000011672746003021635 1perfbook_html/img261.pngustar paulmckpaulmckperfbook_html/img1.png0000644000175000017500000000557411672745766015166 0ustar paulmckpaulmckPNG  IHDRvD!Z)O0PLTEݙwwwUUU333fffDDD"""etRNS@f IDATx]h[EovaFGVV%,FQ W&c-i,K`!AᙱfntPvdYQb:; *tjleu%lcC1wd[{|?R\9ql2.ۑ%7oB,?6o^Vw]ނj.%7PewݨbX`t\?on=eX5lVuB.T)yfKls{i , .xLXI7ÞAIl'^fܜ2' on>ͽ{=ۢ5||D=wz|2p2y)l}aygygyg`_7?Jn ;S9*&v72㝔%\Is9xH'ƛN|ȕ'ii4=J9fWO0mq9g~㼩rnygy|Kz7ocg{ᩙJ&&-ys&5&MKuSf[ygygygygygygyg'cpɼ*ɡ7%u5bdۏo<ՏVnb3s2^6<%f*Ѿ~b/S<*&xYەZP?e$] =%3h?-.|3 SE}^ 6< jX ѣGߙ>57 B}T?9=ЧH<:}4;kGGGeF=zOș; #gCl?>JO:y}kzymtƓW=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG?V^<7mY^2yU>mz~`ù'/I^MM:m};;zx6.WJ7\_I﮻&9$HKzȘHN9x Ϝ^@x_ն>CTʬ齑~ gE{G&VP$xntsL[k3Kw7oE&?yֶ-нo wѣG=zE}dG"?t7mb"ԗGMAO{D'Rhd@=??#E~|sѣG=zѣG߲\s?]M9#9ڹ~&!FRLJ?[~[;z,<#G3=婱/H޿T9t^;dɇgtzOu^XͶ g:ٶLWQ=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zHsS.]Ak;=3ԭɌ}Z`ᴩ}D7BRϚ]˻>l?<ը}ښ]^v/Nd{q\kyۖfodrt>X)vSEm\D;%mgWn;(~Y[mHrptנ>.jÅwN rމ;Yiܞp;Oѵi;_=9icn sC+.}i/]NoT93^[{]^ /ԝ{4a-?7ݝ10fqVsx\z^C_~e*vϮfVzv!!.%;z%OtcO![h]u]u]u]u]u]vG;IJ%u~xv>c<'߈lkT#b''\=֩~9/0g}58Ȏ7ۋѿigE,x ,.։I捲;Q.iXfІ3JzI} :Ю:Ю:Ю:Ю:Ю:Ю:Ю:ЮZ{cgOo~Xo%$S=Ra= "/[ |͑ n s%9Wgl1J\)R;+ѕ}_r;8֮Mn_ 7״Zv.Խv棚j|b\ROO‘{s G"G{]8%;|ɡ1v _oǭ}B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}"*Ю£7>(k-IENDB`perfbook_html/node392.html0000644000175000017500000001361211672746163015654 0ustar paulmckpaulmck D.3.7.3 Interrupts from Dyntick-Idle Mode


D.3.7.3 Interrupts from Dyntick-Idle Mode

Figure: Interrupts from Dyntick-Idle Mode
\begin{figure}{ \scriptsize
\begin{verbatim}1 void rcu_irq_enter(void)
2 {
...
...cu_bh_data).nxtlist)
23 set_need_resched();
24 }\end{verbatim}
}\end{figure}

Figure [*] shows rcu_irq_enter() and rcu_irq_exit(), which handle interrupt entry and exit, respectively. As with NMIs, it is important to note that entering an interrupt handler exits dyntick-idle mode and vice versa, due to the fact that RCU read-side critical sections can appear in interrupt handlers.

Line 5 of rcu_irq_enter() once again acquires a reference to the current CPU's rcu_dynticks structure. Line 6 increments the ->dynticks_nesting field, and if the original value was already non-zero (in other words, RCU was already paying attention to this CPU), line 7 silently returns. Otherwise, line 8 increments the ->dynticks field, which then must have an odd-numbered value. Finally, line 9 executes a memory barrier so that this increment is seen by all CPUs as happening before any RCU read-side critical sections that might be in the interrupt handler.

Line 16 of rcu_irq_exit() does the by-now traditional acquisition of a reference to the currently running CPU's rcu_dynticks structure. Line 17 decrements the ->dynticks_nesting field, and, if the result is non-zero (in other words, RCU must still pay attention to this CPU despite exiting this interrupt handler), then line 18 silently returns. Otherwise, line 19 executes a memory barrier so that any RCU read-side critical sections that might have been in the interrupt handler are seen by all CPUs as having happened before the increment on line 20 of the ->dynticks field (which must now have an even-numbered value). Lines 21 and 22 check to see if the interrupt handler posted any ``rcu'' or ``rcu_bh'' callbacks, and, if so, line 23 forces this CPU to reschedule, which has the side-effect of forcing it out of dynticks-idle mode, as is required to allow RCU to handle the grace period required by these callbacks.

Paul E. McKenney 2011-12-16
perfbook_html/node227.html0000644000175000017500000003175411672746162015657 0ustar paulmckpaulmck 14.2.10.7 Examples of Memory Barrier Pairings


14.2.10.7 Examples of Memory Barrier Pairings

Firstly, write barriers act as a partial orderings on store operations. Consider the following sequence of events:



STORE A = 1
STORE B = 2
STORE C = 3
<write barrier>
STORE D = 4
STORE E = 5


This sequence of events is committed to the memory coherence system in an order that the rest of the system might perceive as the unordered set of {A=1,B=2,C=3} all occurring before the unordered set of {D=4,E=5}, as shown in Figure [*].

Figure: Write Barrier Ordering Semantics
\includegraphics{advsync/WriteBarrierOrdering}

Secondly, data dependency barriers act as a partial orderings on data-dependent loads. Consider the following sequence of events with initial values {B = 7, X = 9, Y = 8, C = &Y}:



CPU 1 CPU 2
a = 1;
b = 2;
<write barrier>
c = &b; LOAD X
d = 4; LOAD C (gets &B)
LOAD *C (reads B)


Without intervention, CPU 2 may perceive the events on CPU 1 in some effectively random order, despite the write barrier issued by CPU 1:

Figure: Data Dependency Barrier Omitted
\includegraphics{advsync/DataDependencyNeeded}

In the above example, CPU 2 perceives that B is 7, despite the load of *C (which would be B) coming after the LOAD of C.

If, however, a data dependency barrier were to be placed between the load of C and the load of *C (i.e.: B) on CPU 2, again with initial values of {B = 7, X = 9, Y = 8, C = &Y}:



CPU 1 CPU 2
a = 1;
b = 2;
<write barrier>
c = &b; LOAD X
d = 4; LOAD C (gets &B)
<data dependency barrier>
LOAD *C (reads B)


then ordering will be as intuitively expected, as shown in Figure [*].

Figure: Data Dependency Barrier Supplied
\includegraphics{advsync/DataDependencySupplied}

And thirdly, a read barrier acts as a partial order on loads. Consider the following sequence of events, with initial values {A = 0, B = 9}:



CPU 1 CPU 2
a = 1;
<write barrier>
b = 2;
LOAD B
LOAD A


Without intervention, CPU 2 may then choose to perceive the events on CPU 1 in some effectively random order, despite the write barrier issued by CPU 1:

Figure: Read Barrier Needed
\includegraphics{advsync/ReadBarrierNeeded}

If, however, a read barrier were to be placed between the load of B and the load of A on CPU 2, again with initial values of {A = 0, B = 9}:



CPU 1 CPU 2
a = 1;
<write barrier>
b = 2;
LOAD B
<read barrier>
LOAD A


then the partial ordering imposed by CPU 1's write barrier will be perceived correctly by CPU 2, as shown in Figure [*].

Figure: Read Barrier Supplied
\includegraphics{advsync/ReadBarrierSupplied}

To illustrate this more completely, consider what could happen if the code contained a load of A either side of the read barrier, once again with the same initial values of {A = 0, B = 9}:



CPU 1 CPU 2
a = 1;
<write barrier>
b = 2;
LOAD B
LOAD A (1st)
<read barrier>
LOAD A (2nd)


Even though the two loads of A both occur after the load of B, they may both come up with different values, as shown in Figure [*].

Figure: Read Barrier Supplied, Double Load
\includegraphics{advsync/ReadBarrierSupplied1}

Of course, it may well be that CPU 1's update to A becomes perceptible to CPU 2 before the read barrier completes, as shown in Figure [*].

Figure: Read Barrier Supplied, Take Two
\includegraphics{advsync/ReadBarrierSupplied2}

The guarantee is that the second load will always come up with A == 1 if the load of B came up with B == 2. No such guarantee exists for the first load of A; that may come up with either A == 0 or A == 1.

Paul E. McKenney 2011-12-16
perfbook_html/node145.html0000644000175000017500000001726411672746162015656 0ustar paulmckpaulmck 10.3.2.5 RCU is a Way of Providing Existence Guarantees


10.3.2.5 RCU is a Way of Providing Existence Guarantees

Gamsa et al. [GKAS99] discuss existence guarantees and describe how a mechanism resembling RCU can be used to provide these existence guarantees (see section 5 on page 7 of the PDF), and Section [*] discusses how to guarantee existence via locking, along with the ensuing disadvantages of doing so. The effect is that if any RCU-protected data element is accessed within an RCU read-side critical section, that data element is guaranteed to remain in existence for the duration of that RCU read-side critical section.

Figure: Existence Guarantees Enable Per-Element Locking
\begin{figure}{ \scriptsize
\begin{verbatim}1 int delete(int key)
2 {
3 str...
...>lock);
23 rcu_read_unlock();
24 return 0;
25 }\end{verbatim}
}\end{figure}

Figure [*] demonstrates how RCU-based existence guarantees can enable per-element locking via a function that deletes an element from a hash table. Line 6 computes a hash function, and line 7 enters an RCU read-side critical section. If line 9 finds that the corresponding bucket of the hash table is empty or that the element present is not the one we wish to delete, then line 10 exits the RCU read-side critical section and line 11 indicates failure.

Quick Quiz 10.17: What if the element we need to delete is not the first element of the list on line 9 of Figure [*]? End Quick Quiz

Otherwise, line 13 acquires the update-side spinlock, and line 14 then checks that the element is still the one that we want. If so, line 15 leaves the RCU read-side critical section, line 16 removes it from the table, line 17 releases the lock, line 18 waits for all pre-existing RCU read-side critical sections to complete, line 19 frees the newly removed element, and line 20 indicates success. If the element is no longer the one we want, line 22 releases the lock, line 23 leaves the RCU read-side critical section, and line 24 indicates failure to delete the specified key.

Quick Quiz 10.18: Why is it OK to exit the RCU read-side critical section on line 15 of Figure [*] before releasing the lock on line 17? End Quick Quiz

Quick Quiz 10.19: Why not exit the RCU read-side critical section on line 23 of Figure [*] before releasing the lock on line 22? End Quick Quiz

Alert readers will recognize this as only a slight variation on the original "RCU is a way of waiting for things to finish" theme, which is addressed in Section [*]. They might also note the deadlock-immunity advantages over the lock-based existence guarantees discussed in Section [*].

Paul E. McKenney 2011-12-16
perfbook_html/img163.png0000644000175000017500000000364111672746127015320 0ustar paulmckpaulmckPNG  IHDRW1J0PLTEgggMMM''' tttZZZ@@@444lܬ]tRNS@fIDATxOhU;}M'! V41zPzlADkRW{IAQ)QvHQJI{O5=Yd(JAZi6^Ͷ͛Iߗm:2l`M"{+[;l8@cQToKq@1Aty''lhKQ}0m\4a$:a0jnP1 3 oD& vZG3_U몋\{ۙ2jP{۠]<&j퉀Zm=kWKv@"\< `9r{$\6Lϗj=h[7SK~4ڀ9Ys߀Lo P{kl%?4Z]߲{f]!j anJ)>5^k7!}03Zڱb`P&aKӚv\ȶhfrmk`9ջn*U'0}[p[wRsQmY`lYp,[H#۲@e+ζY&qASw40"{0>G-x٠؂tLRXR,1(ps{6)%B:MRema-qfd2|9M3zCq2lm[S{XI)ʴD dK "5rMoFt;7m [} BVh[}n\ZBD:񚒒RwURLg =Mو4ڧ2h zOS!];7 .8@ 6Y[RTօ]sܟgBju֩'-o2Iۖl-@ m 8bؾ}Y lvKB# tV*Gݖ QRRf]rsn4Bt:F=@LIK11϶@C\{bl0 edAhPF&edAhPF&dAvz-Lt" akL n ,ma"G*F M0/ٖDH͞O h!1J ? ,},0:'FjfRD?0LL4(# D22ѠL4(# D22ѠL4(# D22`KBz iđu͢w$G":S(# D22ѠL4DO/_ΑNd+;>ffq$2ҩqY !3C#=wʧ Ó ʬ--P߿ڢnYgaSllBgC$ƛ)edAhPF&edAhPF&)CqAhYQkk͚Nހ9L"j:dN^ޝ15v~=]x9PY0W! t(ⷼNJ!z~Ҭ7wE4hVh_ G"BOTvY*c-YQR͊jVT%լ(u]4qCL4!t&: r9DBgA3 ЙhCmZ`3L@md I 2Su 7LxM?2 E.3 Promela Example: Atomic Increment


E.3 Promela Example: Atomic Increment

Figure: Promela Code for Atomic Increment
\begin{figure}{ \scriptsize
\begin{verbatim}1 proctype incrementer(byte me)
...
...ounter = temp + 1;
8 }
9 progress[me] = 1;
10 }\end{verbatim}
}\end{figure}

Figure: Atomic Increment spin Output
\begin{figure}{ \scriptsize
\begin{verbatim}(Spin Version 4.2.5 -- 2 April 200...
...es)
unreached in proctype :init:
(0 of 24 states)\end{verbatim}
}\end{figure}

It is easy to fix this example by placing the body of the incrementer processes in an atomic blocks as shown in Figure [*]. One could also have simply replaced the pair of statements with counter = counter + 1, because Promela statements are atomic. Either way, running this modified model gives us an error-free traversal of the state space, as shown in Figure [*].



Subsections

Paul E. McKenney 2011-12-16
perfbook_html/img170.png0000644000175000017500000000031111672746135015304 0ustar paulmckpaulmckPNG  IHDR L1!PLTEMJK# b``mkkXUV.*+d#tRNS@fVIDATcp`pgpBp@B...SفUfAcf@C@\iN('Cp JCih0p9F5IENDB`perfbook_html/images.aux0000644000175000017500000000067711672745743015601 0ustar paulmckpaulmck\relax \ifx\hyper@anchor\@undefined \global \let \oldcontentsline\contentsline \gdef \contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} \global \let \oldnewlabel\newlabel \gdef \newlabel#1#2{\newlabelxx{#1}#2} \gdef \newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} \AtEndDocument{\let \contentsline\oldcontentsline \let \newlabel\oldnewlabel} \else \global \let \hyper@last\relax \fi \providecommand*\HyPL@Entry[1]{} \HyPL@Entry{0<
>} perfbook_html/node136.html0000644000175000017500000001213311672746162015644 0ustar paulmckpaulmck 10.3.2.1.2 Deadlock Immunity

10.3.2.1.2 Deadlock Immunity

Although RCU offers significant performance advantages for read-mostly workloads, one of the primary reasons for creating RCU in the first place was in fact its immunity to read-side deadlocks. This immunity stems from the fact that RCU read-side primitives do not block, spin, or even do backwards branches, so that their execution time is deterministic. It is therefore impossible for them to participate in a deadlock cycle.

Quick Quiz 10.14: Is there an exception to this deadlock immunity, and if so, what sequence of events could lead to deadlock? End Quick Quiz

An interesting consequence of RCU's read-side deadlock immunity is that it is possible to unconditionally upgrade an RCU reader to an RCU updater. Attempting to do such an upgrade with reader-writer locking results in deadlock. A sample code fragment that does an RCU read-to-update upgrade follows:



  1 rcu_read_lock();
  2 list_for_each_entry_rcu(p, &head, list_field) {
  3   do_something_with(p);
  4   if (need_update(p)) {
  5     spin_lock(my_lock);
  6     do_update(p);
  7     spin_unlock(&my_lock);
  8   }
  9 }
 10 rcu_read_unlock();


Note that do_update() is executed under the protection of the lock and under RCU read-side protection.

Another interesting consequence of RCU's deadlock immunity is its immunity to a large class of priority inversion problems. For example, low-priority RCU readers cannot prevent a high-priority RCU updater from acquiring the update-side lock. Similarly, a low-priority RCU updater cannot prevent high-priority RCU readers from entering an RCU read-side critical section.

Paul E. McKenney 2011-12-16
perfbook_html/img273.png0000644000175000017500000000000011672746115021645 1perfbook_html/img125.pngustar paulmckpaulmckperfbook_html/img31.png0000644000175000017500000000102311672746142015217 0ustar paulmckpaulmckPNG  IHDR*)I0PLTEMJK# b``mkkXUV856C@@wuv.*+ Ė`tRNS@fIDATX헽N`B'%z܁ Y''NhFٽ'n0q늉rMڱAUNԜg#{8_KhurߪQnMZHeM-JY#SRKZX+/JR'W哚vwWq9rqX~Dt`Y3r&5\6+\3\'q5ovJQ!+G|~`p]XzA֮T?jJ%+)6bX!G ,%UVkHJJ*B]HJ8qGRͩRѩR}:^1;BRu}LǎT1Vo:v"9Q+$U:f=cGLOL\xL#!QIENDB`perfbook_html/img73.png0000644000175000017500000001376411672746134015245 0ustar paulmckpaulmckPNG  IHDR&- EPLTETRRMJKPMM# b``mkkXUVJGH856KHHC@@wuv.*+|zzÍOtRNS@f]IDATx]R+cS̠$I{ݕFlF$;s!Gtqc8qGa#[9ۘ}Dxԑ70YoLjoaVj@hPf_Ỏn6{h63t-~ 6k]Fzox͡}=P_. ޺CN0C] gulN.+8I/V=x?޹cŹ7X,|*#|hEYIp/'5|ef![i}(]ܩeWB"(w[?!6)PPkl#@-X'ѐkAX05 4*+$ݸ?o^> u "rM^vPc.4 AF[˝ 4eR@i}ϘI;i;j]a_v*]g&U}zAC4>|Wvp˸ZnoFldEO_hN%s o|oKqTz*wFGN W/ }84Gb+;{HKl _`? <>xW4s{qr-|ckBsz W},&8&v=޳ScvF8I;[8Ɉȅ߼kz\y16 xw+ sMӠrZ#̆;%D%k˜jϻ5 Q/sJ̿_CtT1`dzw;Ż3Wy-#cT)QM+Ύ3m =do ޲;?h7Fh 4g[uA)L=`JV5 @~5E| s"mt=G_@Lp>)x ;r9_ eT&zr̚(p} 1h)Q] H*_Rn!F2QNϹˍfmק .)űDiɵǝ0-M@rˡ. az2Wh ٬h؀ <'Ξ(Cp1RK H︦6rSugh `@M"%MM8?9^/2l`.l_Q;Ig۬4)>LuuSe,:ns*Sh , [MO,eriz E1;OI,Xne&6=2sFWVr԰utLb}0{D|Yʚ[+Y2r5{ڍAp (8aݰ?dIdp#Wg8L_:` a5Lc~v=tM;D" a˂ Ú~Z7puQ&ZĦij=}tc1Xɴ:iU۰Pw&˔h ?qdg_[ K4dY,@&82lK7VV*j8H.p ]/5%R m)kݧtXyKLb8rO-^cxP[C9ΧKGኸF L(IDfkgkGq (ǪЛp5DGcUI,?k)dhY `DF[j6hksE[J } e.g54!xvQazRIۜجÏƜU(A?be- b@a[9ȓ:Dp0-9Ҙ]9{YMI1zA~caUAW%sqDx|Y 3jeQhtTOXbIi*0켓vC>0o1_VFh{V0d]̕${p$]êP2?;$@wȐw3 Hcb]\ ZC3J4x01E$E%q%L~ }3s=`[Y}+X!ƛIt0IKh .OrgL6GwWl(Ste X X!:W>\C㘉xƦst?C`|8%AٲX#u6@҆ތBgDeoL'̳ը5TÚtEn^uk^Ynx!xO6$'G^d+ɴBy|%7Kj0 WL2ĭ}_)uH8n䯸o ;BCT(docwĴ#kd7L[v }V/'ˮs<ɋZw)ƵeR\K)9mձL1/,! l][΃q,>WϘMdS}sD+HO5, ʀi.T'|.@t\ +GE \ VÝ`YQH@ i]_Vd,/tedUGAQ&]= vͼvt`^8lMOc)Ao &  #g\M2:y ?-q/l da*23;WNKtdUh_kvFAiAၴ)L&8j:si [4UU,~ttne@ִ vel*(8L-aMHT1AuЮ/q2k qIx]Z k\+~ ǜ;`j1!36˵C5HjYZfpވ _K2tR(orhkV*׍6hM\y*&lR茔ǫgdz\AyǜmsA Vz-wk9*%s4\x+S>\#6i]tp8jJܮ?Nmc? WemfKo3E_0j[6ijԣcS_LT7t'N} %N-x楏= _zqyW[Y)((a|Jh֎6_Cv+@wVY]F؄nqwA<𗨪&2D&m\M{ "8偿5-ѭNTUi[܃ỽfY}QT򼝰$[M(RDNa3i#bEӷ 5 "%o 7x'Oo|]%2w ' uLsX~*gnxVq|NS?Ycp }'ֵm.zfcZ.X}x.xޢcڇc]^?fLmX6Cd>ʱj$o3ToAbkbӆJؔ&d(9H/Yt(i`YPPk+0M7Eo@ZI7xg&‘w'B̃haFޘ)l S.ҖSvB℉GrߕCI1D<5LU4^Tn^I,-y\L=KH[(. #:8 iߕCIqIHnYi27^RK/&*K(YQqxpaZGDWyiVksWڏ-D_#$dn6DSi@5u]JMmApL#mBhXwM ջnv-i{1#aB#U/w[W]mï8NMvqkJ-R<0A*wI2"WcUn߸9t}.i{1#!m&U/w1Wxp_-є1܌)5uPMzt9&^'X>Zj^Ynp7# }77-U*U!.x.mdΰiE7컒|3"ZM*VPx{aSiѲiz"Cv]DVe:GzȘ'jJveZ9KJaf'l''ʘzs`O`j%n,oυ{SKY=~2Dq 5 Ƌe$Y7eaèvܢY/J((,NUVZs$Eˑ7JRXݙ)oyvo)h..U=6.|%Q**%_RNR"2\-ML ZӨթ+ 06၂Tv{Z-Gs@ف;nMi ޵z'0rd0 = 6R7c7H^ӨyH?1ckȺI8Mٻ1ҵ$/iԼr|IW! mDAo $yE]IoPM,Oui-|u6tM[:94vkډy #$j =YXRZv8bs):fjߜ7$jx\M1q·} %a߂> @IkK 0Qm~K ㍤ϵ\ }McN`h2f8ž }7MX5!Z@5 }݁%.Q.(!Bo*!M7pwJJxXbWIENDB`perfbook_html/img321.png0000644000175000017500000001167611672746012015314 0ustar paulmckpaulmckPNG  IHDR|k=6PLTEMJK# b``mkkiggXUV856C@@wuv.*+|zzFTFtRNS@f6IDATx]*eFug$n}V)NX suI#rvI|ohM5RjmV)p1}RF&Z!˸+Ϛ$fEX%r[>u!~MPOe~[.^Š"N@( -qƈ a{sEQf;2'd@y\#z8ok}"2inÉ}`rQBEG{Ϧ ƨ.j$E 2A<]\G(8U'ZrPĒs3ļ>DSM\_Y B~URc$Vz] 'EHM nſPaM_nR_]jD~fVZ "ҙ~GI4kTs(tJAm8LxS&sXw˫ ,Q Trvc/9M4!Cav̡[4aQ+icȖqӖ.{0'I!rj1%[R O:A`y:k|wekpЯc"ƗhjM.kvch5&v\ܵ!ّ34so6Kcyֲ}L럴U_ѯ;dS"=AK-R 41Ptgh: :KM^F*3|#L5lwYJ*$^dv87m3p/!@Vda:Fq-<{_LR,Ջ ;U$9(`LUXrGRA2 bbw^\%nη۪:a\TL*v4k%2c% GҸz&24<2GJ&^aEU籨*5mj~݃tĿa/|SbpvstJAWm wnw ps' b'c2K]ob.QsE%5ԇfoQk< -xɧf]\M`XW .-bU@D,VE4<`A8N3L@&qNUE ,x5|-n .vi@ ar3C  D2^uKa8'!ngZ$ވӌ*Fk`㴈(\EZ eN$7,fz%MA9 We s3{̅ob"Gsʉlꖕ &Y8 c}.{gPS^^olɆZ!Àqv0hӜ_pL#S k}TT,4˜2e·PD7 7̎40!+P 0)zgZ١l).OKg|1¦)'B=@}Hd1z, J%ʈTTəp794zq%UOOl w-ɑrNeOJ` i@y2z5||pnr%'SQ2"ʶ^>G;zQ+XW $~pmѲl%W̡s@ީ6 lOO_rv|S S݇'1s$m 3>\91َN_2iG9aH~P*i\%h=fm #Ge+J b,CoULu X'grDަzzk|20zZ/B6zzaJ!|2BwRQ_ȴ͢rRKNp3a'T Llr ,%jt!IL#wH S:j^EƿCYtBRNEzwݪfBGBFlܒ.u4i8!9KoLА%ax),r,sͭGn!+0𢙼&cfq;ӴwGx)j0eAtaDy*, 4z¦3$uQ, AhxW<_b6)⺚¸X 24D;7{ɋ(s+7Tu0O%m}r }>nf<$f@!^0'w'?x=L]'nmV>=amB>m$N$'#ǐ=23~u'9=GbOdׇl ResXDh0g8V5S K; Th20ٓ^Tk>,\::xG/H% 7f!Tɑ%ōM= lE`iVь%ōkAoͱSXC种* Ta4O(޺2KI8u)6 VsuSkE$;^d &.4CyQ#eZmcr8EU3MvԆTI*vG1Ͼ=M,fQV/ǰ0Di4KCj6;|}yqGaF;x;k6?|>*^J9t,_*:mU`v/qRҍA\E?liogp.ϼ-'Eҹf{\=G8p:|ȑGcʴ"tΞ&q`43 N *dbDLG&Ckx| GѱH'SM3⺙ڃY vt̞_]ucC'߀Ë _;;tY[" %6Bpr8:"Q[y0m'ct^iD+W>?řgw0m8Z 6"5:Nʳű堉X.l6x8X-;q_M`-s?|1D_sG·! ^P*Ս~Ւ&3-$lmb_*@r֬Khw|쿏mS@IENDB`perfbook_html/img208.png0000644000175000017500000000024311672746155015314 0ustar paulmckpaulmckPNG  IHDR}nPLTEMJKb``mkkC@@.*+8iGtRNS@f9IDAT8cp`>0 hr4)iekFzYJ/e|4 !%\IENDB`