Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / trace_capture / tc_host.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdint.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <sys/ioctl.h>
42#include "../include/scif.h"
43#include "trace_capture.h"
44
45#define BARRIER(epd, string) { \
46 printf("%s\n", string); \
47 if ((err = scif_send(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \
48 printf("scif_send failed with err %d\n", errno); \
49 fflush(stdout); \
50 goto close; \
51 } \
52 if ((err = scif_recv(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \
53 printf("scif_recv failed with err %d\n", errno); \
54 fflush(stdout); \
55 goto close; \
56 } \
57}
58
59#if 0
60// These are common to the Host App
61// and the MIC driver Trace Capture Feature
62// COMMON DEFINES START HERE
63enum TRACE_COMMAND {
64 TRACE_NOP = 100,
65 TRACE_DATA,
66 TRACE_HOST_READY,
67 TRACE_DONE,
68 TRACE_ERROR,
69 TRACE_PRINT,
70 TRACE_GET_FILE,
71 TRACE_PAGE_READY,
72 TRACE_REG_COMPLETE,
73 TRACE_MEM_COMPLETE,
74 TRACE_COMPLETE
75};
76
77#define TRACE_STATUS_OFFSET 8
78#define TRACE_SIZE_OFFSET 12
79
80// Enable/Disable Memory Test.
81// This MUST be enabled simultaneously on Host App as well.
82#define MIC_TRACE_CAPTURE_MEMORY_TEST 0
83
84#if MIC_TRACE_CAPTURE_MEMORY_TEST
85#define TRACE_CHECKSUM_OFFSET 16
86#endif
87
88#define TRACE_TRIGGER_OFFSET 20
89#define TRACE_DATA_OFFSET 4096
90
91// Types of Triggers - Refer to uOS Trace Capture Wiki for Usage
92// Generic counter
93#define TRACE_HOST_GENERIC_COUNTER 0x1
94// Async Flip counter
95#define TRACE_HOST_FRAME_COUNTER 0x2
96// COMMON DEFINES END HERE
97#endif
98
99// End points for SCIF
100//static scif_epd_t mictc_epd_cmd;
101static scif_epd_t mictc_epd_data;
102
103// SCIF ports - temp hack; move to scif.h
104#define MICTC_SCIF_PORT_DATA 300
105
106static volatile uint64_t *g_traceBufferStatusOffset = NULL;
107static volatile uint64_t *g_traceBufferSizeOffset = NULL;
108static volatile uint32_t *g_traceBufferDataOffset = NULL;
109static volatile uint32_t *g_traceBufferTriggerOffset = NULL;
110
111// This is an array of trigger numbers. The value TRACE_EOL is ignored.
112static uint32_t g_traceTriggers[TRACE_TRIGGER_MAX];
113
114static struct scif_portID portID_data;
115static scif_epd_t mictc_newepd;
116
117static void *g_mictc_buffer_base;
118static void *g_mictc_buffer_offset_xml;
119static off_t g_mictc_buffer_offset_mem;
120
121FILE *fp;
122
123static
124int open_scif_channels(void)
125{
126 int err;
127 struct pollfd spollfd;
128 int control_msg = 0;
129 long scif_offset_dst;
130 int timeout = 0;
131 int page_count = 0;
132 int i;
133
134 if ((err = posix_memalign(&g_mictc_buffer_base, 0x1000, MICTC_MEM_BUFFER_SIZE))) {
135 fprintf(stderr, "posix_memalign failed failed with %d\n", err);
136 return 0;
137 }
138 // Data channel
139 if ((mictc_epd_data = scif_open()) == SCIF_OPEN_FAILED) {
140 fprintf(stderr, "scif_open failed with ENOMEM\n", errno);
141 return 0;
142 }
143
144 if (scif_bind(mictc_epd_data, MICTC_SCIF_PORT_DATA) == -1) {
145 fprintf(stderr, "scif_bind failed with error %d\n", errno);
146 return 0;
147 }
148
149 portID_data.node = 1;
150 portID_data.port = MICTC_SCIF_PORT_DATA;
151
152 if (scif_listen(mictc_epd_data, 1) == -1) {
153 fprintf(stderr, "scif_listen failed with error %d\n", errno);
154 return 0;
155 }
156
157 while (1) {
158 printf("scif_accept in poll mode until a connect request is found\n");
159 err = 1;
160 while (err) {
161 spollfd.fd = scif_get_fd(mictc_epd_data);
162 spollfd.events = POLLIN;
163 spollfd.revents = 0;
164 if ((err = poll(&spollfd, 1, -1)) < 0) {
165 printf("poll failed with err %d\n", errno);
166 }
167 if (((err = scif_accept(mictc_epd_data, &portID_data, &mictc_newepd, 0)) < 0) && (errno != EAGAIN)) {
168 printf("scif_accept failed with err %d\n", errno);
169 return 0;
170 }
171 }
172
173 printf("scif_accept from port %d complete\n", portID_data.port);
174
175 if ((g_mictc_buffer_offset_mem = scif_register(mictc_newepd, g_mictc_buffer_base, MICTC_MEM_BUFFER_SIZE, 0, // suggested_offset,
176 SCIF_PROT_READ | SCIF_PROT_WRITE, 0)) < 0) {
177 fprintf(stderr, "scif_register failed with err %d\n", errno);
178 return 0;
179 }
180
181 printf("After scif_register, g_mictc_buffer_offset_mem = %llx\n",
182 (unsigned long long)g_mictc_buffer_offset_mem);
183 fflush(stdout);
184
185 // printf("Before scif_send\n");
186 // fflush(stdout);
187
188 BARRIER(mictc_newepd, "before barrier");
189
190 if ((err =
191 scif_send(mictc_newepd, &g_mictc_buffer_offset_mem, sizeof(g_mictc_buffer_offset_mem),
192 SCIF_SEND_BLOCK)) <= 0) {
193 printf("scif_send failed with err %d\n", errno);
194 fflush(stdout);
195 goto close;
196 }
197 // BARRIER(mictc_newepd, "scif_send");
198
199 // printf("scif_offset = %lx\n", scif_offset);
200 // fflush(stdout);
201
202 printf("Before scif_recv\n");
203 fflush(stdout);
204
205 if ((err = scif_recv(mictc_newepd, &scif_offset_dst, sizeof(scif_offset_dst), SCIF_RECV_BLOCK)) <= 0) {
206 printf("scif_recv failed with err %d\n", errno);
207 fflush(stdout);
208 goto close;
209 }
210 printf("scif_offset_dst = %lx\n", scif_offset_dst);
211
212 printf("Before scif_mmap\n");
213
214 if ((g_mictc_buffer_offset_xml = scif_mmap(0, // physical address
215 MICTC_XML_BUFFER_SIZE, // length
216 SCIF_PROT_READ | SCIF_PROT_WRITE, // protection
217 0, // flags
218 mictc_newepd, // endpoint
219 scif_offset_dst) // offset
220 ) == (void *)-1) {
221 fprintf(stderr, "scif_mmap failed with err %d\n", errno);
222 return 0;
223 }
224
225 g_traceBufferStatusOffset = (uint64_t *) (g_mictc_buffer_offset_xml + TRACE_STATUS_OFFSET);
226 g_traceBufferSizeOffset = (uint64_t *) (g_mictc_buffer_offset_xml + TRACE_SIZE_OFFSET);
227 g_traceBufferDataOffset = (uint32_t *) (g_mictc_buffer_offset_xml + TRACE_DATA_OFFSET);
228 g_traceBufferTriggerOffset = (uint32_t *) (g_mictc_buffer_offset_xml + TRACE_TRIGGER_OFFSET);
229
230 for (i = 0; i < TRACE_TRIGGER_MAX; i++) {
231 *g_traceBufferTriggerOffset = g_traceTriggers[i];
232 g_traceBufferTriggerOffset++;
233 }
234
235 *g_traceBufferStatusOffset = TRACE_HOST_READY;
236
237 printf("Before fopen\n");
238
239 if ((fp = fopen("cpu.xml", "w")) == NULL) {
240 fprintf(stderr, "Cannot open file cpu.xml.\n");
241 }
242
243 printf("Waiting for TRACE_REG_COMPLETE or TRACE_ABORTED");
244 fflush(stdout);
245
246 while (*g_traceBufferStatusOffset != TRACE_REG_COMPLETE) {
247 printf(".");
248 fflush(stdout);
249 sleep(1);
250 if (timeout++ >= 200) {
251 // Hmmm, something is hung up. Save everything in the buffer ignoring length.
252 printf("Punt!\n");
253 fprintf(fp, "%s\n", (char *)g_traceBufferDataOffset);
254 *g_traceBufferStatusOffset = TRACE_GET_FILE;
255 fclose(fp);
256 sleep(5);
257 goto close; // and quit
258 }
259 // If this happens the current trigger was not one we want -- reset and wait.
260 if (*g_traceBufferStatusOffset == TRACE_ABORTED) {
261 printf("\nAborted trace\n");
262 fflush(stdout);
263 goto close2;
264 }
265 }
266 printf("\n");
267
268 {
269 int j;
270
271 asm volatile ("lfence" ::: "memory");
272 j = *g_traceBufferSizeOffset;
273 fprintf(fp, "%*s\n", j, (char *)g_traceBufferDataOffset);
274 }
275 *g_traceBufferStatusOffset = TRACE_GET_FILE;
276 fclose(fp);
277 sleep(5);
278
279 // Memory dump
280
281 if ((fp = fopen("mem.dat", "w")) == NULL) {
282 fprintf(stderr, "Cannot open file mem.dat.\n");
283 }
284
285 printf("Waiting for memory pages\n");
286 fflush(stdout);
287
288 timeout = 0;
289
290 {
291 long i = 0;
292
293 while (*g_traceBufferStatusOffset != TRACE_MEM_COMPLETE) {
294 //printf("status %d\n", *g_traceBufferStatusOffset);
295
296 if (*g_traceBufferStatusOffset == TRACE_PAGE_READY) {
297 printf(" %ld", i++);
298 fflush(stdout);
299 asm volatile ("lfence" ::: "memory");
300
301 if (fwrite(g_mictc_buffer_base, *g_traceBufferSizeOffset, 1, fp) != 1) {
302 fprintf(stderr, "\nCannot write file mem.dat. error = %d\n", ferror(fp));
303 return 0;
304 }
305 *g_traceBufferStatusOffset = TRACE_HOST_READY; // Get next page
306 timeout = 0;
307 } else {
308 // printf(".");
309 // fflush(stdout);
310 usleep(10000);
311
312 if (timeout++ >= 2000) {
313 // Hmmm, something is hung up. Just close and quit.
314 printf("Punt!\n");
315 fclose(fp);
316 sleep(5);
317 goto close; // and quit
318 }
319 }
320 }
321 }
322 close1:
323 printf("\nClosing memory dump file.\n");
324 fflush(stdout);
325 fclose(fp);
326 *g_traceBufferStatusOffset = TRACE_COMPLETE; // File is closed; tell driver we are done.
327 printf("Done.\n");
328 fflush(stdout);
329 close2:
330 sleep(2);
331 scif_munmap(g_mictc_buffer_offset_xml, MICTC_XML_BUFFER_SIZE);
332 scif_unregister(mictc_newepd, (off_t) g_mictc_buffer_base, MICTC_MEM_BUFFER_SIZE);
333 scif_close(mictc_newepd);
334 } // while (1)
335 close:
336 scif_munmap(g_mictc_buffer_offset_xml, MICTC_XML_BUFFER_SIZE);
337 scif_close(mictc_newepd);
338 scif_close(mictc_epd_data);
339 free(g_mictc_buffer_base);
340 return 1;
341}
342
343int main(int argc, char *argv[])
344{
345 int i;
346
347 for (i = 0; i < TRACE_TRIGGER_MAX; i++) {
348 g_traceTriggers[i] = TRACE_EOL;
349 }
350
351 if (argc >= 2) {
352 for (i = 1; i < argc; i++) {
353 if (i > TRACE_TRIGGER_MAX) break;
354
355 g_traceTriggers[i - 1] = atoi(argv[i]);
356 printf("Trigger %d\n", g_traceTriggers[i - 1]);
357 }
358 } else {
359 printf("No triggers -- accept everything\n");
360 }
361
362 if (!open_scif_channels())
363 exit(1);
364
365 exit(0);
366}