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