Home | History | Annotate | Download | only in profil
      1 /*
      2  *   Copyright (c) International Business Machines  Corp., 2002
      3  *   Copyright (C) 2014 Linux Test Project, Inc.
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  */
     15 /*
     16  * ALGORITHM
     17  *	Set up a profiling buffer, turn profiling on, set a timer for
     18  *	cpu time, spin the pc and wait for timer to go off.
     19  *	The profiling buffer should contain some info, highly concentrated.
     20  *	We just do a "looks reasonable" check.
     21  */
     22 
     23 #include <stdio.h>
     24 #include <signal.h>
     25 #include <unistd.h>
     26 #include <errno.h>
     27 #include <sys/types.h>
     28 #include "test.h"
     29 #include "safe_macros.h"
     30 #include "config.h"
     31 
     32 char *TCID = "profil01";
     33 
     34 #if HAVE_PROFIL
     35 
     36 #define PROFIL_TIME 5
     37 
     38 /* Should be large enough to hold data for test_profil() .text,
     39  * on x86_64 this is ~600 bytes, so 16k should enough for all arches.
     40  * We will monitor 16k on each side around current pc value,
     41  * just in case compiler put call to get_pc() below "data shuffling" code */
     42 #define PROFIL_BUFLEN (32*1024)
     43 
     44 int TST_TOTAL = 1;
     45 
     46 static volatile sig_atomic_t profil_done;
     47 
     48 static void alrm_handler(int sig)
     49 {
     50 	(void) sig;
     51 	profil_done = 1;
     52 }
     53 
     54 static void __attribute__ ((noinline)) *get_pc(void)
     55 {
     56 #if defined(__s390__) && __WORDSIZE == 32
     57 	/* taken from glibc,
     58 	 *   sysdeps/unix/sysv/linux/s390/s390-32/profil-counter.h
     59 	 * 31-bit s390 pointers don't use the 32th bit, however integers do,
     60 	 * so wrap the value around at 31 bits */
     61 	return (void *)
     62 		((unsigned long) __builtin_return_address(0) & 0x7fffffffUL);
     63 #else
     64 	return __builtin_return_address(0);
     65 #endif
     66 }
     67 
     68 static void test_profil(void)
     69 {
     70 	unsigned short buf[PROFIL_BUFLEN] = { 0 };
     71 	volatile int data[8] = { 0 };
     72 	size_t offset = (size_t) get_pc() - PROFIL_BUFLEN/2, count = 0;
     73 	int ret, i;
     74 
     75 	/* reset for test looping */
     76 	profil_done = 0;
     77 
     78 	/* profil_count in glibc calculates offset as
     79 	 *   i = (pc - pc_offset - (void *) 0) / 2
     80 	 *   i = i * pc_scale / 65536
     81 	 * set scale to 2*65536 to have 1:1 mapping for $pc */
     82 	ret = profil(buf, sizeof(buf), offset, 2*65536);
     83 	if (ret)
     84 		tst_brkm(TBROK, NULL, "profil returned: %d\n", ret);
     85 
     86 	signal(SIGALRM, alrm_handler);
     87 	alarm(PROFIL_TIME);
     88 
     89 	while (!profil_done) {
     90 		if (data[0])
     91 			data[0] = -data[7];
     92 		else
     93 			data[1] = data[0] / 2;
     94 		if (data[2])
     95 			data[2] = data[1] * 2;
     96 		else
     97 			data[3] = data[2] + data[0];
     98 		if (data[4])
     99 			data[4] = data[3] - data[1];
    100 		else
    101 			data[5] = data[4] * data[2];
    102 		if (data[6])
    103 			data[6] = data[5] + data[3];
    104 		else
    105 			data[7] = data[6] - data[4];
    106 	}
    107 
    108 	for (i = 0; i < PROFIL_BUFLEN; i++)
    109 		if (buf[i]) {
    110 			tst_resm(TINFO, "buf[0x%04x]=%d", i, buf[i]);
    111 			count += buf[i];
    112 		}
    113 
    114 	if (count > 0)
    115 		tst_resm(TPASS, "profil recorded some data");
    116 	else
    117 		tst_resm(TFAIL, "profil failed to record anything");
    118 }
    119 
    120 int main(int ac, char *av[])
    121 {
    122 	int lc;
    123 
    124 	tst_parse_opts(ac, av, NULL, NULL);
    125 
    126 	for (lc = 0; TEST_LOOPING(lc); lc++)
    127 		test_profil();
    128 
    129 	tst_exit();
    130 }
    131 #else /* systems without profil() */
    132 int main(void)
    133 {
    134         tst_brkm(TCONF, NULL, "system doesn't have profil() support");
    135 }
    136 #endif
    137