home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / mach / doc / unpublished / monmanual.doc.Z / monmanual.doc
Encoding:
Text File  |  1992-08-18  |  24.2 KB  |  1,022 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.                        MACH KERNEL MONITOR
  13.           (WITH APPLICATIONS USING THE PIE ENVIRONMENT)
  14.  
  15.  
  16.  
  17.                          23 August 1990
  18.  
  19.  
  20.  
  21.                             Ted Lehr
  22.                            David Black
  23.  
  24.         Department of Electrical and Computer Engineering
  25.                  and School of Computer Science
  26.  
  27.                    Carnegie Mellon University
  28.  
  29.                        Pittsburgh PA 15213
  30.  
  31.  
  32.  
  33.                             ABSTRACT
  34.  
  35. Factors  such  as  the  decomposition of parallel programs affect
  36. their performance.  Measurements of parallel program  performance
  37. are improved if supported by information such as how programs are
  38. scheduled.  This manual  describes  how  to  use  MKM,  the  Mach
  39. (context-switch)  kernel  monitor.    Special  examples  of  data
  40. obtained  by  using  MKM  are  shown  via  the  PIE   performance
  41. monitoring environment.
  42.  
  43. 1 The Mach Kernel Monitor:  The Need to Monitor Context-Switching
  44.  
  45. The  performance of computations on parallel machines is affected
  46.  
  47. by user designed attributes such as the parallel decomposition of
  48.  
  49. the   computations  and  by  operating  system  actions  such  as
  50.  
  51. scheduling.    One  way  of  determining  how  computations   are
  52.  
  53. scheduled  is  to  detect  and time-stamp the context-switches of
  54.  
  55. their threads.
  56.  
  57.  
  58.  
  59. Certain Mach configurations (ie. those with  the  EXP  extension)
  60.  
  61. include the Mach Kernel Monitor (MKM) for monitoring kernel-level
  62.  
  63. behavior.  Currently, MKM only monitors context-switches of  user
  64.  
  65. selectable  threads.    It  permits  simultaneous  monitoring  of
  66.  
  67. independent computations so that multiple users  may  selectively
  68.  
  69. observe  as many computations as they desire, collecting only the
  70.  
  71. data about those they are interested in regardless of  what  else
  72.  
  73. is running on the system.
  74.  
  75.  
  76.  
  77. After discussing the implementation and system calls of MKM, this
  78.  
  79. manual gives some examples using the  PIE  (For  introduction  to
  80.  
  81. PIE,  see  "Visualizing Performance Debugging," in IEEE Computer,
  82.  
  83. October 1989, by Ted Lehr, et ala.).  performance monitoring  and
  84.  
  85. visualization  system.    Using  the PIE examples, the scheduling
  86.  
  87. information  collected  by  MKM  fulfills  the  double  role   of
  88.  
  89. visualizing   scheduling   performance  in  general  as  well  as
  90.  
  91. visualizing the influence of the scheduler on user algorithms.
  92.  
  93. 2 Implementation
  94.  
  95. An MKM monitor consists of:
  96.  
  97.    - A data structure  consisting  of  buffers  for  storing
  98.      information  about  detected  events  (in  the  current
  99.      implementation, a  monitor  can  detect  only  context-
  100.      switch events) and state information.
  101.  
  102.    - A list of threads that can be observed by the monitor.
  103.  
  104.    - Event  detection  sensors within Mach context-switching
  105.      code.
  106.  
  107.    - Entries within thread  data  structures  for  assigning
  108.      monitors to threads.
  109.  
  110. These data structures are operated upon by several monitor system
  111.  
  112. calls. Future versions of the monitor may contain data structures
  113.  
  114. for  monitoring  message  sends  and recieves or paging behavior.
  115.  
  116. Currently, the only calls recognized by a Mach kernel monitor are
  117.  
  118. ones concerned with detection of context-switches.
  119.  
  120.  
  121.  
  122. The  monitor_create  call  creates  a  monitor within the calling
  123.  
  124. task.  The call returns the monitor id and the size of the  event
  125.  
  126. buffer  in  the  kernel.   The user uses this size to allocate an
  127.  
  128. appropriatly sized user buffer  into  which  monitor_read  writes
  129.  
  130. context-switch data read from the kernel.  monitor_create returns
  131.  
  132. the monitor in a suspended  state.    monitor_resume  starts  the
  133.  
  134. monitor.    monitor_suspend  permits  the user to suspend (pause)
  135.  
  136. monitoring.      monitor_terminate    destroys    the    monitor.
  137.  
  138. monitor_read  reads the context-switch event data from the kernel
  139.  
  140. into a user supplied buffer.  monitor_read  calls  are  valid  as
  141.  
  142. long   as  its  argument  is  a  valid,  non-terminated  monitor.
  143.  
  144. thread_monitor enables individual threads for monitoring.  When a
  145.  
  146. thread  calls  thread_monitor  the associated monitor will detect
  147.  
  148. each time the thread context-switches.  thread_unmonitor disables
  149.  
  150. a thread from being monitored.
  151.  
  152.     #include <mach.h>
  153.     #include <mach/kernel_event.h>
  154.     #include <mach/monitor.h>
  155.  
  156.     main()
  157.     {
  158.         int                 buf_size;
  159.         monitor_t           my_monitor;
  160.         int                 j,num_events=MONITOR_MIG_BUFFER_S
  161.         kern_mon_buffer_t   kernel_events;
  162.  
  163.         buf_size = REQUESTED_SIZE;
  164.         monitor_create(task_self(), &this_monitor, &buf_size)
  165.         monitor_resume(this_monitor);
  166.         thread_monitor(this_monitor,UNIQUE_ID,thread_self());
  167.  
  168.         for(i = 0; i < 300; i++) sleep(1);
  169.  
  170.         thread_unmonitor(this_monitor, thread_self());
  171.         kernel_events = (kern_mon_buffer_t)
  172.           malloc(sizeof(kern_mon_data_t)*MONITOR_MIG_BUFFER_S
  173.         while (num_events == MONITOR_MIG_BUFFER_SIZE) {
  174.           monitor_read(this_monitor,kernel_events,&num_events
  175.           for (j = 0; j < num_events; j++) {
  176.             printf("%8.8x %8.8x %8.8x %8.8x %8.8x\n",
  177.                    kernel_events[j].third_element,
  178.                    kernel_events[j].second_element,
  179.                    kernel_events[j].hi_time,
  180.                    kernel_events[j].lo_time,
  181.                    kernel_events[j].first_element);
  182.             }
  183.         }
  184.         monitor_terminate(this_monitor);
  185.     }
  186.  
  187.          Figure 1:  Simple Example Program Using Monitor
  188.  
  189.  
  190.  
  191. Figure  1 shows an example program using monitoring.  The program
  192.  
  193. runs as a single thread.  The constant REQUESTED_SIZE is assigned
  194.  
  195. to  buf_size.   This is the requested size of the monitor buffers
  196.  
  197. allocated  inside  the  kernel.    After  creating  and  resuming
  198.  
  199. (starting)   the   monitor,   the   program  enables  itself  for
  200.  
  201. monitoring.  UNIQUE_ID is some constant that the  user  knows  is
  202.  
  203. unique  across  all  the  threads  in his program.  In this case,
  204.  
  205. since there is  only  one  thread,  the  value  of  UNIQUE_ID  is
  206.  
  207. arbitrary.
  208.  
  209.  
  210.  
  211. After  executing  a  sleep  statement  300  times,  the thread is
  212.  
  213. disabled  for  monitoring.    Then  a  user  routine  is  called,
  214.  
  215. print_events,  that  repeatedly calls monitor_read and prints the
  216.  
  217. events until the kernel_buffer is empty.    Note  that  the  user
  218.  
  219. buffer   is   only   MONITOR_MIG_BUFFER_SIZE  big  because  of  a
  220.  
  221. limitation on MIG buffer sizes.   Thus,  the  program  must  call
  222.  
  223. monitor_read  until  it returns less than MONITOR_MIG_BUFFER_SIZE
  224.  
  225. events.  When this occurs, the  program  knows  that  the  kernel
  226.  
  227. buffer  is  empty.    When  print_events  returns, the monitor is
  228.  
  229. terminated.  Note that in this program, monitor_suspend is  never
  230.  
  231. called.
  232.  
  233. The   context-switch  data  structure  saved  for  each  relevant
  234.  
  235. context-switch is:
  236.  
  237.  
  238.     typedef
  239.     struct  kernel_event {
  240.         unsigned    event_type;      /* type           */
  241.         unsigned    first_element;   /* stopped thread */
  242.         unsigned    second_element;  /* started thread */
  243.         unsigned    third_element;   /* flag and cpu   */
  244.         unsigned    hi_time;         /* hi time stamp  */
  245.         unsigned    lo_time;         /* lo time stamp  */
  246.     } kern_mon_data_t, *kern_mon_buffer_t;
  247.  
  248.  
  249.  
  250. The members of  the  structure  consist  of  the  type  of  event
  251.  
  252. (currently,   only   one   type  of  kernel  event  is  detected:
  253.  
  254. context-switches), the  stopped-thread  and  started-thread,  the
  255.  
  256. processor   on  which  the  threads  switched,  and  a  timestamp
  257.  
  258. separated into seconds and microseconds fields.  If  one  of  the
  259.  
  260. threads  is  unknown,  its id is set to -1.  The most significant
  261.  
  262. bit of the processor  field  is  1  if  that  event  overwrote  a
  263.  
  264. previous, unread event (ie. overflow).
  265.  
  266.   NOTE:
  267.      Currently, there is no internal protection guarding  against
  268.      requesting  too  much  memory  for buffers.  It is suggested
  269.      that no more than a half megabyte should be  requested.    A
  270.      rule  of  thumb  is that the greater the thread-to-processor
  271.      ratio, t, of one's computation,  the  more  context-switches
  272.      there  will  be.   Assume that when t>1.0, there will be ten
  273.      context-switches per second.    The  size  of  the  internal
  274.      buffers   then   depends   on   how  often  they  are  read.
  275.      monitor_read retrieves at most n = sizeof(kern_mon_data_t) x
  276.      MONITOR_MIG_BUFFER_IZE bytes each time the buffers are read.
  277.      Assume that once  one  monitor_read  is  made  to  read  the
  278.      buffers,  the  user  repeats  the call until the buffers are
  279.      empty.    In  such  case,  if  the  user  makes  bursts   of
  280.      monitor_read  calls once every d seconds, a good buffer size
  281.      would be 10d*n.
  282.  
  283. Figure 2 is schematic depicting a case in which  two  independent
  284.  
  285. non-communicating  Mach tasks have created separate MKM monitors.
  286.  
  287. Each monitor is represented by a port in its parent task.   Thus,
  288.  
  289. the  task  that creates a monitor obtains rights to the port that
  290.  
  291. represents the monitor; only tasks that possesses such rights can
  292.  
  293. access  the  monitor.  In our example, unless task B gives task A
  294.  
  295. rights to the monitor created by B, task A cannot access it.
  296.  
  297.  
  298.  
  299. Figure 2 also shows non-intersecting  sets  of  circular  buffers
  300.  
  301. allocated  to  each monitor for holding context-switch events.  A
  302.  
  303. buffer is assigned  to  each  processor  in  order  to  eliminate
  304.  
  305. contention  between  processors  for  buffers.    When  a  thread
  306.  
  307. context-switches, a software context-switch sensor detects which,
  308.  
  309. if any, monitor is tracking the thread and writes an event to the
  310.  
  311. appropriate buffer.  Eventually,  a  task  holding  rights  to  a
  312.  
  313. monitor  will  release  those  rights  and terminate the monitor.
  314.  
  315. This can be done either explicitly while the task  is  alive,  or
  316.  
  317. implicitly  when  the  task  terminates.    In  either  case, the
  318.  
  319. termination of  a  particular  monitor  is  accomplished  by  the
  320.  
  321. kernel.
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.          Figure 2:  General Kernel Monitor Architecture
  378. monitor_create
  379.  
  380. #include <mach.h>
  381. #include <mach/kernel_event.h>
  382.  
  383. kern_return_t monitor_create(owner_task, new_monitor, buffer_size
  384.         task_t          owner_task;
  385.         monitor_t       *new_monitor;   /* out */
  386.         int             *buffer_size;   /* out */
  387.  
  388.  
  389. Description
  390.  
  391. monitor_create creates a new monitor within the task specified by
  392.  
  393. owner_task argument. buffer_size is the requested size (in number
  394.  
  395. of   events)   for   the  monitor  kernel  buffer  used  to  hold
  396.  
  397. context-switch events.  When monitor_create returns,  buffer_size
  398.  
  399. is maximum number of events that kernel buffer may hold before it
  400.  
  401. overflows.  When the  monitor  is  created  send  rights  to  its
  402.  
  403. monitor  kernel  port are given to it and returned in new_monitor
  404.  
  405. to the caller.  The new monitor is returned in a suspended state.
  406.  
  407. To  get  a  new monitor to run, first monitor_create is called to
  408.  
  409. get the new monitor's identifier,(monitor).  Then  monitor_resume
  410.  
  411. is called to get the monitor to execute.
  412.  
  413. Arguments
  414.  
  415. owner_task      The task which is to contain the new monitor.
  416.  
  417.  
  418. new_monitor     The new monitor.
  419.  
  420.  
  421. buffer_size     The  size  (in  number  of events) of the monitor
  422.                 buffer in kernel.
  423.  
  424. Returns
  425.  
  426. KERN_SUCCESS    A new monitor has been created.
  427.  
  428.  
  429. KERN_INVALID_ARGUMENT
  430.                 parent_task is not a valid task.
  431.  
  432. Notes
  433.  
  434. Currently,  there  is  no  internal  protection  guarding against
  435.  
  436. requesting too much memory for buffers.  It is suggested that  no
  437.  
  438. more  than  a half megabyte should be requested.  A rule of thumb
  439.  
  440. is that the greater the thread-to-processor ratio,  t,  of  one's
  441.  
  442. computation,  the  more  context-switches  there will be.  Assume
  443.  
  444. that when t > 1.0, there will be ten context-switches per second.
  445.  
  446. The  size  of the internal buffers then depends on how often they
  447.  
  448. are read.  Each time the buffers are read, (see monitor_read)  at
  449.  
  450. most n = sizeof(kern_mon_data_t) x MONITOR_MIG_BUF_SIZE bytes are
  451.  
  452. retrieved.  Assume that once one monitor_read is made to read the
  453.  
  454. buffers,  the  user repeats the call until the buffers are empty.
  455.  
  456. In such case, if the user makes bursts of monitor_read calls once
  457.  
  458. every d seconds, a good buffer size would be 10d*n.
  459.  
  460. See Also
  461.  
  462. monitor_resume, monitor_terminate, monitor_suspend, monitor_read,
  463.  
  464. thread_monitor, thread_unmonitor, monitor
  465. monitor_resume
  466.  
  467. #include <mach.h>
  468. #include <mach/kernel_event.h>
  469.  
  470. kern_return_t monitor_resume(target_monitor)
  471.         monitor_t       target_monitor;
  472.  
  473.  
  474. Arguments
  475.  
  476. target_monitor  The monitor to be resumed.
  477.  
  478. Description
  479.  
  480. Sets the state  of  target_monitor  to  MONITOR_RUN.    When  the
  481.  
  482. monitor is in this state, it can detect events.
  483.  
  484. Returns
  485.  
  486. KERN_SUCCESS    The monitor has been resumed.
  487.  
  488.  
  489. KERN_FAILURE    The monitor state is MONITOR_SHUTDOWN.
  490.  
  491.  
  492. KERN_INVALID_ARGUMENT
  493.                 target_monitor is not a monitor or its port is no
  494.                 longer valid.
  495.  
  496. See Also
  497.  
  498. monitor_create, monitor_terminate, monitor_suspend, monitor_read,
  499.  
  500. thread_monitor, thread_unmonitor, monitor
  501. monitor_suspend
  502.  
  503. #include <mach.h>
  504. #include <mach/kernel_event.h>
  505.  
  506. kern_return_t monitor_suspend(target_monitor);
  507.         monitor_t       target_monitor;
  508.  
  509.  
  510. Arguments
  511.  
  512. target_monitor  The monitor to be suspended.
  513.  
  514. Description
  515.  
  516. Sets the state of target_monitor to MONITOR_PAUSE.  No events are
  517.  
  518. detected   when  the  monitor  is  in  this  state  although  any
  519.  
  520. previously detected events may be read by monitor_read.
  521.  
  522. Returns
  523.  
  524. KERN_SUCCESS    The monitor has been suspended.
  525.  
  526.  
  527. KERN_FAILURE    The monitor state is MONITOR_SHUTDOWN.
  528.  
  529.  
  530. KERN_INVALID_ARGUMENT
  531.                 target_monitor is not a monitor or its port is no
  532.                 longer valid.
  533.  
  534. See Also
  535.  
  536. monitor_create, monitor_terminate, monitor_resume,  monitor_read,
  537.  
  538. thread_monitor, thread_unmonitor, monitor
  539. monitor_terminate
  540.  
  541. #include <mach.h>
  542. #include <mach/kernel_event.h>
  543.  
  544. kern_return_t monitor_terminate(target_monitor)
  545.         monitor_t       target_monitor;
  546.  
  547.  
  548.  
  549. Description
  550.  
  551. monitor_terminate    destroys    the    monitor    specified   by
  552.  
  553. target_monitor.
  554.  
  555. Arguments
  556.  
  557. target_monitor  The monitor to be destroyed.
  558.  
  559. Returns
  560.  
  561. KERN_SUCCESS    The monitor has been destroyed.
  562.  
  563.  
  564. KERN_INVALID_ARGUMENT
  565.                 target_monitor  is  not  a  valid  monitor or its
  566.                 monitor port no longer exists.
  567.  
  568. See Also
  569.  
  570. monitor_create,  monitor_resume,  monitor_suspend,  monitor_read,
  571.  
  572. thread_monitor, thread_unmonitor, monitor
  573. monitor_read
  574.  
  575. #include <mach.h>
  576. #include <mach/kernel_event.h>
  577.  
  578. /* only current interpretion of kernel_event */
  579.  
  580. typedef
  581. struct  kernel_event {  /* unit kernel event */
  582.      unsigned   event_type;      /* the type of kernel event  */
  583.      unsigned   first_element;   /* the stopped thread        */
  584.      unsigned   second_element;  /* the started thread        */
  585.      unsigned   third_element;   /* flag and cpu number       */
  586.      unsigned   hi_time;         /* hi time stamp             */
  587.      unsigned   lo_time;         /* lo time stamp             */
  588. } kern_mon_event, *kern_mon_event_t, kern_mon_data_t,
  589.   *kern_mon_buffer_t;
  590.  
  591. kern_return_t monitor_read(target_monitor, buffer, events_read)
  592.         monitor_t               target_monitor;
  593.         kern_mon_buffer_t       buffer;
  594.         int                     events_read;
  595.  
  596.  
  597. Description
  598.  
  599. monitor_read  returns  events detected by target_monitor into the
  600.  
  601. buffer argument.  events_read is the number of  events  returned.
  602.  
  603. Each  call  to  monitor_read is limited to returning a maximum of
  604.  
  605. MONITOR_MIG_BUF_SIZE events, a limitation  of  MIG  buffer  size.
  606.  
  607. Buffer  data  is  aligned  around  event boundaries but it is the
  608.  
  609. responsibility of user code  to  properly  declare  and  allocate
  610.  
  611. buffer
  612.  
  613. Arguments
  614.  
  615. target_monitor  The monitor for which events are being read.
  616.  
  617.  
  618. buffer          The  user's  buffer into which the events will be
  619.                 written.
  620.  
  621.  
  622. events_read     The number of events read by the call.
  623.  
  624. Returns
  625.  
  626. KERN_SUCCESS    The monitor buffer was successfully read.
  627.  
  628.  
  629. KERN_INVALID_ARGUMENT
  630.                 target_monitor  is  not  a monitor or the monitor
  631.                 port is not valid.
  632.  
  633. Notes
  634.  
  635. A rule of thumb  is  that  the  greater  the  thread-to-processor
  636.  
  637. ratio,  t,  of one's computation, the more context-switches there
  638.  
  639. will  be.    Assume  that  when  t  >  1.0,  there  will  be  ten
  640.  
  641. context-switches  per  second.   In order to prevent the internal
  642.  
  643. buffers from overflowing, monitor_read should be called at  least
  644.  
  645. once  every  MONITOR_MIG_BUF_SIZE/10 seconds which in the current
  646.  
  647. implementation is about every 30  seconds.    Or,  if  each  time
  648.  
  649. monitor_read  is  called  it  is immediately followed by repeated
  650.  
  651. calls until the internal  buffers  are  empty,  these  bursts  of
  652.  
  653. repeated    calls    should    occur    every   every   B/(10   x
  654.  
  655. sizeof(kern_mon_data_t)) seconds where  B  is  the  size  of  the
  656.  
  657. internal buffer in bytes.
  658.  
  659. See Also
  660.  
  661. monitor_resume, monitor_terminate, monitor_suspend, monitor_read,
  662.  
  663. thread_monitor, thread_unmonitor, monitor
  664. thread_monitor
  665.  
  666. #include <mach.h>
  667. #include <mach/kernel_event.h>
  668.  
  669. kern_return_t thread_monitor(target_monitor,unique_id,target_thre
  670.         monitor_t               target_monitor;
  671.         int                     unique_id;
  672.         thread_t                target_thread;
  673.  
  674.  
  675. Arguments
  676.  
  677. target_monitor  The monitor which will observe target_thread
  678.  
  679.  
  680. unique_id       An id for thread identification outside kernel.
  681.  
  682.  
  683. target_thread   The thread which will be monitored.
  684.  
  685. Description
  686.  
  687. thread_monitor   enables   target_thread   for   monitoring    by
  688.  
  689. target_monitor  argument.   The caller is responsible for keeping
  690.  
  691. unique_id unique among all threads that target_monitor  observes.
  692.  
  693. target_thread can be observed by only one monitor at a time.
  694.  
  695. Returns
  696.  
  697. KERN_SUCCESS    The  thread  has  been  enabled to be observed by
  698.                 monitor.
  699.  
  700.  
  701. KERN_FAILURE    The monitor state is MONITOR_SHUTDOWN  or  thread
  702.                 is not active.
  703.  
  704.  
  705. KERN_INVALID_ARGUMENT
  706.                 target_monitor is not a monitor, target_thread is
  707.                 not a thread, or the monitor port is not valid.
  708.  
  709. See Also
  710.  
  711. monitor_create,         monitor_terminate,        monitor_resume,
  712.  
  713. monitor_suspend, monitor_read, thread_unmonitor, monitor
  714. thread_unmonitor
  715.  
  716. #include <mach.h>
  717. #include <mach/kernel_event.h>
  718.  
  719. kern_return_t thread_unmonitor(target_monitor, target_thread)
  720.         monitor_t               target_monitor;
  721.         thread_t                target_thread;
  722.  
  723.  
  724. Arguments
  725.  
  726. target_monitor  The monitor which observes target_thread
  727.  
  728.  
  729. target_thread   The thread which will be disabled.
  730.  
  731. Description
  732.  
  733. thread_unmonitor disables target_thread from being  monitored  by
  734.  
  735. target_monitor.
  736.  
  737. Returns
  738.  
  739. KERN_SUCCESS    The thread has been disabled from monitoring.
  740.  
  741.  
  742. KERN_INVALID_ARGUMENT
  743.                 target_monitor is a valid monitor,  target_thread
  744.                 is  not  a  thread,  or  the  monitor port is not
  745.                 valid.
  746.  
  747. See Also
  748.  
  749. monitor_create,        monitor_terminate,         monitor_resume,
  750.  
  751. monitor_suspend, monitor_read, thread_monitor, monitor
  752.  
  753. 3 Examples of Context-Switch Monitoring
  754.  
  755. Before  giving  examples  of  some  results achieved using MKM, a
  756.  
  757. brief description of the  PIE  environment  is  necessary.    The
  758.  
  759. Parallel  Programming  and Instrumentation Environment (PIE) is a
  760.  
  761. software development environment for debugging performance  using
  762.  
  763. special   development   and   data   analysis  tools.  PIE  is  a
  764.  
  765. "computational   laboratory"   in   which   programmers    design
  766.  
  767. experiments to evaluate the real behavior of computations.
  768.  
  769.  
  770.  
  771. PIE  is  a  portable system whose basic platform is a workstation
  772.  
  773. running the X Window System.  It supports several sequential  and
  774.  
  775. parallel  languages.  Currently, PIE's monitoring instrumentation
  776.  
  777. runs on Vax and Sun  workstations,  Encore  Multimax,  and  Warp.
  778.  
  779. Although  PIE can be ported to other Unix-like operating systems,
  780.  
  781. its current form is implemented on  top  of  the  Mach  operating
  782.  
  783. system.
  784.  
  785.  
  786.  
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.                  Figure 3:  Organization of PIE
  810.  
  811.  
  812.  
  813. Figure  3  depicts  the general organization of PIE.  This manual
  814.  
  815. only  presents  the  visualization  component  of   PIE,   called
  816.  
  817. PIEscope,  because  of  its relevance in showing context-switches
  818.  
  819. detected by MKM.  The context-switches shown in the examples were
  820.  
  821. detected by MKM and retrieved by PIE using the monitor_read call.
  822.  
  823. The begin and end of  the  threads  were  recorded  using  simple
  824.  
  825. methods in PIE.
  826.  
  827.  
  828.  
  829. 3.1 Interpreting the PIE Figures
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857. Figure 4:  Execution and Cpu Views of Incomplete Gang Scheduling
  858.  
  859. The two views in Figure 4 are examples of PIE's principle formats
  860.  
  861. for representing performance information.  These particular views
  862.  
  863. show  the  execution of a matrix multiplication computation.  The
  864.  
  865. top view is an example of the execution barscope view; the bottom
  866.  
  867. view  is  an  example of the cpu barscope view.  In the execution
  868.  
  869. barscope view, time is measured in microseconds on the horizontal
  870.  
  871. while the threads of the computation are ordered on the vertical.
  872.  
  873. This particular view shows the part of the execution  from  about
  874.  
  875. 0.0  to  36.7  seconds.  The time of execution for each thread is
  876.  
  877. depicted by the dark rectangles.
  878.  
  879.  
  880.  
  881. The cpu barscope shows thread-to-processor assignments during the
  882.  
  883. execution  of  a  computation.  As in the execution barscope, the
  884.  
  885. cpu barscope displays time in microseconds on the horizontal.  On
  886.  
  887. the vertical, however, the processors used by the computation are
  888.  
  889. ordered and arbitrarily numbered on the vertical.  Opposite  each
  890.  
  891. cpu  are  alternating  sets of patterned rectangles.  A patterned
  892.  
  893. rectangle represents an identifiable  executing  thread  while  a
  894.  
  895. white   rectangle  is  a  period  when  none  of  the  respective
  896.  
  897. computation's threads are running on the  associated  cpu.    PIE
  898.  
  899. allows  a user to arbitrarily assign unique colors or patterns to
  900.  
  901. as many threads per cpu-view as he wishes.
  902.  
  903.  
  904.  
  905. 3.2 Gang Scheduling
  906.  
  907. Sometimes, the number of threads is greater than  the  number  of
  908.  
  909. processors.    The  two  views  of Figure 4 are execution and cpu
  910.  
  911. barscopes of an entire matrix multiply computation for which five
  912.  
  913. processors  were allocated.  In each view, a pair of time cursors
  914.  
  915. delimit approximately the same period in time, one in  which  the
  916.  
  917. collector,  again represented by dark diagonally slashed bars, is
  918.  
  919. running on cpu 12.
  920.  
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936.  
  937.  
  938.  
  939.  
  940.  
  941.  
  942.  
  943.  
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951. Figure 5:  The Execution of Two Threads on Three Kernels:  XF29, 
  952.  
  953. 3.3 Comparing Schedulers for a Uniprocessor
  954.  
  955. PIE and MKM can also monitor sequential computations.  The  three
  956.  
  957. views  in  Figure  5  are  execution  barscopes that were used to
  958.  
  959. evaluate the Mach scheduler.    Each  view  shows  the  same  two
  960.  
  961. threads  time-sharing  one  processor.    As  one  moves down the
  962.  
  963. Figure, the views represent newer versions of Mach.  Because  the
  964.  
  965. views  depict  uniprocessor  executions, cutting a vertical swath
  966.  
  967. through a view at any  point  slices  through  only  one  running
  968.  
  969. thread ... only a single black rectangle.
  970.  
  971.  
  972.  
  973. The  top  view  of  Figure 5 depicts an execution on the old XF29
  974.  
  975. kernel.  The next view depicts the same computation on  the  less
  976.  
  977. primitive  CS5a kernel.  The X96 kernel in the bottom view is the
  978.  
  979. most advanced.
  980.  
  981.  
  982.  
  983. The views show that the two threads do not behave identically  on
  984.  
  985. three  kernels.    XF29  uses  a simple scheduling algorithm that
  986.  
  987. switches  the  threads  roughly  every  100  milliseconds.    The
  988.  
  989. schedulers  of the latter two kernels use a progressive algorithm
  990.  
  991. which attempt to increase the length of the time slices allocated
  992.  
  993. to  each  thread.    Despite  good  intentions,  the  progressive
  994.  
  995. algorithm of CS5a fails to  dramatically  reduce  the  number  of
  996.  
  997. context-switches   because   it  permits  threads  to  switch  to
  998.  
  999. themselves  repeatedly  as  indicated  by  the  preponderance  of
  1000.  
  1001. "squiggles."    X96 corrects this drawback by preempting a thread
  1002.  
  1003. from switching to itself.
  1004.  
  1005.                         Table of Contents
  1006.    1 The  Mach  Kernel  Monitor:    The  Need   to   Monitor    1
  1007.      Context-Switching
  1008.    2 Implementation                                             1
  1009.    3 Examples of Context-Switch Monitoring                     11
  1010.        3.1 Interpreting the PIE Figures                        11
  1011.        3.2 Gang Scheduling                                     11
  1012.        3.3 Comparing Schedulers for a Uniprocessor             12
  1013.  
  1014.                          List of Figures
  1015.    Figure 1:   Simple Example Program Using Monitor             1
  1016.    Figure 2:   General Kernel Monitor Architecture              3
  1017.    Figure 3:   Organization of PIE                             11
  1018.    Figure 4:   Execution  and  Cpu  Views of Incomplete Gang   11
  1019.                Scheduling
  1020.    Figure 5:   The  Execution  of  Two  Threads   on   Three   11
  1021.                Kernels:  XF29, CS5a, X96
  1022.