| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117 |
- .. SPDX-License-Identifier: GPL-2.0
- ======================
- Histogram Design Notes
- ======================
- :Author: Tom Zanussi <zanussi@kernel.org>
- This document attempts to provide a description of how the ftrace
- histograms work and how the individual pieces map to the data
- structures used to implement them in trace_events_hist.c and
- tracing_map.c.
- Note: All the ftrace histogram command examples assume the working
- directory is the ftrace /tracing directory. For example::
- # cd /sys/kernel/tracing
- Also, the histogram output displayed for those commands will be
- generally be truncated - only enough to make the point is displayed.
- 'hist_debug' trace event files
- ==============================
- If the kernel is compiled with CONFIG_HIST_TRIGGERS_DEBUG set, an
- event file named 'hist_debug' will appear in each event's
- subdirectory. This file can be read at any time and will display some
- of the hist trigger internals described in this document. Specific
- examples and output will be described in test cases below.
- Basic histograms
- ================
- First, basic histograms. Below is pretty much the simplest thing you
- can do with histograms - create one with a single key on a single
- event and cat the output::
- # echo 'hist:keys=pid' >> events/sched/sched_waking/trigger
- # cat events/sched/sched_waking/hist
- { pid: 18249 } hitcount: 1
- { pid: 13399 } hitcount: 1
- { pid: 17973 } hitcount: 1
- { pid: 12572 } hitcount: 1
- ...
- { pid: 10 } hitcount: 921
- { pid: 18255 } hitcount: 1444
- { pid: 25526 } hitcount: 2055
- { pid: 5257 } hitcount: 2055
- { pid: 27367 } hitcount: 2055
- { pid: 1728 } hitcount: 2161
- Totals:
- Hits: 21305
- Entries: 183
- Dropped: 0
- What this does is create a histogram on the sched_waking event using
- pid as a key and with a single value, hitcount, which even if not
- explicitly specified, exists for every histogram regardless.
- The hitcount value is a per-bucket value that's automatically
- incremented on every hit for the given key, which in this case is the
- pid.
- So in this histogram, there's a separate bucket for each pid, and each
- bucket contains a value for that bucket, counting the number of times
- sched_waking was called for that pid.
- Each histogram is represented by a hist_data struct.
- To keep track of each key and value field in the histogram, hist_data
- keeps an array of these fields named fields[]. The fields[] array is
- an array containing struct hist_field representations of each
- histogram val and key in the histogram (variables are also included
- here, but are discussed later). So for the above histogram we have one
- key and one value; in this case the one value is the hitcount value,
- which all histograms have, regardless of whether they define that
- value or not, which the above histogram does not.
- Each struct hist_field contains a pointer to the ftrace_event_field
- from the event's trace_event_file along with various bits related to
- that such as the size, offset, type, and a hist_field_fn_t function,
- which is used to grab the field's data from the ftrace event buffer
- (in most cases - some hist_fields such as hitcount don't directly map
- to an event field in the trace buffer - in these cases the function
- implementation gets its value from somewhere else). The flags field
- indicates which type of field it is - key, value, variable, variable
- reference, etc., with value being the default.
- The other important hist_data data structure in addition to the
- fields[] array is the tracing_map instance created for the histogram,
- which is held in the .map member. The tracing_map implements the
- lock-free hash table used to implement histograms (see
- kernel/trace/tracing_map.h for much more discussion about the
- low-level data structures implementing the tracing_map). For the
- purposes of this discussion, the tracing_map contains a number of
- buckets, each bucket corresponding to a particular tracing_map_elt
- object hashed by a given histogram key.
- Below is a diagram the first part of which describes the hist_data and
- associated key and value fields for the histogram described above. As
- you can see, there are two fields in the fields array, one val field
- for the hitcount and one key field for the pid key.
- Below that is a diagram of a run-time snapshot of what the tracing_map
- might look like for a given run. It attempts to show the
- relationships between the hist_data fields and the tracing_map
- elements for a couple hypothetical keys and values.::
- +------------------+
- | hist_data |
- +------------------+ +----------------+
- | .fields[] |---->| val = hitcount |----------------------------+
- +----------------+ +----------------+ |
- | .map | | .size | |
- +----------------+ +--------------+ |
- | .offset | |
- +--------------+ |
- | .fn() | |
- +--------------+ |
- . |
- . |
- . |
- +----------------+ <--- n_vals |
- | key = pid |----------------------------|--+
- +----------------+ | |
- | .size | | |
- +--------------+ | |
- | .offset | | |
- +--------------+ | |
- | .fn() | | |
- +----------------+ <--- n_fields | |
- | unused | | |
- +----------------+ | |
- | | | |
- +--------------+ | |
- | | | |
- +--------------+ | |
- | | | |
- +--------------+ | |
- n_keys = n_fields - n_vals | |
- The hist_data n_vals and n_fields delineate the extent of the fields[] | |
- array and separate keys from values for the rest of the code. | |
- Below is a run-time representation of the tracing_map part of the | |
- histogram, with pointers from various parts of the fields[] array | |
- to corresponding parts of the tracing_map. | |
- The tracing_map consists of an array of tracing_map_entrys and a set | |
- of preallocated tracing_map_elts (abbreviated below as map_entry and | |
- map_elt). The total number of map_entrys in the hist_data.map array = | |
- map->max_elts (actually map->map_size but only max_elts of those are | |
- used. This is a property required by the map_insert() algorithm). | |
- If a map_entry is unused, meaning no key has yet hashed into it, its | |
- .key value is 0 and its .val pointer is NULL. Once a map_entry has | |
- been claimed, the .key value contains the key's hash value and the | |
- .val member points to a map_elt containing the full key and an entry | |
- for each key or value in the map_elt.fields[] array. There is an | |
- entry in the map_elt.fields[] array corresponding to each hist_field | |
- in the histogram, and this is where the continually aggregated sums | |
- corresponding to each histogram value are kept. | |
- The diagram attempts to show the relationship between the | |
- hist_data.fields[] and the map_elt.fields[] with the links drawn | |
- between diagrams::
- +-----------+ | |
- | hist_data | | |
- +-----------+ | |
- | .fields | | |
- +---------+ +-----------+ | |
- | .map |---->| map_entry | | |
- +---------+ +-----------+ | |
- | .key |---> 0 | |
- +---------+ | |
- | .val |---> NULL | |
- +-----------+ | |
- | map_entry | | |
- +-----------+ | |
- | .key |---> pid = 999 | |
- +---------+ +-----------+ | |
- | .val |--->| map_elt | | |
- +---------+ +-----------+ | |
- . | .key |---> full key * | |
- . +---------+ +---------------+ | |
- . | .fields |--->| .sum (val) |<-+ |
- +-----------+ +---------+ | 2345 | | |
- | map_entry | +---------------+ | |
- +-----------+ | .offset (key) |<----+
- | .key |---> 0 | 0 | | |
- +---------+ +---------------+ | |
- | .val |---> NULL . | |
- +-----------+ . | |
- | map_entry | . | |
- +-----------+ +---------------+ | |
- | .key | | .sum (val) or | | |
- +---------+ +---------+ | .offset (key) | | |
- | .val |--->| map_elt | +---------------+ | |
- +-----------+ +---------+ | .sum (val) or | | |
- | map_entry | | .offset (key) | | |
- +-----------+ +---------------+ | |
- | .key |---> pid = 4444 | |
- +---------+ +-----------+ | |
- | .val | | map_elt | | |
- +---------+ +-----------+ | |
- | .key |---> full key * | |
- +---------+ +---------------+ | |
- | .fields |--->| .sum (val) |<-+ |
- +---------+ | 65523 | |
- +---------------+ |
- | .offset (key) |<----+
- | 0 |
- +---------------+
- .
- .
- .
- +---------------+
- | .sum (val) or |
- | .offset (key) |
- +---------------+
- | .sum (val) or |
- | .offset (key) |
- +---------------+
- Abbreviations used in the diagrams::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- fn = hist_field_fn_t
- map_entry = struct tracing_map_entry
- map_elt = struct tracing_map_elt
- map_elt.fields = struct tracing_map_field
- Whenever a new event occurs and it has a hist trigger associated with
- it, event_hist_trigger() is called. event_hist_trigger() first deals
- with the key: for each subkey in the key (in the above example, there
- is just one subkey corresponding to pid), the hist_field that
- represents that subkey is retrieved from hist_data.fields[] and the
- hist_field_fn_t fn() associated with that field, along with the
- field's size and offset, is used to grab that subkey's data from the
- current trace record.
- Once the complete key has been retrieved, it's used to look that key
- up in the tracing_map. If there's no tracing_map_elt associated with
- that key, an empty one is claimed and inserted in the map for the new
- key. In either case, the tracing_map_elt associated with that key is
- returned.
- Once a tracing_map_elt available, hist_trigger_elt_update() is called.
- As the name implies, this updates the element, which basically means
- updating the element's fields. There's a tracing_map_field associated
- with each key and value in the histogram, and each of these correspond
- to the key and value hist_fields created when the histogram was
- created. hist_trigger_elt_update() goes through each value hist_field
- and, as for the keys, uses the hist_field's fn() and size and offset
- to grab the field's value from the current trace record. Once it has
- that value, it simply adds that value to that field's
- continually-updated tracing_map_field.sum member. Some hist_field
- fn()s, such as for the hitcount, don't actually grab anything from the
- trace record (the hitcount fn() just increments the counter sum by 1),
- but the idea is the same.
- Once all the values have been updated, hist_trigger_elt_update() is
- done and returns. Note that there are also tracing_map_fields for
- each subkey in the key, but hist_trigger_elt_update() doesn't look at
- them or update anything - those exist only for sorting, which can
- happen later.
- Basic histogram test
- --------------------
- This is a good example to try. It produces 3 value fields and 2 key
- fields in the output::
- # echo 'hist:keys=common_pid,call_site.sym:values=bytes_req,bytes_alloc,hitcount' >> events/kmem/kmalloc/trigger
- To see the debug data, cat the kmem/kmalloc's 'hist_debug' file. It
- will show the trigger info of the histogram it corresponds to, along
- with the address of the hist_data associated with the histogram, which
- will become useful in later examples. It then displays the number of
- total hist_fields associated with the histogram along with a count of
- how many of those correspond to keys and how many correspond to values.
- It then goes on to display details for each field, including the
- field's flags and the position of each field in the hist_data's
- fields[] array, which is useful information for verifying that things
- internally appear correct or not, and which again will become even
- more useful in further examples::
- # cat events/kmem/kmalloc/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=common_pid,call_site.sym:vals=hitcount,bytes_req,bytes_alloc:sort=hitcount:size=2048 [active]
- #
- hist_data: 000000005e48c9a5
- n_vals: 3
- n_keys: 2
- n_fields: 5
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- VAL: normal u64 value
- ftrace_event_field name: bytes_req
- type: size_t
- size: 8
- is_signed: 0
- hist_data->fields[2]:
- flags:
- VAL: normal u64 value
- ftrace_event_field name: bytes_alloc
- type: size_t
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: common_pid
- type: int
- size: 8
- is_signed: 1
- hist_data->fields[4]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: call_site
- type: unsigned long
- size: 8
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=common_pid,call_site.sym:values=bytes_req,bytes_alloc,hitcount' >> events/kmem/kmalloc/trigger
- Variables
- =========
- Variables allow data from one hist trigger to be saved by one hist
- trigger and retrieved by another hist trigger. For example, a trigger
- on the sched_waking event can capture a timestamp for a particular
- pid, and later a sched_switch event that switches to that pid event
- can grab the timestamp and use it to calculate a time delta between
- the two events::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >>
- events/sched/sched_waking/trigger
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >>
- events/sched/sched_switch/trigger
- In terms of the histogram data structures, variables are implemented
- as another type of hist_field and for a given hist trigger are added
- to the hist_data.fields[] array just after all the val fields. To
- distinguish them from the existing key and val fields, they're given a
- new flag type, HIST_FIELD_FL_VAR (abbreviated FL_VAR) and they also
- make use of a new .var.idx field member in struct hist_field, which
- maps them to an index in a new map_elt.vars[] array added to the
- map_elt specifically designed to store and retrieve variable values.
- The diagram below shows those new elements and adds a new variable
- entry, ts0, corresponding to the ts0 variable in the sched_waking
- trigger above.
- sched_waking histogram
- ----------------------
- .. code-block::
- +------------------+
- | hist_data |<-------------------------------------------------------+
- +------------------+ +-------------------+ |
- | .fields[] |-->| val = hitcount | |
- +----------------+ +-------------------+ |
- | .map | | .size | |
- +----------------+ +-----------------+ |
- | .offset | |
- +-----------------+ |
- | .fn() | |
- +-----------------+ |
- | .flags | |
- +-----------------+ |
- | .var.idx | |
- +-------------------+ |
- | var = ts0 | |
- +-------------------+ |
- | .size | |
- +-----------------+ |
- | .offset | |
- +-----------------+ |
- | .fn() | |
- +-----------------+ |
- | .flags & FL_VAR | |
- +-----------------+ |
- | .var.idx |----------------------------+-+ |
- +-----------------+ | | |
- . | | |
- . | | |
- . | | |
- +-------------------+ <--- n_vals | | |
- | key = pid | | | |
- +-------------------+ | | |
- | .size | | | |
- +-----------------+ | | |
- | .offset | | | |
- +-----------------+ | | |
- | .fn() | | | |
- +-----------------+ | | |
- | .flags & FL_KEY | | | |
- +-----------------+ | | |
- | .var.idx | | | |
- +-------------------+ <--- n_fields | | |
- | unused | | | |
- +-------------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- | | | | |
- +-----------------+ | | |
- n_keys = n_fields - n_vals | | |
- | | |
- This is very similar to the basic case. In the above diagram, we can | | |
- see a new .flags member has been added to the struct hist_field | | |
- struct, and a new entry added to hist_data.fields representing the ts0 | | |
- variable. For a normal val hist_field, .flags is just 0 (modulo | | |
- modifier flags), but if the value is defined as a variable, the .flags | | |
- contains a set FL_VAR bit. | | |
- As you can see, the ts0 entry's .var.idx member contains the index | | |
- into the tracing_map_elts' .vars[] array containing variable values. | | |
- This idx is used whenever the value of the variable is set or read. | | |
- The map_elt.vars idx assigned to the given variable is assigned and | | |
- saved in .var.idx by create_tracing_map_fields() after it calls | | |
- tracing_map_add_var(). | | |
- Below is a representation of the histogram at run-time, which | | |
- populates the map, along with correspondence to the above hist_data and | | |
- hist_field data structures. | | |
- The diagram attempts to show the relationship between the | | |
- hist_data.fields[] and the map_elt.fields[] and map_elt.vars[] with | | |
- the links drawn between diagrams. For each of the map_elts, you can | | |
- see that the .fields[] members point to the .sum or .offset of a key | | |
- or val and the .vars[] members point to the value of a variable. The | | |
- arrows between the two diagrams show the linkages between those | | |
- tracing_map members and the field definitions in the corresponding | | |
- hist_data fields[] members.::
- +-----------+ | | |
- | hist_data | | | |
- +-----------+ | | |
- | .fields | | | |
- +---------+ +-----------+ | | |
- | .map |---->| map_entry | | | |
- +---------+ +-----------+ | | |
- | .key |---> 0 | | |
- +---------+ | | |
- | .val |---> NULL | | |
- +-----------+ | | |
- | map_entry | | | |
- +-----------+ | | |
- | .key |---> pid = 999 | | |
- +---------+ +-----------+ | | |
- | .val |--->| map_elt | | | |
- +---------+ +-----------+ | | |
- . | .key |---> full key * | | |
- . +---------+ +---------------+ | | |
- . | .fields |--->| .sum (val) | | | |
- . +---------+ | 2345 | | | |
- . +--| .vars | +---------------+ | | |
- . | +---------+ | .offset (key) | | | |
- . | | 0 | | | |
- . | +---------------+ | | |
- . | . | | |
- . | . | | |
- . | . | | |
- . | +---------------+ | | |
- . | | .sum (val) or | | | |
- . | | .offset (key) | | | |
- . | +---------------+ | | |
- . | | .sum (val) or | | | |
- . | | .offset (key) | | | |
- . | +---------------+ | | |
- . | | | |
- . +---------------->+---------------+ | | |
- . | ts0 |<--+ | |
- . | 113345679876 | | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . . | | |
- . . | | |
- . . | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . | unused | | | |
- . | | | | |
- . +---------------+ | | |
- . | | |
- +-----------+ | | |
- | map_entry | | | |
- +-----------+ | | |
- | .key |---> pid = 4444 | | |
- +---------+ +-----------+ | | |
- | .val |--->| map_elt | | | |
- +---------+ +-----------+ | | |
- . | .key |---> full key * | | |
- . +---------+ +---------------+ | | |
- . | .fields |--->| .sum (val) | | | |
- +---------+ | 2345 | | | |
- +--| .vars | +---------------+ | | |
- | +---------+ | .offset (key) | | | |
- | | 0 | | | |
- | +---------------+ | | |
- | . | | |
- | . | | |
- | . | | |
- | +---------------+ | | |
- | | .sum (val) or | | | |
- | | .offset (key) | | | |
- | +---------------+ | | |
- | | .sum (val) or | | | |
- | | .offset (key) | | | |
- | +---------------+ | | |
- | | | |
- | +---------------+ | | |
- +---------------->| ts0 |<--+ | |
- | 213499240729 | | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- . | |
- . | |
- . | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- | unused | | |
- | | | |
- +---------------+ | |
- For each used map entry, there's a map_elt pointing to an array of | |
- .vars containing the current value of the variables associated with | |
- that histogram entry. So in the above, the timestamp associated with | |
- pid 999 is 113345679876, and the timestamp variable in the same | |
- .var.idx for pid 4444 is 213499240729. | |
- sched_switch histogram | |
- ---------------------- | |
- The sched_switch histogram paired with the above sched_waking | |
- histogram is shown below. The most important aspect of the | |
- sched_switch histogram is that it references a variable on the | |
- sched_waking histogram above. | |
- The histogram diagram is very similar to the others so far displayed, | |
- but it adds variable references. You can see the normal hitcount and | |
- key fields along with a new wakeup_lat variable implemented in the | |
- same way as the sched_waking ts0 variable, but in addition there's an | |
- entry with the new FL_VAR_REF (short for HIST_FIELD_FL_VAR_REF) flag. | |
- Associated with the new var ref field are a couple of new hist_field | |
- members, var.hist_data and var_ref_idx. For a variable reference, the | |
- var.hist_data goes with the var.idx, which together uniquely identify | |
- a particular variable on a particular histogram. The var_ref_idx is | |
- just the index into the var_ref_vals[] array that caches the values of | |
- each variable whenever a hist trigger is updated. Those resulting | |
- values are then finally accessed by other code such as trace action | |
- code that uses the var_ref_idx values to assign param values. | |
- The diagram below describes the situation for the sched_switch | |
- histogram referred to before::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> | |
- events/sched/sched_switch/trigger | |
- | |
- +------------------+ | |
- | hist_data | | |
- +------------------+ +-----------------------+ | |
- | .fields[] |-->| val = hitcount | | |
- +----------------+ +-----------------------+ | |
- | .map | | .size | | |
- +----------------+ +---------------------+ | |
- +--| .var_refs[] | | .offset | | |
- | +----------------+ +---------------------+ | |
- | | .fn() | | |
- | var_ref_vals[] +---------------------+ | |
- | +-------------+ | .flags | | |
- | | $ts0 |<---+ +---------------------+ | |
- | +-------------+ | | .var.idx | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .var.hist_data | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .var_ref_idx | | |
- | | | | +-----------------------+ | |
- | +-------------+ | | var = wakeup_lat | | |
- | . | +-----------------------+ | |
- | . | | .size | | |
- | . | +---------------------+ | |
- | +-------------+ | | .offset | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .fn() | | |
- | | | | +---------------------+ | |
- | +-------------+ | | .flags & FL_VAR | | |
- | | +---------------------+ | |
- | | | .var.idx | | |
- | | +---------------------+ | |
- | | | .var.hist_data | | |
- | | +---------------------+ | |
- | | | .var_ref_idx | | |
- | | +---------------------+ | |
- | | . | |
- | | . | |
- | | . | |
- | | +-----------------------+ <--- n_vals | |
- | | | key = pid | | |
- | | +-----------------------+ | |
- | | | .size | | |
- | | +---------------------+ | |
- | | | .offset | | |
- | | +---------------------+ | |
- | | | .fn() | | |
- | | +---------------------+ | |
- | | | .flags | | |
- | | +---------------------+ | |
- | | | .var.idx | | |
- | | +-----------------------+ <--- n_fields | |
- | | | unused | | |
- | | +-----------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | | | | |
- | | +---------------------+ | |
- | | n_keys = n_fields - n_vals | |
- | | | |
- | | | |
- | | +-----------------------+ | |
- +---------------------->| var_ref = $ts0 | | |
- | +-----------------------+ | |
- | | .size | | |
- | +---------------------+ | |
- | | .offset | | |
- | +---------------------+ | |
- | | .fn() | | |
- | +---------------------+ | |
- | | .flags & FL_VAR_REF | | |
- | +---------------------+ | |
- | | .var.idx |--------------------------+ |
- | +---------------------+ |
- | | .var.hist_data |----------------------------+
- | +---------------------+
- +---| .var_ref_idx |
- +---------------------+
- Abbreviations used in the diagrams::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- fn = hist_field_fn_t
- FL_KEY = HIST_FIELD_FL_KEY
- FL_VAR = HIST_FIELD_FL_VAR
- FL_VAR_REF = HIST_FIELD_FL_VAR_REF
- When a hist trigger makes use of a variable, a new hist_field is
- created with flag HIST_FIELD_FL_VAR_REF. For a VAR_REF field, the
- var.idx and var.hist_data take the same values as the referenced
- variable, as well as the referenced variable's size, type, and
- is_signed values. The VAR_REF field's .name is set to the name of the
- variable it references. If a variable reference was created using the
- explicit system.event.$var_ref notation, the hist_field's system and
- event_name variables are also set.
- So, in order to handle an event for the sched_switch histogram,
- because we have a reference to a variable on another histogram, we
- need to resolve all variable references first. This is done via the
- resolve_var_refs() calls made from event_hist_trigger(). What this
- does is grabs the var_refs[] array from the hist_data representing the
- sched_switch histogram. For each one of those, the referenced
- variable's var.hist_data along with the current key is used to look up
- the corresponding tracing_map_elt in that histogram. Once found, the
- referenced variable's var.idx is used to look up the variable's value
- using tracing_map_read_var(elt, var.idx), which yields the value of
- the variable for that element, ts0 in the case above. Note that both
- the hist_fields representing both the variable and the variable
- reference have the same var.idx, so this is straightforward.
- Variable and variable reference test
- ------------------------------------
- This example creates a variable on the sched_waking event, ts0, and
- uses it in the sched_switch trigger. The sched_switch trigger also
- creates its own variable, wakeup_lat, but nothing yet uses it::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> events/sched/sched_switch/trigger
- Looking at the sched_waking 'hist_debug' output, in addition to the
- normal key and value hist_fields, in the val fields section we see a
- field with the HIST_FIELD_FL_VAR flag, which indicates that that field
- represents a variable. Note that in addition to the variable name,
- contained in the var.name field, it includes the var.idx, which is the
- index into the tracing_map_elt.vars[] array of the actual variable
- location. Note also that the output shows that variables live in the
- same part of the hist_data->fields[] array as normal values::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 000000009536f554
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- Moving on to the sched_switch trigger hist_debug output, in addition
- to the unused wakeup_lat variable, we see a new section displaying
- variable references. Variable references are displayed in a separate
- section because in addition to being logically separate from
- variables and values, they actually live in a separate hist_data
- array, var_refs[].
- In this example, the sched_switch trigger has a reference to a
- variable on the sched_waking trigger, $ts0. Looking at the details,
- we can see that the var.hist_data value of the referenced variable
- matches the previously displayed sched_waking trigger, and the var.idx
- value matches the previously displayed var.idx value for that
- variable. Also displayed is the var_ref_idx value for that variable
- reference, which is where the value for that variable is cached for
- use when the trigger is invoked::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000f4ee8006
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 000000009536f554
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Actions and Handlers
- ====================
- Adding onto the previous example, we will now do something with that
- wakeup_lat variable, namely send it and another field as a synthetic
- event.
- The onmatch() action below basically says that whenever we have a
- sched_switch event, if we have a matching sched_waking event, in this
- case if we have a pid in the sched_waking histogram that matches the
- next_pid field on this sched_switch event, we retrieve the
- variables specified in the wakeup_latency() trace action, and use
- them to generate a new wakeup_latency event into the trace stream.
- Note that the way the trace handlers such as wakeup_latency() (which
- could equivalently be written trace(wakeup_latency,$wakeup_lat,next_pid)
- are implemented, the parameters specified to the trace handler must be
- variables. In this case, $wakeup_lat is obviously a variable, but
- next_pid isn't, since it's just naming a field in the sched_switch
- trace event. Since this is something that almost every trace() and
- save() action does, a special shortcut is implemented to allow field
- names to be used directly in those cases. How it works is that under
- the covers, a temporary variable is created for the named field, and
- this variable is what is actually passed to the trace handler. In the
- code and documentation, this type of variable is called a 'field
- variable'.
- Fields on other trace event's histograms can be used as well. In that
- case we have to generate a new histogram and an unfortunately named
- 'synthetic_field' (the use of synthetic here has nothing to do with
- synthetic events) and use that special histogram field as a variable.
- The diagram below illustrates the new elements described above in the
- context of the sched_switch histogram using the onmatch() handler and
- the trace() action.
- First, we define the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid' >> synthetic_events
- Next, the sched_waking hist trigger as before::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >>
- events/sched/sched_waking/trigger
- Finally, we create a hist trigger on the sched_switch event that
- generates a wakeup_latency() trace event. In this case we pass
- next_pid into the wakeup_latency synthetic event invocation, which
- means it will be automatically converted into a field variable::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid)' >>
- /sys/kernel/tracing/events/sched/sched_switch/trigger
- The diagram for the sched_switch event is similar to previous examples
- but shows the additional field_vars[] array for hist_data and shows
- the linkages between the field_vars and the variables and references
- created to implement the field variables. The details are discussed
- below::
- +------------------+
- | hist_data |
- +------------------+ +-----------------------+
- | .fields[] |-->| val = hitcount |
- +----------------+ +-----------------------+
- | .map | | .size |
- +----------------+ +---------------------+
- +---| .field_vars[] | | .offset |
- | +----------------+ +---------------------+
- |+--| .var_refs[] | | .offset |
- || +----------------+ +---------------------+
- || | .fn() |
- || var_ref_vals[] +---------------------+
- || +-------------+ | .flags |
- || | $ts0 |<---+ +---------------------+
- || +-------------+ | | .var.idx |
- || | $next_pid |<-+ | +---------------------+
- || +-------------+ | | | .var.hist_data |
- ||+>| $wakeup_lat | | | +---------------------+
- ||| +-------------+ | | | .var_ref_idx |
- ||| | | | | +-----------------------+
- ||| +-------------+ | | | var = wakeup_lat |
- ||| . | | +-----------------------+
- ||| . | | | .size |
- ||| . | | +---------------------+
- ||| +-------------+ | | | .offset |
- ||| | | | | +---------------------+
- ||| +-------------+ | | | .fn() |
- ||| | | | | +---------------------+
- ||| +-------------+ | | | .flags & FL_VAR |
- ||| | | +---------------------+
- ||| | | | .var.idx |
- ||| | | +---------------------+
- ||| | | | .var.hist_data |
- ||| | | +---------------------+
- ||| | | | .var_ref_idx |
- ||| | | +---------------------+
- ||| | | .
- ||| | | .
- ||| | | .
- ||| | | .
- ||| +--------------+ | | .
- +-->| field_var | | | .
- || +--------------+ | | .
- || | var | | | .
- || +------------+ | | .
- || | val | | | .
- || +--------------+ | | .
- || | field_var | | | .
- || +--------------+ | | .
- || | var | | | .
- || +------------+ | | .
- || | val | | | .
- || +------------+ | | .
- || . | | .
- || . | | .
- || . | | +-----------------------+ <--- n_vals
- || +--------------+ | | | key = pid |
- || | field_var | | | +-----------------------+
- || +--------------+ | | | .size |
- || | var |--+| +---------------------+
- || +------------+ ||| | .offset |
- || | val |-+|| +---------------------+
- || +------------+ ||| | .fn() |
- || ||| +---------------------+
- || ||| | .flags |
- || ||| +---------------------+
- || ||| | .var.idx |
- || ||| +---------------------+ <--- n_fields
- || |||
- || ||| n_keys = n_fields - n_vals
- || ||| +-----------------------+
- || |+->| var = next_pid |
- || | | +-----------------------+
- || | | | .size |
- || | | +---------------------+
- || | | | .offset |
- || | | +---------------------+
- || | | | .flags & FL_VAR |
- || | | +---------------------+
- || | | | .var.idx |
- || | | +---------------------+
- || | | | .var.hist_data |
- || | | +-----------------------+
- || +-->| val for next_pid |
- || | | +-----------------------+
- || | | | .size |
- || | | +---------------------+
- || | | | .offset |
- || | | +---------------------+
- || | | | .fn() |
- || | | +---------------------+
- || | | | .flags |
- || | | +---------------------+
- || | | | |
- || | | +---------------------+
- || | |
- || | |
- || | | +-----------------------+
- +|------------------|-|>| var_ref = $ts0 |
- | | | +-----------------------+
- | | | | .size |
- | | | +---------------------+
- | | | | .offset |
- | | | +---------------------+
- | | | | .fn() |
- | | | +---------------------+
- | | | | .flags & FL_VAR_REF |
- | | | +---------------------+
- | | +---| .var_ref_idx |
- | | +-----------------------+
- | | | var_ref = $next_pid |
- | | +-----------------------+
- | | | .size |
- | | +---------------------+
- | | | .offset |
- | | +---------------------+
- | | | .fn() |
- | | +---------------------+
- | | | .flags & FL_VAR_REF |
- | | +---------------------+
- | +-----| .var_ref_idx |
- | +-----------------------+
- | | var_ref = $wakeup_lat |
- | +-----------------------+
- | | .size |
- | +---------------------+
- | | .offset |
- | +---------------------+
- | | .fn() |
- | +---------------------+
- | | .flags & FL_VAR_REF |
- | +---------------------+
- +------------------------| .var_ref_idx |
- +---------------------+
- As you can see, for a field variable, two hist_fields are created: one
- representing the variable, in this case next_pid, and one to actually
- get the value of the field from the trace stream, like a normal val
- field does. These are created separately from normal variable
- creation and are saved in the hist_data->field_vars[] array. See
- below for how these are used. In addition, a reference hist_field is
- also created, which is needed to reference the field variables such as
- $next_pid variable in the trace() action.
- Note that $wakeup_lat is also a variable reference, referencing the
- value of the expression common_timestamp-$ts0, and so also needs to
- have a hist field entry representing that reference created.
- When hist_trigger_elt_update() is called to get the normal key and
- value fields, it also calls update_field_vars(), which goes through
- each field_var created for the histogram, and available from
- hist_data->field_vars and calls val->fn() to get the data from the
- current trace record, and then uses the var's var.idx to set the
- variable at the var.idx offset in the appropriate tracing_map_elt's
- variable at elt->vars[var.idx].
- Once all the variables have been updated, resolve_var_refs() can be
- called from event_hist_trigger(), and not only can our $ts0 and
- $next_pid references be resolved but the $wakeup_lat reference as
- well. At this point, the trace() action can simply access the values
- assembled in the var_ref_vals[] array and generate the trace event.
- The same process occurs for the field variables associated with the
- save() action.
- Abbreviations used in the diagram::
- hist_data = struct hist_trigger_data
- hist_data.fields = struct hist_field
- field_var = struct field_var
- fn = hist_field_fn_t
- FL_KEY = HIST_FIELD_FL_KEY
- FL_VAR = HIST_FIELD_FL_VAR
- FL_VAR_REF = HIST_FIELD_FL_VAR_REF
- trace() action field variable test
- ----------------------------------
- This example adds to the previous test example by finally making use
- of the wakeup_lat variable, but in addition also creates a couple of
- field variables that then are all passed to the wakeup_latency() trace
- action via the onmatch() handler.
- First, we create the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- Next, the sched_waking trigger from previous examples::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Finally, as in the previous test example, we calculate and assign the
- wakeup latency using the $ts0 reference from the sched_waking trigger
- to the wakeup_lat variable, and finally use it along with a couple
- sched_switch event fields, next_pid and next_comm, to generate a
- wakeup_latency trace event. The next_pid and next_comm event fields
- are automatically converted into field variables for this purpose::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm)' >> /sys/kernel/tracing/events/sched/sched_switch/trigger
- The sched_waking hist_debug output shows the same data as in the
- previous test example::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000d60ff61f
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The sched_switch hist_debug output shows the same key and value fields
- as in the previous test example - note that wakeup_lat is still in the
- val fields section, but that the new field variables are not there -
- although the field variables are variables, they're held separately in
- the hist_data's field_vars[] array. Although the field variables and
- the normal variables are located in separate places, you can see that
- the actual variable locations for those variables in the
- tracing_map_elt.vars[] do have increasing indices as expected:
- wakeup_lat takes the var.idx = 0 slot, while the field variables for
- next_pid and next_comm have values var.idx = 1, and var.idx = 2. Note
- also that those are the same values displayed for the variable
- references corresponding to those variables in the variable reference
- fields section. Since there are two triggers and thus two hist_data
- addresses, those addresses also need to be accounted for when doing
- the matching - you can see that the first variable refers to the 0
- var.idx on the previous hist trigger (see the hist_data address
- associated with that trigger), while the second variable refers to the
- 0 var.idx on the sched_switch hist trigger, as do all the remaining
- variable references.
- Finally, the action tracking variables section just shows the system
- and event name for the onmatch() handler::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm) [active]
- #
- hist_data: 0000000008f551b7
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000d60ff61f
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 2
- type: pid_t
- size: 4
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- var.hist_data: 0000000008f551b7
- var_ref_idx (into hist_data->var_refs[]): 3
- type: char[16]
- size: 256
- is_signed: 0
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- field_vars[0].val:
- ftrace_event_field name: next_pid
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->field_vars[1]:
- field_vars[1].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- field_vars[1].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,next_comm)' >> /sys/kernel/tracing/events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- action_data and the trace() action
- ----------------------------------
- As mentioned above, when the trace() action generates a synthetic
- event, all the parameters to the synthetic event either already are
- variables or are converted into variables (via field variables), and
- finally all those variable values are collected via references to them
- into a var_ref_vals[] array.
- The values in the var_ref_vals[] array, however, don't necessarily
- follow the same ordering as the synthetic event params. To address
- that, struct action_data contains another array, var_ref_idx[] that
- maps the trace action params to the var_ref_vals[] values. Below is a
- diagram illustrating that for the wakeup_latency() synthetic event::
- +------------------+ wakeup_latency()
- | action_data | event params var_ref_vals[]
- +------------------+ +-----------------+ +-----------------+
- | .var_ref_idx[] |--->| $wakeup_lat idx |---+ | |
- +----------------+ +-----------------+ | +-----------------+
- | .synth_event | | $next_pid idx |---|-+ | $wakeup_lat val |
- +----------------+ +-----------------+ | | +-----------------+
- . | +->| $next_pid val |
- . | +-----------------+
- . | .
- +-----------------+ | .
- | | | .
- +-----------------+ | +-----------------+
- +--->| $wakeup_lat val |
- +-----------------+
- Basically, how this ends up getting used in the synthetic event probe
- function, trace_event_raw_event_synth(), is as follows::
- for each field i in .synth_event
- val_idx = .var_ref_idx[i]
- val = var_ref_vals[val_idx]
- action_data and the onXXX() handlers
- ------------------------------------
- The hist trigger onXXX() actions other than onmatch(), such as onmax()
- and onchange(), also make use of and internally create hidden
- variables. This information is contained in the
- action_data.track_data struct, and is also visible in the hist_debug
- output as will be described in the example below.
- Typically, the onmax() or onchange() handlers are used in conjunction
- with the save() and snapshot() actions. For example::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >>
- /sys/kernel/tracing/events/sched/sched_switch/trigger
- or::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \
- onmax($wakeup_lat).snapshot()' >>
- /sys/kernel/tracing/events/sched/sched_switch/trigger
- save() action field variable test
- ---------------------------------
- For this example, instead of generating a synthetic event, the save()
- action is used to save field values whenever an onmax() handler
- detects that a new max latency has been hit. As in the previous
- example, the values being saved are also field values, but in this
- case, are kept in a separate hist_data array named save_vars[].
- As in previous test examples, we set up the sched_waking trigger::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- In this case, however, we set up the sched_switch trigger to save some
- sched_switch field values whenever we hit a new maximum latency. For
- both the onmax() handler and save() action, variables will be created,
- which we can use the hist_debug files to examine::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >> events/sched/sched_switch/trigger
- The sched_waking hist_debug output shows the same data as in the
- previous test examples::
- # cat events/sched/sched_waking/hist_debug
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000e6290f48
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The output of the sched_switch trigger shows the same val and key
- values as before, but also shows a couple new sections.
- First, the action tracking variables section now shows the
- actions[].track_data information describing the special tracking
- variables and references used to track, in this case, the running
- maximum value. The actions[].track_data.var_ref member contains the
- reference to the variable being tracked, in this case the $wakeup_lat
- variable. In order to perform the onmax() handler function, there
- also needs to be a variable that tracks the current maximum by getting
- updated whenever a new maximum is hit. In this case, we can see that
- an auto-generated variable named ' __max' has been created and is
- visible in the actions[].track_data.track_var variable.
- Finally, in the new 'save action variables' section, we can see that
- the 4 params to the save() function have resulted in 4 field variables
- being created for the purposes of saving the values of the named
- fields when the max is hit. These variables are kept in a separate
- save_vars[] array off of hist_data, so are displayed in a separate
- section::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) [active]
- #
- hist_data: 0000000057bcd28d
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000e6290f48
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000057bcd28d
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].track_data.var_ref:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000057bcd28d
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->actions[0].track_data.track_var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: __max
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 8
- is_signed: 0
- save action variables (save() params):
- hist_data->save_vars[0]:
- save_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- save_vars[0].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- hist_data->save_vars[1]:
- save_vars[1].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_pid
- var.idx (into tracing_map_elt.vars[]): 3
- save_vars[1].val:
- ftrace_event_field name: prev_pid
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->save_vars[2]:
- save_vars[2].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_prio
- var.idx (into tracing_map_elt.vars[]): 4
- save_vars[2].val:
- ftrace_event_field name: prev_prio
- type: int
- size: 4
- is_signed: 1
- hist_data->save_vars[3]:
- save_vars[3].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: prev_comm
- var.idx (into tracing_map_elt.vars[]): 5
- save_vars[3].val:
- ftrace_event_field name: prev_comm
- type: char[16]
- size: 256
- is_signed: 0
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- A couple special cases
- ======================
- While the above covers the basics of the histogram internals, there
- are a couple of special cases that should be discussed, since they
- tend to create even more confusion. Those are field variables on other
- histograms, and aliases, both described below through example tests
- using the hist_debug files.
- Test of field variables on other histograms
- -------------------------------------------
- This example is similar to the previous examples, but in this case,
- the sched_switch trigger references a hist trigger field on another
- event, namely the sched_waking event. In order to accomplish this, a
- field variable is created for the other event, but since an existing
- histogram can't be used, as existing histograms are immutable, a new
- histogram with a matching variable is created and used, and we'll see
- that reflected in the hist_debug output shown below.
- First, we create the wakeup_latency synthetic event. Note the
- addition of the prio field::
- # echo 'wakeup_latency u64 lat; pid_t pid; int prio' >> synthetic_events
- As in previous test examples, we set up the sched_waking trigger::
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- Here we set up a hist trigger on sched_switch to send a wakeup_latency
- event using an onmatch handler naming the sched_waking event. Note
- that the third param being passed to the wakeup_latency() is prio,
- which is a field name that needs to have a field variable created for
- it. There isn't however any prio field on the sched_switch event so
- it would seem that it wouldn't be possible to create a field variable
- for it. The matching sched_waking event does have a prio field, so it
- should be possible to make use of it for this purpose. The problem
- with that is that it's not currently possible to define a new variable
- on an existing histogram, so it's not possible to add a new prio field
- variable to the existing sched_waking histogram. It is however
- possible to create an additional new 'matching' sched_waking histogram
- for the same event, meaning that it uses the same key and filters, and
- define the new prio field variable on that.
- Here's the sched_switch trigger::
- # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio)' >> events/sched/sched_switch/trigger
- And here's the output of the hist_debug information for the
- sched_waking hist trigger. Note that there are two histograms
- displayed in the output: the first is the normal sched_waking
- histogram we've seen in the previous examples, and the second is the
- special histogram we created to provide the prio field variable.
- Looking at the second histogram below, we see a variable with the name
- synthetic_prio. This is the field variable created for the prio field
- on that sched_waking histogram::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000349570e4
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:synthetic_prio=prio:sort=hitcount:size=2048 [active]
- #
- hist_data: 000000006920cf38
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- ftrace_event_field name: prio
- var.name: synthetic_prio
- var.idx (into tracing_map_elt.vars[]): 0
- type: int
- size: 4
- is_signed: 1
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- Looking at the sched_switch histogram below, we can see a reference to
- the synthetic_prio variable on sched_waking, and looking at the
- associated hist_data address we see that it is indeed associated with
- the new histogram. Note also that the other references are to a
- normal variable, wakeup_lat, and to a normal field variable, next_pid,
- the details of which are in the field variables section::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio) [active]
- #
- hist_data: 00000000a73b67df
- n_vals: 2
- n_keys: 1
- n_fields: 3
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000349570e4
- var_ref_idx (into hist_data->var_refs[]): 0
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000a73b67df
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 00000000a73b67df
- var_ref_idx (into hist_data->var_refs[]): 2
- type: pid_t
- size: 4
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: synthetic_prio
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 000000006920cf38
- var_ref_idx (into hist_data->var_refs[]): 3
- type: int
- size: 4
- is_signed: 1
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_pid
- var.idx (into tracing_map_elt.vars[]): 1
- field_vars[0].val:
- ftrace_event_field name: next_pid
- type: pid_t
- size: 4
- is_signed: 1
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,prio)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; int prio' >> synthetic_events
- Alias test
- ----------
- This example is very similar to previous examples, but demonstrates
- the alias flag.
- First, we create the wakeup_latency synthetic event::
- # echo 'wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
- Next, we create a sched_waking trigger similar to previous examples,
- but in this case we save the pid in the waking_pid variable::
- # echo 'hist:keys=pid:waking_pid=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- For the sched_switch trigger, instead of using $waking_pid directly in
- the wakeup_latency synthetic event invocation, we create an alias of
- $waking_pid named $woken_pid, and use that in the synthetic event
- invocation instead::
- # echo 'hist:keys=next_pid:woken_pid=$waking_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm)' >> events/sched/sched_switch/trigger
- Looking at the sched_waking hist_debug output, in addition to the
- normal fields, we can see the waking_pid variable::
- # cat events/sched/sched_waking/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=pid:vals=hitcount:waking_pid=pid,ts0=common_timestamp.usecs:sort=hitcount:size=2048:clock=global [active]
- #
- hist_data: 00000000a250528c
- n_vals: 3
- n_keys: 1
- n_fields: 4
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- ftrace_event_field name: pid
- var.name: waking_pid
- var.idx (into tracing_map_elt.vars[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: ts0
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 8
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: pid
- type: pid_t
- size: 8
- is_signed: 1
- The sched_switch hist_debug output shows that a variable named
- woken_pid has been created but that it also has the
- HIST_FIELD_FL_ALIAS flag set. It also has the HIST_FIELD_FL_VAR flag
- set, which is why it appears in the val field section.
- Despite that implementation detail, an alias variable is actually more
- like a variable reference; in fact it can be thought of as a reference
- to a reference. The implementation copies the var_ref->fn() from the
- variable reference being referenced, in this case, the waking_pid
- fn(), which is hist_field_var_ref() and makes that the fn() of the
- alias. The hist_field_var_ref() fn() requires the var_ref_idx of the
- variable reference it's using, so waking_pid's var_ref_idx is also
- copied to the alias. The end result is that when the value of alias
- is retrieved, in the end it just does the same thing the original
- reference would have done and retrieves the same value from the
- var_ref_vals[] array. You can verify this in the output by noting
- that the var_ref_idx of the alias, in this case woken_pid, is the same
- as the var_ref_idx of the reference, waking_pid, in the variable
- reference fields section.
- Additionally, once it gets that value, since it is also a variable, it
- then saves that value into its var.idx. So the var.idx of the
- woken_pid alias is 0, which it fills with the value from var_ref_idx 0
- when its fn() is called to update itself. You'll also notice that
- there's a woken_pid var_ref in the variable refs section. That is the
- reference to the woken_pid alias variable, and you can see that it
- retrieves the value from the same var.idx as the woken_pid alias, 0,
- and then in turn saves that value in its own var_ref_idx slot, 3, and
- the value at this position is finally what gets assigned to the
- $woken_pid slot in the trace event invocation::
- # cat events/sched/sched_switch/hist_debug
- # event histogram
- #
- # trigger info: hist:keys=next_pid:vals=hitcount:woken_pid=$waking_pid,wakeup_lat=common_timestamp.usecs-$ts0:sort=hitcount:size=2048:clock=global:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm) [active]
- #
- hist_data: 0000000055d65ed0
- n_vals: 3
- n_keys: 1
- n_fields: 4
- val fields:
- hist_data->fields[0]:
- flags:
- VAL: HIST_FIELD_FL_HITCOUNT
- type: u64
- size: 8
- is_signed: 0
- hist_data->fields[1]:
- flags:
- HIST_FIELD_FL_VAR
- HIST_FIELD_FL_ALIAS
- var.name: woken_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var_ref_idx (into hist_data->var_refs[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->fields[2]:
- flags:
- HIST_FIELD_FL_VAR
- var.name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 1
- type: u64
- size: 0
- is_signed: 0
- key fields:
- hist_data->fields[3]:
- flags:
- HIST_FIELD_FL_KEY
- ftrace_event_field name: next_pid
- type: pid_t
- size: 8
- is_signed: 1
- variable reference fields:
- hist_data->var_refs[0]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: waking_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 00000000a250528c
- var_ref_idx (into hist_data->var_refs[]): 0
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->var_refs[1]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: ts0
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 00000000a250528c
- var_ref_idx (into hist_data->var_refs[]): 1
- type: u64
- size: 8
- is_signed: 0
- hist_data->var_refs[2]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: wakeup_lat
- var.idx (into tracing_map_elt.vars[]): 1
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 2
- type: u64
- size: 0
- is_signed: 0
- hist_data->var_refs[3]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: woken_pid
- var.idx (into tracing_map_elt.vars[]): 0
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 3
- type: pid_t
- size: 4
- is_signed: 1
- hist_data->var_refs[4]:
- flags:
- HIST_FIELD_FL_VAR_REF
- name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- var.hist_data: 0000000055d65ed0
- var_ref_idx (into hist_data->var_refs[]): 4
- type: char[16]
- size: 256
- is_signed: 0
- field variables:
- hist_data->field_vars[0]:
- field_vars[0].var:
- flags:
- HIST_FIELD_FL_VAR
- var.name: next_comm
- var.idx (into tracing_map_elt.vars[]): 2
- field_vars[0].val:
- ftrace_event_field name: next_comm
- type: char[16]
- size: 256
- is_signed: 0
- action tracking variables (for onmax()/onchange()/onmatch()):
- hist_data->actions[0].match_data.event_system: sched
- hist_data->actions[0].match_data.event: sched_waking
- The commands below can be used to clean things up for the next test::
- # echo '!hist:keys=next_pid:woken_pid=$waking_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,$woken_pid,next_comm)' >> events/sched/sched_switch/trigger
- # echo '!hist:keys=pid:ts0=common_timestamp.usecs' >> events/sched/sched_waking/trigger
- # echo '!wakeup_latency u64 lat; pid_t pid; char comm[16]' >> synthetic_events
|