1<?xml version="1.0" encoding="ISO-8859-1"?> 2<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" 3 "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ 4 <!ENTITY % defs SYSTEM "/xserver/doc/xml/xserver.ent"> %defs; 5]> 6 7<article id="Xserver-DTrace"> 8 <articleinfo> 9 <title>Xserver Provider for DTrace</title> 10 <author> 11 <firstname>Alan</firstname><surname>Coopersmith</surname> 12 <affiliation> 13 <orgname>Oracle Corporation</orgname> 14 <orgdiv>Solaris Engineering</orgdiv> 15 </affiliation> 16 </author> 17 <releaseinfo>X Server Version &xserver.version;</releaseinfo> 18 <copyright><year>2005</year><year>2006</year><year>2007</year><year>2010</year><year>2020</year> 19 <holder>Oracle and/or its affiliates.</holder> 20 </copyright> 21 <legalnotice id="copyright"> 22 <para> 23Permission is hereby granted, free of charge, to any person obtaining a 24copy of this software and associated documentation files (the "Software"), 25to deal in the Software without restriction, including without limitation 26the rights to use, copy, modify, merge, publish, distribute, sublicense, 27and/or sell copies of the Software, and to permit persons to whom the 28Software is furnished to do so, subject to the following conditions: 29 </para><para> 30The above copyright notice and this permission notice (including the next 31paragraph) shall be included in all copies or substantial portions of the 32Software. 33 </para><para> 34THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 37THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 39FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 40DEALINGS IN THE SOFTWARE. 41 </para> 42 </legalnotice> 43 </articleinfo> 44 45 <sect1 id="introduction"> 46 <title>Introduction</title> 47 <para> 48 This page provides details on a 49 <ulink url="http://dtrace.org/guide/chp-usdt.html">statically defined user application tracing provider</ulink> 50 for the 51 <ulink url="http://dtrace.org/blogs/about/">DTrace</ulink> 52 facility in <productname>Solaris</productname> 10, 53 <productname>MacOS X</productname> 10.5, and later releases. This 54 provider instruments various points in the X server, to allow 55 tracing what client applications are up to. DTrace probes may be used 56 with <ulink url="http://sourceware.org/systemtap/">SystemTap</ulink> 57 on GNU/Linux systems. 58 </para> 59 60 <para> 61 The provider was integrated into the X.Org git master repository 62 with Solaris 10 & OpenSolaris support for the Xserver 1.4 release, 63 released in 2007 with X11R7.3. Support for DTrace on MacOS X 64 was added in Xserver 1.7. 65 </para> 66 67 <para> 68 These probes expose the request and reply structure of the X protocol 69 between clients and the X server, so an understanding of that basic 70 nature will aid in learning how to use these probes. 71 </para> 72 </sect1> 73 74 <sect1 id="probes"> 75 <title>Available probes</title> 76 77 <para> 78 Due to the way User-Defined DTrace probes work, arguments to 79 these probes all bear undistinguished names of 80 <parameter>arg0</parameter>, <parameter>arg1</parameter>, 81 <parameter>arg2</parameter>, etc. These tables should help you 82 determine what the real data is for each of the probe arguments. 83 84 <table id="Probes_and_their_arguments"> 85 <title>Probes and their arguments</title> 86 <tgroup cols='9'> 87 <colspec colname="probe" colwidth="2*"/> 88 <colspec colname="desc" colwidth="3*"/> 89 <colspec colname="arg0" colwidth="1*"/> 90 <colspec colname="arg1" colwidth="1*"/> 91 <colspec colname="arg2" colwidth="1*"/> 92 <colspec colname="arg3" colwidth="1*"/> 93 <colspec colname="arg4" colwidth="1*"/> 94 <colspec colname="arg5" colwidth="1*"/> 95 <colspec colname="arg6" colwidth="1*"/> 96 <spanspec spanname="all" namest="probe" nameend="arg4"/> 97 <thead> 98 <row> 99 <entry>Probe name</entry> 100 <entry>Description</entry> 101 <entry>arg0</entry> 102 <entry>arg1</entry> 103 <entry>arg2</entry> 104 <entry>arg3</entry> 105 <entry>arg4</entry> 106 <entry>arg5</entry> 107 <entry>arg6</entry> 108 </row> 109 </thead> 110 <tbody> 111 <row> 112 <entry spanname="all" class="grouphead">Request Probes</entry> 113 </row> 114 <row> 115 <entry>request-start</entry> 116 <entry>Called just before processing each client request.</entry> 117 <entry><parameter>requestName</parameter></entry> 118 <entry><parameter>requestCode</parameter></entry> 119 <entry><parameter>requestLength</parameter></entry> 120 <entry><parameter>clientId</parameter></entry> 121 <entry><parameter>requestBuffer</parameter></entry> 122 <entry nameend="arg5" class="unused"/> 123 <entry nameend="arg6" class="unused"/> 124 </row> 125 <row> 126 <entry>request-done</entry> 127 <entry>Called just after processing each client request.</entry> 128 <entry><parameter>requestName</parameter></entry> 129 <entry><parameter>requestCode</parameter></entry> 130 <entry><parameter>sequenceNumber</parameter></entry> 131 <entry><parameter>clientId</parameter></entry> 132 <entry><parameter>resultCode</parameter></entry> 133 <entry nameend="arg5" class="unused"/> 134 <entry nameend="arg6" class="unused"/> 135 </row> 136 <row> 137 <entry spanname="all" class="grouphead">Event Probes</entry> 138 </row> 139 <row> 140 <entry>send-event</entry> 141 <entry>Called just before send each event to a client.</entry> 142 <entry><parameter>clientId</parameter></entry> 143 <entry><parameter>eventCode</parameter></entry> 144 <entry><parameter>eventBuffer</parameter></entry> 145 <entry nameend="arg3" class="unused"/> 146 <entry nameend="arg4" class="unused"/> 147 <entry nameend="arg5" class="unused"/> 148 <entry nameend="arg6" class="unused"/> 149 </row> 150 <row> 151 <entry spanname="all" class="grouphead">Client Connection Probes</entry> 152 </row> 153 <row> 154 <entry>client-connect</entry> 155 <entry>Called when a new connection is opened from a client</entry> 156 <entry><parameter>clientId</parameter></entry> 157 <entry><parameter>clientFD</parameter></entry> 158 <entry nameend="arg2" class="unused"/> 159 <entry nameend="arg3" class="unused"/> 160 <entry nameend="arg4" class="unused"/> 161 <entry nameend="arg5" class="unused"/> 162 <entry nameend="arg6" class="unused"/> 163 </row> 164 <row> 165 <entry>client-auth</entry> 166 <entry>Called when client authenticates (normally just after connection opened)</entry> 167 <entry><parameter>clientId</parameter></entry> 168 <entry><parameter>clientAddr</parameter></entry> 169 <entry><parameter>clientPid</parameter></entry> 170 <entry><parameter>clientZoneId</parameter></entry> 171 <entry nameend="arg4" class="unused"/> 172 <entry nameend="arg5" class="unused"/> 173 <entry nameend="arg6" class="unused"/> 174 </row> 175 <row> 176 <entry>client-disconnect</entry> 177 <entry>Called when a client connection is closed</entry> 178 <entry><parameter>clientId</parameter></entry> 179 <entry nameend="arg1" class="unused"/> 180 <entry nameend="arg2" class="unused"/> 181 <entry nameend="arg3" class="unused"/> 182 <entry nameend="arg4" class="unused"/> 183 <entry nameend="arg5" class="unused"/> 184 <entry nameend="arg6" class="unused"/> 185 </row> 186 <row> 187 <entry spanname="all" class="grouphead">Resource Allocation Probes</entry> 188 </row> 189 <row> 190 <entry>resource-alloc</entry> 191 <entry>Called when a new resource (pixmap, gc, colormap, etc.) is allocated</entry> 192 <entry><parameter>resourceId</parameter></entry> 193 <entry><parameter>resourceTypeId</parameter></entry> 194 <entry><parameter>resourceValue</parameter></entry> 195 <entry><parameter>resourceTypeName</parameter></entry> 196 <entry nameend="arg4" class="unused"/> 197 <entry nameend="arg5" class="unused"/> 198 <entry nameend="arg6" class="unused"/> 199 </row> 200 <row> 201 <entry>resource-free</entry> 202 <entry>Called when a resource is freed</entry> 203 <entry><parameter>resourceId</parameter></entry> 204 <entry><parameter>resourceTypeId</parameter></entry> 205 <entry><parameter>resourceValue</parameter></entry> 206 <entry><parameter>resourceTypeName</parameter></entry> 207 <entry nameend="arg4" class="unused"/> 208 <entry nameend="arg5" class="unused"/> 209 <entry nameend="arg6" class="unused"/> 210 </row> 211 <row> 212 <entry spanname="all" class="grouphead">Input API probes</entry> 213 </row> 214 <row> 215 <entry>input-event</entry> 216 <entry>Called when an input event was submitted for processing</entry> 217 <entry><parameter>deviceid</parameter></entry> 218 <entry><parameter>eventtype</parameter></entry> 219 <entry><parameter>button</parameter> or 220 <parameter>keycode</parameter> or 221 <parameter>touchid</parameter></entry> 222 <entry><parameter>flags</parameter></entry> 223 <entry><parameter>nvalues</parameter></entry> 224 <entry><parameter>mask</parameter></entry> 225 <entry><parameter>values</parameter></entry> 226 </row> 227 </tbody> 228 </tgroup> 229 </table> 230 </para> 231 </sect1> 232 233 <sect1 id="arguments"> 234 <title>Data Available in Probe Arguments</title> 235 236 <para> 237 To access data in arguments of type <type>string</type>, you will need 238 to use <ulink url="http://dtrace.org/guide/chp-actsub.html#chp-actsub-copyinstr"><function>copyinstr()</function></ulink>. 239 To access data buffers referenced via <type>uintptr_t</type>'s, you will 240 need to use <ulink url="http://dtrace.org/guide/chp-actsub.html#chp-actsub-copyin"><function>copyin()</function></ulink>. 241 242 <table id="Probe_Arguments"> 243 <title>Probe Arguments</title> 244 <tgroup cols='3'> 245 <colspec colname="arg" colwidth="2*"/> 246 <colspec colname="type" colwidth="1*"/> 247 <colspec colname="desc" colwidth="7*"/> 248 <thead> 249 <row> 250 <entry>Argument name</entry> 251 <entry>Type</entry> 252 <entry>Description</entry> 253 </row> 254 </thead> 255 <tbody> 256 <row> 257 <entry><parameter>clientAddr</parameter></entry> 258 <entry><type>string</type></entry> 259 <entry>String representing address client connected from</entry> 260 </row> 261 <row> 262 <entry><parameter>clientFD</parameter></entry> 263 <entry><type>int</type></entry> 264 <entry>X server's file descriptor for server side of each connection</entry> 265 </row> 266 <row> 267 <entry><parameter>clientId</parameter></entry> 268 <entry><type>int</type></entry> 269 <entry>Unique integer identifier for each connection to the 270 X server</entry> 271 </row> 272 <row> 273 <entry><parameter>clientPid</parameter></entry> 274 <entry><type>pid_t</type></entry> 275 <entry>Process id of client, if connection is local 276 (from <function>getpeerucred()</function>)</entry> 277 </row> 278 <row> 279 <entry><parameter>clientZoneId</parameter></entry> 280 <entry><type>zoneid_t</type></entry> 281 <entry>Solaris: Zone id of client, if connection is local 282 (from <function>getpeerucred()</function>)</entry> 283 </row> 284 <row> 285 <entry><parameter>eventBuffer</parameter></entry> 286 <entry><type>uintptr_t</type></entry> 287 <entry>Pointer to buffer containing X event - decode using 288 structures in 289 <<ulink url="https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/blob/master/include/X11/Xproto.h"><filename class="headerfile">X11/Xproto.h</filename></ulink>> 290 and similar headers for each extension</entry> 291 </row> 292 <row> 293 <entry><parameter>eventCode</parameter></entry> 294 <entry><type>uint8_t</type></entry> 295 <entry>Event number of X event</entry> 296 </row> 297 <row> 298 <entry><parameter>resourceId</parameter></entry> 299 <entry><type>uint32_t</type></entry> 300 <entry>X resource id (XID)</entry> 301 </row> 302 <row> 303 <entry><parameter>resourceTypeId</parameter></entry> 304 <entry><type>uint32_t</type></entry> 305 <entry>Resource type id</entry> 306 </row> 307 <row> 308 <entry><parameter>resourceTypeName</parameter></entry> 309 <entry><type>string</type></entry> 310 <entry>String representing X resource type 311 (<literal>"PIXMAP"</literal>, etc.)</entry> 312 </row> 313 <row> 314 <entry><parameter>resourceValue</parameter></entry> 315 <entry><type>uintptr_t</type></entry> 316 <entry>Pointer to data for X resource</entry> 317 </row> 318 <row> 319 <entry><parameter>resultCode</parameter></entry> 320 <entry><type>int</type></entry> 321 <entry>Integer code representing result status of request</entry> 322 </row> 323 <row> 324 <entry><parameter>requestBuffer</parameter></entry> 325 <entry><type>uintptr_t</type></entry> 326 <entry>Pointer to buffer containing X request - decode using 327 structures in 328 <<ulink url="https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/blob/master/include/X11/Xproto.h"><filename class="headerfile">X11/Xproto.h</filename></ulink>> 329 and similar headers for each extension</entry> 330 </row> 331 <row> 332 <entry><parameter>requestCode</parameter></entry> 333 <entry><type>uint8_t</type></entry> 334 <entry>Request number of X request or Extension</entry> 335 </row> 336 <row> 337 <entry><parameter>requestName</parameter></entry> 338 <entry><type>string</type></entry> 339 <entry>Name of X request or Extension</entry> 340 </row> 341 <row> 342 <entry><parameter>requestLength</parameter></entry> 343 <entry><type>uint16_t</type></entry> 344 <entry>Length of X request</entry> 345 </row> 346 <row> 347 <entry><parameter>sequenceNumber</parameter></entry> 348 <entry><type>uint32_t</type></entry> 349 <entry>Number of X request in in this connection</entry> 350 </row> 351 <row> 352 <entry><parameter>deviceid</parameter></entry> 353 <entry><type>int</type></entry> 354 <entry>The device's numerical ID</entry> 355 </row> 356 <row> 357 <entry><parameter>eventtype</parameter></entry> 358 <entry><type>int</type></entry> 359 <entry>Protocol event type</entry> 360 </row> 361 <row> 362 <entry><parameter>button, keycode, touchid</parameter></entry> 363 <entry><type>uint32_t</type></entry> 364 <entry>The button number, keycode or touch ID</entry> 365 </row> 366 <row> 367 <entry><parameter>flags</parameter></entry> 368 <entry><type>uint32_t</type></entry> 369 <entry>Miscellaneous event-specific server flags</entry> 370 </row> 371 <row> 372 <entry><parameter>nvalues</parameter></entry> 373 <entry><type>int8_t</type></entry> 374 <entry>Number of bits in <parameter>mask</parameter> and number of elements 375 in <parameter>values</parameter></entry> 376 </row> 377 <row> 378 <entry><parameter>mask</parameter></entry> 379 <entry><type>uint8_t*</type></entry> 380 <entry>Binary mask indicating which indices in <parameter>values</parameter> contain 381 valid data</entry> 382 </row> 383 <row> 384 <entry><parameter>values</parameter></entry> 385 <entry><type>double*</type></entry> 386 <entry>Valuator values. Values for indices for which the 387 <parameter>mask</parameter> is not set are undefined</entry> 388 </row> 389 </tbody> 390 </tgroup> 391 </table> 392 </para> 393 </sect1> 394 395 <sect1 id="examples"> 396 <title>Examples</title> 397 398 <example id="Counting_requests_by_request_name"> 399 <title>Counting requests by request name</title> 400 401 <para> 402 This script simply increments a counter for each different request 403 made, and when you exit the script (such as by hitting 404 <keycombo action='simul'><keycap>Control</keycap><keycap>C</keycap> 405 </keycombo>) prints the counts. 406 407 <programlisting> 408#!/usr/sbin/dtrace -s 409 410Xserver*:::request-start 411{ 412 @counts[copyinstr(arg0)] = count(); 413} 414 </programlisting> 415 416 The output from a short run may appear as: 417 <screen> 418 QueryPointer 1 419 CreatePixmap 2 420 FreePixmap 2 421 PutImage 2 422 ChangeGC 10 423 CopyArea 10 424 CreateGC 14 425 FreeGC 14 426 RENDER 28 427 SetClipRectangles 40 428 </screen> 429 </para> 430 431 <para> 432 This can be rewritten slightly to cache the string containing the name 433 of the request since it will be reused many times, instead of copying 434 it over and over from the kernel: 435 436 <programlisting> 437#!/usr/sbin/dtrace -s 438 439string Xrequest[uintptr_t]; 440 441Xserver*:::request-start 442/Xrequest[arg0] == ""/ 443{ 444 Xrequest[arg0] = copyinstr(arg0); 445} 446 447Xserver*:::request-start 448{ 449 @counts[Xrequest[arg0]] = count(); 450} 451 </programlisting> 452 </para> 453 </example> 454 455 <example id="Get_average_CPU_time_per_request"> 456 <title>Get average CPU time per request</title> 457 458 <para>This script records the CPU time used between the probes at 459 the start and end of each request and aggregates it per request type. 460 461 <programlisting> 462#!/usr/sbin/dtrace -s 463 464Xserver*:::request-start 465{ 466 reqstart = vtimestamp; 467} 468 469Xserver*:::request-done 470{ 471 @times[copyinstr(arg0)] = avg(vtimestamp - reqstart); 472} 473 </programlisting> 474 475 The output from a sample run might look like: 476 477 <screen> 478 ChangeGC 889 479 MapWindow 907 480 SetClipRectangles 1319 481 PolyPoint 1413 482 PolySegment 1434 483 PolyRectangle 1828 484 FreeCursor 1895 485 FreeGC 1950 486 CreateGC 2244 487 FreePixmap 2246 488 GetInputFocus 2249 489 TranslateCoords 8508 490 QueryTree 8846 491 GetGeometry 9948 492 CreatePixmap 12111 493 AllowEvents 14090 494 GrabServer 14791 495 MIT-SCREEN-SAVER 16747 496 ConfigureWindow 22917 497 SetInputFocus 28521 498 PutImage 240841 499 500 </screen> 501 </para> 502 </example> 503 504 <example id="Monitoring_clients_that_connect_and_disconnect"> 505 <title>Monitoring clients that connect and disconnect</title> 506 507 <para> 508 This script simply prints information about each client that 509 connects or disconnects from the server while it is running. 510 Since the provider is specified as <code>Xserver$1</code> instead 511 of <code>Xserver*</code> like previous examples, it won't monitor 512 all Xserver processes running on the machine, but instead expects 513 the process id of the X server to monitor to be specified as the 514 argument to the script. 515 516 <programlisting> 517#!/usr/sbin/dtrace -s 518 519Xserver$1:::client-connect 520{ 521 printf("** Client Connect: id %d\n", arg0); 522} 523 524Xserver$1:::client-auth 525{ 526 printf("** Client auth'ed: id %d => %s pid %d\n", 527 arg0, copyinstr(arg1), arg2); 528} 529 530Xserver$1:::client-disconnect 531{ 532 printf("** Client Disconnect: id %d\n", arg0); 533} 534 </programlisting> 535 536 A sample run: 537 538 <screen> 539<prompt>#</prompt> <userinput>./foo.d 5790</userinput> 540<computeroutput>dtrace: script './foo.d' matched 4 probes 541CPU ID FUNCTION:NAME 542 0 15774 CloseDownClient:client-disconnect ** Client Disconnect: id 65 543 544 2 15774 CloseDownClient:client-disconnect ** Client Disconnect: id 64 545 546 0 15773 EstablishNewConnections:client-connect ** Client Connect: id 64 547 548 0 15772 AuthAudit:client-auth ** Client auth'ed: id 64 => local host pid 2034 549 550 0 15773 EstablishNewConnections:client-connect ** Client Connect: id 65 551 552 0 15772 AuthAudit:client-auth ** Client auth'ed: id 65 => local host pid 2034 553 554 0 15774 CloseDownClient:client-disconnect ** Client Disconnect: id 64 555 </computeroutput> 556 </screen> 557 558 </para> 559 </example> 560 561 <example id="Monitoring_clients_creating_Pixmaps"> 562 <title>Monitoring clients creating Pixmaps</title> 563 564 <para> 565 This script can be used to determine which clients are creating 566 pixmaps in the X server, printing information about each client 567 as it connects to help trace it back to the program on the other 568 end of the X connection. 569 570 <programlisting> 571#!/usr/sbin/dtrace -qs 572 573string Xrequest[uintptr_t]; 574string Xrestype[uintptr_t]; 575 576Xserver$1:::request-start 577/Xrequest[arg0] == ""/ 578{ 579 Xrequest[arg0] = copyinstr(arg0); 580} 581 582Xserver$1:::resource-alloc 583/arg3 != 0 && Xrestype[arg3] == ""/ 584{ 585 Xrestype[arg3] = copyinstr(arg3); 586} 587 588 589Xserver$1:::request-start 590/Xrequest[arg0] == "X_CreatePixmap"/ 591{ 592 printf("-> %s: client %d\n", Xrequest[arg0], arg3); 593} 594 595Xserver$1:::request-done 596/Xrequest[arg0] == "X_CreatePixmap"/ 597{ 598 printf("<- %s: client %d\n", Xrequest[arg0], arg3); 599} 600 601Xserver$1:::resource-alloc 602/Xrestype[arg3] == "PIXMAP"/ 603{ 604 printf("** Pixmap alloc: %08x\n", arg0); 605} 606 607 608Xserver$1:::resource-free 609/Xrestype[arg3] == "PIXMAP"/ 610{ 611 printf("** Pixmap free: %08x\n", arg0); 612} 613 614Xserver$1:::client-connect 615{ 616 printf("** Client Connect: id %d\n", arg0); 617} 618 619Xserver$1:::client-auth 620{ 621 printf("** Client auth'ed: id %d => %s pid %d\n", 622 arg0, copyinstr(arg1), arg2); 623} 624 625Xserver$1:::client-disconnect 626{ 627 printf("** Client Disconnect: id %d\n", arg0); 628} 629 </programlisting> 630 631 Sample output from a run of this script: 632 <screen><computeroutput> 633** Client Connect: id 17 634** Client auth'ed: id 17 => local host pid 20273 635-> X_CreatePixmap: client 17 636** Pixmap alloc: 02200009 637<- X_CreatePixmap: client 17 638-> X_CreatePixmap: client 15 639** Pixmap alloc: 01e00180 640<- X_CreatePixmap: client 15 641-> X_CreatePixmap: client 15 642** Pixmap alloc: 01e00181 643<- X_CreatePixmap: client 15 644-> X_CreatePixmap: client 14 645** Pixmap alloc: 01c004c8 646<- X_CreatePixmap: client 14 647** Pixmap free: 02200009 648** Client Disconnect: id 17 649** Pixmap free: 01e00180 650** Pixmap free: 01e00181 651 </computeroutput></screen> 652 653 </para> 654 655 </example> 656 657 <example id="Input_API_monitoring_with_systemtap"> 658 <title>Input API monitoring with SystemTap</title> 659 660 <para> 661 This script can be used to monitor events submitted by drivers to 662 the server for enqueuing. Due to the integration of the input API 663 probes, some server-enqueued events will show up too. 664 <programlisting> 665 # Compile+run with 666 # stap -g xorg.stp /usr/bin/Xorg 667 # 668 669 670 function print_valuators:string(nvaluators:long, mask_in:long, valuators_in:long) %{ 671 int i; 672 unsigned char *mask = (unsigned char*)THIS->mask_in; 673 double *valuators = (double*)THIS->valuators_in; 674 char str[128] = {0}; 675 char *s = str; 676 677 #define BitIsSet(ptr, bit) (((unsigned char*)(ptr))[(bit)>>3] & (1 << ((bit) & 7))) 678 679 s += sprintf(s, "nval: %d ::", (int)THIS->nvaluators); 680 for (i = 0; i < THIS->nvaluators; i++) 681 { 682 s += sprintf(s, " %d: ", i); 683 if (BitIsSet(mask, i)) 684 s += sprintf(s, "%d", (int)valuators[i]); 685 } 686 687 sprintf(THIS->__retvalue, "%s", str); 688 %} 689 690 probe process(@1).mark("input__event") 691 { 692 deviceid = $arg1 693 type = $arg2 694 detail = $arg3 695 flags = $arg4 696 nvaluators = $arg5 697 698 str = print_valuators(nvaluators, $arg6, $arg7) 699 printf("Event: device %d type %d detail %d flags %#x %s\n", 700 deviceid, type, detail, flags, str); 701 } 702 </programlisting> 703 704 Sample output from a run of this script: 705 <screen><computeroutput> 706Event: device 13 type 4 detail 1 flags 0x0 nval: 0 :: 707Event: device 13 type 6 detail 0 flags 0xa nval: 1 :: 0: 1 708Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 2 1: -1 709Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 2 1: -1 710Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 4 1: -3 711Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 3 1: -3 712Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 3 1: -2 713Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 2 1: -2 714Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 2 1: -2 715Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 2 1: -2 716Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 1: -1 717Event: device 13 type 6 detail 0 flags 0xa nval: 2 :: 0: 1: -1 718Event: device 13 type 5 detail 1 flags 0x0 nval: 0 :: 719 </computeroutput></screen> 720 721 </para> 722 723 </example> 724 725 </sect1> 726 727</article> 728