The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/prof_machdep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1996 Bruce D. Evans.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: src/sys/i386/isa/prof_machdep.c,v 1.4.2.1 1999/09/05 08:13:19 peter Exp $
   27  */
   28 
   29 #ifdef GUPROF
   30 #include "opt_cpu.h"
   31 #include "opt_i586_guprof.h"
   32 #include "opt_perfmon.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/gmon.h>
   37 
   38 #include <machine/clock.h>
   39 #include <machine/perfmon.h>
   40 #include <machine/profile.h>
   41 #endif
   42 
   43 #ifdef PC98
   44 #include <pc98/pc98/pc98.h>
   45 #else
   46 #include <i386/isa/isa.h>
   47 #endif
   48 #include <i386/isa/timerreg.h>
   49 
   50 #ifdef GUPROF
   51 #define CPUTIME_CLOCK_UNINITIALIZED     0
   52 #define CPUTIME_CLOCK_I8254             1
   53 #define CPUTIME_CLOCK_I586_CTR          2
   54 #define CPUTIME_CLOCK_I586_PMC          3
   55 #define CPUTIME_CLOCK_I8254_SHIFT       7
   56 
   57 int     cputime_bias = 1;       /* initialize for locality of reference */
   58 
   59 static int      cputime_clock = CPUTIME_CLOCK_UNINITIALIZED;
   60 #ifdef I586_PMC_GUPROF
   61 static u_int    cputime_clock_pmc_conf = I586_PMC_GUPROF;
   62 static int      cputime_clock_pmc_init;
   63 static struct gmonparam saved_gmp;
   64 #endif
   65 #endif /* GUPROF */
   66 
   67 #ifdef __GNUC__
   68 asm("
   69 GM_STATE        =       0
   70 GMON_PROF_OFF   =       3
   71 
   72         .text
   73         .align  4,0x90
   74         .globl  __mcount
   75 __mcount:
   76         #
   77         # Check that we are profiling.  Do it early for speed.
   78         #
   79         cmpl    $GMON_PROF_OFF,__gmonparam+GM_STATE
   80         je      Lmcount_exit
   81         #
   82         # __mcount is the same as mcount except the caller hasn't changed
   83         # the stack except to call here, so the caller's raddr is above
   84         # our raddr.
   85         #
   86         movl    4(%esp),%edx
   87         jmp     Lgot_frompc
   88  
   89         .align  4,0x90
   90         .globl  mcount
   91 mcount:
   92         cmpl    $GMON_PROF_OFF,__gmonparam+GM_STATE
   93         je      Lmcount_exit
   94         #
   95         # The caller's stack frame has already been built, so %ebp is
   96         # the caller's frame pointer.  The caller's raddr is in the
   97         # caller's frame following the caller's caller's frame pointer.
   98         #
   99         movl    4(%ebp),%edx
  100 Lgot_frompc:
  101         #
  102         # Our raddr is the caller's pc.
  103         #
  104         movl    (%esp),%eax
  105 
  106         pushfl
  107         pushl   %eax
  108         pushl   %edx
  109         cli
  110         call    _mcount
  111         addl    $8,%esp
  112         popfl
  113 Lmcount_exit:
  114         ret
  115 ");
  116 #else /* !__GNUC__ */
  117 #error
  118 #endif /* __GNUC__ */
  119 
  120 #ifdef GUPROF
  121 /*
  122  * mexitcount saves the return register(s), loads selfpc and calls
  123  * mexitcount(selfpc) to do the work.  Someday it should be in a machine
  124  * dependent file together with cputime(), __mcount and mcount.  cputime()
  125  * can't just be put in machdep.c because it has to be compiled without -pg.
  126  */
  127 #ifdef __GNUC__
  128 asm("
  129         .text
  130 #
  131 # Dummy label to be seen when gprof -u hides mexitcount.
  132 #
  133         .align  4,0x90
  134         .globl  __mexitcount
  135 __mexitcount:
  136         nop
  137 
  138 GMON_PROF_HIRES =       4
  139 
  140         .align  4,0x90
  141         .globl  mexitcount
  142 mexitcount:
  143         cmpl    $GMON_PROF_HIRES,__gmonparam+GM_STATE
  144         jne     Lmexitcount_exit
  145         pushl   %edx
  146         pushl   %eax
  147         movl    8(%esp),%eax
  148         pushfl
  149         pushl   %eax
  150         cli
  151         call    _mexitcount
  152         addl    $4,%esp
  153         popfl
  154         popl    %eax
  155         popl    %edx
  156 Lmexitcount_exit:
  157         ret
  158 ");
  159 #else /* !__GNUC__ */
  160 #error
  161 #endif /* __GNUC__ */
  162 
  163 /*
  164  * Return the time elapsed since the last call.  The units are machine-
  165  * dependent.
  166  */
  167 int
  168 cputime()
  169 {
  170         u_int count;
  171         int delta;
  172 #ifdef I586_PMC_GUPROF
  173         u_quad_t event_count;
  174 #endif
  175         u_char high, low;
  176         static u_int prev_count;
  177 
  178 #if defined(I586_CPU) || defined(I686_CPU)
  179         if (cputime_clock == CPUTIME_CLOCK_I586_CTR) {
  180                 count = (u_int)rdtsc();
  181                 delta = (int)(count - prev_count);
  182                 prev_count = count;
  183                 return (delta);
  184         }
  185 #ifdef I586_PMC_GUPROF
  186         if (cputime_clock == CPUTIME_CLOCK_I586_PMC) {
  187                 /*
  188                  * XXX permon_read() should be inlined so that the
  189                  * perfmon module doesn't need to be compiled with
  190                  * profiling disabled and so that it is fast.
  191                  */
  192                 perfmon_read(0, &event_count);
  193 
  194                 count = (u_int)event_count;
  195                 delta = (int)(count - prev_count);
  196                 prev_count = count;
  197                 return (delta);
  198         }
  199 #endif /* I586_PMC_GUPROF */
  200 #endif /* I586_CPU or I686_CPU */
  201 
  202         /*
  203          * Read the current value of the 8254 timer counter 0.
  204          */
  205         outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
  206         low = inb(TIMER_CNTR0);
  207         high = inb(TIMER_CNTR0);
  208         count = ((high << 8) | low) << CPUTIME_CLOCK_I8254_SHIFT;
  209 
  210         /*
  211          * The timer counts down from TIMER_CNTR0_MAX to 0 and then resets.
  212          * While profiling is enabled, this routine is called at least twice
  213          * per timer reset (for mcounting and mexitcounting hardclock()),
  214          * so at most one reset has occurred since the last call, and one
  215          * has occurred iff the current count is larger than the previous
  216          * count.  This allows counter underflow to be detected faster
  217          * than in microtime().
  218          */
  219         delta = prev_count - count;
  220         prev_count = count;
  221         if ((int) delta <= 0)
  222                 return (delta + (timer0_max_count << CPUTIME_CLOCK_I8254_SHIFT));
  223         return (delta);
  224 }
  225 
  226 /*
  227  * The start and stop routines need not be here since we turn off profiling
  228  * before calling them.  They are here for convenience.
  229  */
  230 
  231 void
  232 startguprof(gp)
  233         struct gmonparam *gp;
  234 {
  235         if (cputime_clock == CPUTIME_CLOCK_UNINITIALIZED) {
  236                 cputime_clock = CPUTIME_CLOCK_I8254;
  237 #if defined(I586_CPU) || defined(I686_CPU)
  238                 if (i586_ctr_freq != 0)
  239                         cputime_clock = CPUTIME_CLOCK_I586_CTR;
  240 #endif
  241         }
  242         gp->profrate = timer_freq << CPUTIME_CLOCK_I8254_SHIFT;
  243 #if defined(I586_CPU) || defined(I686_CPU)
  244         if (cputime_clock == CPUTIME_CLOCK_I586_CTR)
  245                 gp->profrate = i586_ctr_freq;
  246 #ifdef I586_PMC_GUPROF
  247         else if (cputime_clock == CPUTIME_CLOCK_I586_PMC) {
  248                 if (perfmon_avail() &&
  249                     perfmon_setup(0, cputime_clock_pmc_conf) == 0) {
  250                         if (perfmon_start(0) != 0)
  251                                 perfmon_fini(0);
  252                         else {
  253                                 /* XXX 1 event == 1 us. */
  254                                 gp->profrate = 1000000;
  255 
  256                                 saved_gmp = *gp;
  257 
  258                                 /* Zap overheads.  They are invalid. */
  259                                 gp->cputime_overhead = 0;
  260                                 gp->mcount_overhead = 0;
  261                                 gp->mcount_post_overhead = 0;
  262                                 gp->mcount_pre_overhead = 0;
  263                                 gp->mexitcount_overhead = 0;
  264                                 gp->mexitcount_post_overhead = 0;
  265                                 gp->mexitcount_pre_overhead = 0;
  266 
  267                                 cputime_clock_pmc_init = TRUE;
  268                         }
  269                 }
  270         }
  271 #endif /* I586_PMC_GUPROF */
  272 #endif /* I586_CPU or I686_CPU */
  273         cputime_bias = 0;
  274         cputime();
  275 }
  276 
  277 void
  278 stopguprof(gp)
  279         struct gmonparam *gp;
  280 {
  281 #if defined(PERFMON) && defined(I586_PMC_GUPROF)
  282         if (cputime_clock_pmc_init) {
  283                 *gp = saved_gmp;
  284                 perfmon_fini(0);
  285                 cputime_clock_pmc_init = FALSE;
  286         }
  287 #endif
  288 }
  289 
  290 #else /* !GUPROF */
  291 #ifdef __GNUC__
  292 asm("
  293         .text
  294         .align  4,0x90
  295         .globl  mexitcount
  296 mexitcount:
  297         ret
  298 ");
  299 #else /* !__GNUC__ */
  300 #error
  301 #endif /* __GNUC__ */
  302 #endif /* GUPROF */

Cache object: 4aab5321627acda4d8dc1fa4a81c4b8e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.