1lcnt(3) Erlang Module Definition lcnt(3)
2
3
4
6 lcnt - A runtime system Lock Profiling tool.
7
9 The lcnt module is used to profile the internal ethread locks in the
10 Erlang Runtime System. With lcnt enabled, internal counters in the run‐
11 time system are updated each time a lock is taken. The counters stores
12 information about the number of acquisition tries and the number of
13 collisions that has occurred during the acquisition tries. The counters
14 also record the waiting time a lock has caused for a blocked thread
15 when a collision has occurred.
16
17 The data produced by the lock counters will give an estimate on how
18 well the runtime system will behave from a parallelizable view point
19 for the scenarios tested. This tool was mainly developed to help Erlang
20 runtime developers iron out potential and generic bottlenecks.
21
22 Locks in the emulator are named after what type of resource they pro‐
23 tect and where in the emulator they are initialized, those are lock
24 'classes'. Most of those locks are also instantiated several times, and
25 given unique identifiers, to increase locking granularity. Typically an
26 instantiated lock protects a disjunct set of the resource, for example
27 ets tables, processes or ports. In other cases it protects a specific
28 range of a resource, for example pix_lock which protects index to
29 process mappings, and is given a unique number within the class. A
30 unique lock in lcnt is referenced by a name (class) and an identifier:
31 {Name, Id}.
32
33 Some locks in the system are static and protects global resources, for
34 example bif_timers and the run_queue locks. Other locks are dynamic and
35 not necessarily long lived, for example process locks and ets-table
36 locks. The statistics data from short lived locks can be stored sepa‐
37 rately when the locks are deleted. This behavior is by default turned
38 off to save memory but can be turned on via lcnt:rt_opt({copy_save,
39 true}). The lcnt:apply/1,2,3 functions enables this behavior during
40 profiling.
41
43 start() -> {ok, Pid} | {error, {already_started, Pid}}
44
45 Types:
46
47 Pid = pid()
48
49 Starts the lock profiler server. The server only act as a medium
50 for the user and performs filtering and printing of data col‐
51 lected by lcnt:collect/1.
52
53 stop() -> ok
54
55 Stops the lock profiler server.
56
57 collect() -> ok
58
59 Same as collect(node()).
60
61 collect(Node) -> ok
62
63 Types:
64
65 Node = node()
66
67 Collects lock statistics from the runtime system. The function
68 starts a server if it is not already started. It then populates
69 the server with lock statistics. If the server held any lock
70 statistics data before the collect then that data is lost.
71
72 clear() -> ok
73
74 Same as clear(node()).
75
76 clear(Node) -> ok
77
78 Types:
79
80 Node = node()
81
82 Clears the internal lock statistics from the runtime system.
83 This does not clear the data on the server only on runtime sys‐
84 tem. All counters for static locks are zeroed, all dynamic locks
85 currently alive are zeroed and all saved locks now destroyed are
86 removed. It also resets the duration timer.
87
88 conflicts() -> ok
89
90 Same as conflicts([]).
91
92 conflicts(Options) -> ok
93
94 Types:
95
96 Options = [option()]
97 option() =
98 {sort, Sort :: sort()} |
99 {reverse, boolean()} |
100 {locations, boolean()} |
101 {thresholds, Thresholds :: [threshold()]} |
102 {print,
103 PrintOptions :: [print() | {print(), integer() >= 0}]} |
104 {max_locks, MaxLocks :: integer() >= 0 | none} |
105 {combine, boolean()}
106 print() =
107 colls | duration | entry | id | name | ratio | time | tries |
108 type
109 sort() =
110 colls | entry | id | name | ratio | time | tries | type
111 threshold() =
112 {colls, integer() >= 0} |
113 {time, integer() >= 0} |
114 {tries, integer() >= 0}
115
116 Prints a list of internal locks and its statistics.
117
118 For option description, see lcnt:inspect/2.
119
120 locations() -> ok
121
122 Same as locations([]).
123
124 locations(Options) -> ok
125
126 Types:
127
128 Options = [option()]
129 option() =
130 {sort, Sort :: sort()} |
131 {reverse, boolean()} |
132 {locations, boolean()} |
133 {thresholds, Thresholds :: [threshold()]} |
134 {print,
135 PrintOptions :: [print() | {print(), integer() >= 0}]} |
136 {max_locks, MaxLocks :: integer() >= 0 | none} |
137 {combine, boolean()}
138 print() =
139 colls | duration | entry | id | name | ratio | time | tries |
140 type
141 sort() =
142 colls | entry | id | name | ratio | time | tries | type
143 threshold() =
144 {colls, integer() >= 0} |
145 {time, integer() >= 0} |
146 {tries, integer() >= 0}
147
148 Prints a list of internal lock counters by source code loca‐
149 tions.
150
151 For option description, see lcnt:inspect/2.
152
153 inspect(Lock) -> ok
154
155 Types:
156
157 Lock = Name | {Name, Id | [Id]}
158 Name = atom() | pid() | port()
159 Id = atom() | integer() | pid() | port()
160
161 Same as inspect(Lock, []).
162
163 inspect(Lock, Options) -> ok
164
165 Types:
166
167 Lock = Name | {Name, Id | [Id]}
168 Name = atom() | pid() | port()
169 Id = atom() | integer() | pid() | port()
170 Options = [option()]
171 option() =
172 {sort, Sort :: sort()} |
173 {reverse, boolean()} |
174 {locations, boolean()} |
175 {thresholds, Thresholds :: [threshold()]} |
176 {print,
177 PrintOptions :: [print() | {print(), integer() >= 0}]} |
178 {max_locks, MaxLocks :: integer() >= 0 | none} |
179 {combine, boolean()}
180 print() =
181 colls | duration | entry | id | name | ratio | time | tries |
182 type
183 sort() =
184 colls | entry | id | name | ratio | time | tries | type
185 threshold() =
186 {colls, integer() >= 0} |
187 {time, integer() >= 0} |
188 {tries, integer() >= 0}
189
190 Prints a list of internal lock counters for a specific lock.
191
192 Lock Name and Id for ports and processes are interchangeable
193 with the use of lcnt:swap_pid_keys/0 and is the reason why pid()
194 and port() options can be used in both Name and Id space. Both
195 pids and ports are special identifiers with stripped creation
196 and can be recreated with lcnt:pid/2,3 and lcnt:port/1,2.
197
198 Option description:
199
200 {combine, boolean()}:
201 Combine the statistics from different instances of a lock
202 class.
203 Default: true
204
205 {locations, boolean()}:
206 Print the statistics by source file and line numbers.
207 Default: false
208
209 {max_locks, MaxLocks}:
210 Maximum number of locks printed or no limit with none.
211 Default: 20
212
213 {print, PrintOptions}:
214 Printing options:
215
216 name:
217 Named lock or named set of locks (classes). The same name
218 used for initializing the lock in the VM.
219
220 id:
221 Internal id for set of locks, not always unique. This
222 could be table name for ets tables (db_tab), port id for
223 ports, integer identifiers for allocators, etc.
224
225 type:
226 Type of lock: rw_mutex, mutex, spinlock, rw_spinlock or
227 proclock.
228
229 entry:
230 In combination with {locations, true} this option prints
231 the lock operations source file and line number entry-
232 points along with statistics for each entry.
233
234 tries:
235 Number of acquisitions of this lock.
236
237 colls:
238 Number of collisions when a thread tried to acquire this
239 lock. This is when a trylock is EBUSY, a write try on read
240 held rw_lock, a try read on write held rw_lock, a thread
241 tries to lock an already locked lock. (Internal states su‐
242 pervises this).
243
244 ratio:
245 The ratio between the number of collisions and the number
246 of tries (acquisitions) in percentage.
247
248 time:
249 Accumulated waiting time for this lock. This could be
250 greater than actual wall clock time, it is accumulated for
251 all threads. Trylock conflicts does not accumulate time.
252
253 duration:
254 Percentage of accumulated waiting time of wall clock time.
255 This percentage can be higher than 100% since accumulated
256 time is from all threads.
257 Default: [name,id,tries,colls,ratio,time,duration]
258
259 {reverse, boolean()}:
260 Reverses the order of sorting.
261 Default: false
262
263 {sort, Sort}:
264 Column sorting orders.
265 Default: time
266
267 {thresholds, Thresholds}:
268 Filtering thresholds. Anything values above the threshold
269 value are passed through.
270 Default: [{tries, 0}, {colls, 0}, {time, 0}]
271
272 information() -> ok
273
274 Prints lcnt server state and generic information about collected
275 lock statistics.
276
277 swap_pid_keys() -> ok
278
279 Swaps places on Name and Id space for ports and processes.
280
281 load(Filename) -> ok
282
283 Types:
284
285 Filename = file:filename()
286
287 Restores previously saved data to the server.
288
289 save(Filename) -> ok
290
291 Types:
292
293 Filename = file:filename()
294
295 Saves the collected data to file.
296
298 The following functions are used for convenience.
299
301 apply(Fun) -> term()
302
303 Types:
304
305 Fun = function()
306
307 Same as apply(Fun, []).
308
309 apply(Fun, Args) -> term()
310
311 Types:
312
313 Fun = function()
314 Args = [term()]
315
316 Clears the lock counters and then setups the instrumentation to
317 save all destroyed locks. After setup the function is called,
318 passing the elements in Args as arguments. When the function re‐
319 turns the statistics are immediately collected to the server.
320 After the collection the instrumentation is returned to its pre‐
321 vious behavior. The result of the applied function is returned.
322
323 Warning:
324 This function should only be used for micro-benchmarks; it sets
325 copy_save to true for the duration of the call, which can
326 quickly lead to running out of memory.
327
328
329 apply(Module, Function, Args) -> term()
330
331 Types:
332
333 Module = module()
334 Function = atom()
335 Args = [term()]
336
337 Same as apply(fun() -> erlang:apply(Module, Function, Args)
338 end).
339
340 pid(Id, Serial) -> pid()
341
342 Types:
343
344 Id = Serial = integer()
345
346 Same as pid(node(), Id, Serial).
347
348 pid(Node, Id, Serial) -> pid()
349
350 Types:
351
352 Node = node()
353 Id = Serial = integer()
354
355 Creates a process id with creation 0.
356
357 port(Id) -> port()
358
359 Types:
360
361 Id = integer()
362
363 Same as port(node(), Id).
364
365 port(Node, Id) -> port()
366
367 Types:
368
369 Node = node()
370 Id = integer()
371
372 Creates a port id with creation 0.
373
375 The following functions control the behavior of the internal counters.
376
378 rt_collect() -> [lock_counter_data()]
379
380 Types:
381
382 lock_counter_data() = term()
383
384 Same as rt_collect(node()).
385
386 rt_collect(Node) -> [lock_counter_data()]
387
388 Types:
389
390 Node = node()
391 lock_counter_data() = term()
392
393 Returns a list of raw lock counter data.
394
395 rt_clear() -> ok
396
397 Same as rt_clear(node()).
398
399 rt_clear(Node) -> ok
400
401 Types:
402
403 Node = node()
404
405 Clear the internal counters. Same as lcnt:clear(Node).
406
407 rt_mask() -> [category_atom()]
408
409 Types:
410
411 category_atom() = atom()
412
413 Same as rt_mask(node()).
414
415 rt_mask(Node) -> [category_atom()]
416
417 Types:
418
419 Node = node()
420 category_atom() = atom()
421
422 Refer to rt_mask/2. for a list of valid categories. All cate‐
423 gories are enabled by default.
424
425 rt_mask(Categories) -> ok | {error, copy_save_enabled}
426
427 Types:
428
429 Categories = [category_atom()]
430 category_atom() = atom()
431
432 Same as rt_mask(node(), Categories).
433
434 rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}
435
436 Types:
437
438 Node = node()
439 Categories = [category_atom()]
440 category_atom() = atom()
441
442 Sets the lock category mask to the given categories.
443
444 This will fail if the copy_save option is enabled; see
445 lcnt:rt_opt/2.
446
447 Valid categories are:
448
449 * allocator
450
451 * db (ETS tables)
452
453 * debug
454
455 * distribution
456
457 * generic
458
459 * io
460
461 * process
462
463 * scheduler
464
465 This list is subject to change at any time, as is the category
466 any given lock may belong to.
467
468 rt_opt(Option) -> boolean()
469
470 Types:
471
472 Option = {Type, Value :: boolean()}
473 Type = copy_save | process_locks
474
475 Same as rt_opt(node(), {Type, Value}).
476
477 rt_opt(Node, Option) -> boolean()
478
479 Types:
480
481 Node = node()
482 Option = {Type, Value :: boolean()}
483 Type = copy_save | process_locks
484
485 Option description:
486
487 {copy_save, boolean()}:
488 Retains the statistics of destroyed locks.
489 Default: false
490
491 Warning:
492 This option will use a lot of memory when enabled, which must
493 be reclaimed with lcnt:rt_clear. Note that it makes no dis‐
494 tinction between locks that were destroyed and locks for which
495 counting was disabled, so enabling this option will disable
496 changes to the lock category mask.
497
498
499 {process_locks, boolean()}:
500 Profile process locks, equal to adding process to the lock
501 category mask; see lcnt:rt_mask/2
502 Default: true
503
505 LCNT User's Guide
506
507
508
509Ericsson AB tools 3.6 lcnt(3)