• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
alrm_handler(int sig)48 static void alrm_handler(int sig)
49 {
50 	(void) sig;
51 	profil_done = 1;
52 }
53 
get_pc(void)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 
test_profil(void)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 
main(int ac,char * av[])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() */
main(void)132 int main(void)
133 {
134         tst_brkm(TCONF, NULL, "system doesn't have profil() support");
135 }
136 #endif
137