1/* cilkview.h                  -*-C++-*-
2 *
3 *************************************************************************
4 *
5 * @copyright
6 * Copyright (C) 2010-2013, Intel Corporation
7 * All rights reserved.
8 *
9 * @copyright
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 *   * Redistributions of source code must retain the above copyright
15 *     notice, this list of conditions and the following disclaimer.
16 *   * Redistributions in binary form must reproduce the above copyright
17 *     notice, this list of conditions and the following disclaimer in
18 *     the documentation and/or other materials provided with the
19 *     distribution.
20 *   * Neither the name of Intel Corporation nor the names of its
21 *     contributors may be used to endorse or promote products derived
22 *     from this software without specific prior written permission.
23 *
24 * @copyright
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
35 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 **************************************************************************/
39
40#ifndef INCLUDED_CILKVIEW_H
41#define INCLUDED_CILKVIEW_H
42
43#include <cilk/cilk_api.h>
44
45#ifdef _WIN32
46#   ifndef _WINBASE_
47__CILKRTS_BEGIN_EXTERN_C
48unsigned long __stdcall GetTickCount();
49__CILKRTS_END_EXTERN_C
50#   endif
51#endif  // _WIN32
52
53#if defined __unix__ || defined __APPLE__ || defined __VXWORKS__
54#   include <sys/time.h>
55#endif  // defined __unix__ || defined __APPLE__
56
57/// @brief Return the system clock with millisecond resolution
58///
59/// This function returns a long integer representing the number of
60/// milliseconds since an arbitrary starting point, e.g., since the system was
61/// started or since the Unix Epoch.  The result is meaningless by itself, but
62/// the difference between two sequential calls to __cilkview_getticks()
63/// represents the time interval that elapsed between them (in ms).
64static inline unsigned long long __cilkview_getticks()
65{
66#if __INTEL_COMPILER > 1200
67    // When inlined, prevent code motion around this call
68    __notify_zc_intrinsic((void*) "test_getticks_start", 0);
69#endif
70
71#ifdef _WIN32
72    // Return milliseconds elapsed since the system started
73    return GetTickCount();
74#elif defined(__unix__) || defined(__APPLE__) || defined __VXWORKS__
75    // Return milliseconds elapsed since the Unix Epoch
76    // (1-Jan-1970 00:00:00.000 UTC)
77    struct timeval t;
78    gettimeofday(&t, 0);
79    return t.tv_sec * 1000ULL + t.tv_usec / 1000;
80#else
81#   error test_getticks() not implemented for this OS
82#endif
83
84#if __INTEL_COMPILER > 1200
85    // When inlined, prevent code motion around this call
86    __notify_zc_intrinsic((void*) "test_getticks_end", 0);
87#endif
88}
89
90typedef struct
91{
92    unsigned int        size;           // Size of structure in bytes
93    unsigned int        status;         // 1 = success, 0 = failure
94    unsigned long long  time;           // Time in milliseconds
95    unsigned long long  work;
96    unsigned long long  span;
97    unsigned long long  burdened_span;
98    unsigned long long  spawns;
99    unsigned long long  syncs;
100    unsigned long long  strands;
101    unsigned long long  atomic_ins;
102    unsigned long long  frames;
103} cilkview_data_t;
104
105typedef struct
106{
107    cilkview_data_t *start;     // Values at start of interval
108    cilkview_data_t *end;       // Values at end of interval
109    const char *label;          // Name for this interval
110    unsigned int flags;         // What to do - see flags below
111} cilkview_report_t;
112
113// What __cilkview_report should do.  The flags can be ORed together
114enum
115{
116    CV_REPORT_WRITE_TO_LOG = 1,     // Write parallelism report to the log (xml or text)
117    CV_REPORT_WRITE_TO_RESULTS = 2  // Write parallelism data to results file
118};
119
120#ifndef CILKVIEW_NO_REPORT
121static void __cilkview_do_report(cilkview_data_t *start,
122                          cilkview_data_t *end,
123                          const char *label,
124                          unsigned int flags);
125#endif /* CILKVIEW_NO_REPORT */
126
127/*
128 * Metacall data
129 *
130 * A metacall is a way to pass data to a function implemented by a tool.
131 * Metacalls are always instrumented when the tool is loaded.
132 */
133
134// Tool code for Cilkview
135#define METACALL_TOOL_CILKVIEW 2
136
137// Metacall codes implemented by Cilkview
138enum
139{
140    CV_METACALL_PUTS,
141    CV_METACALL_QUERY,
142    CV_METACALL_START,
143    CV_METACALL_STOP,
144    CV_METACALL_RESET,
145    CV_METACALL_USE_DEFAULT_GRAIN,
146    CV_METACALL_CONNECTED,
147    CV_METACALL_SUSPEND,
148    CV_METACALL_RESUME,
149    CV_METACALL_REPORT
150};
151
152#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER)
153#  define __cilkview_metacall(code,data) \
154    __cilkrts_metacall(METACALL_TOOL_CILKVIEW, code, data)
155#else
156#  define __cilkview_metacall(annotation,expr) (annotation, (void) (expr))
157#endif
158
159// Write arbitrary string to the log
160#define __cilkview_puts(arg) \
161    __cilkview_metacall(CV_METACALL_PUTS, arg)
162
163// Retrieve the Cilkview performance counters.  The parameter must be a
164// cilkview_data_t
165#define __cilkview_query(d)                             \
166    do {                                                \
167        d.size = sizeof(d);                             \
168        d.status = 0;                                   \
169        __cilkview_metacall(CV_METACALL_QUERY, &d);     \
170        if (0 == d.status)                              \
171            d.time = __cilkview_getticks();             \
172    } while (0)
173
174// Write report to log or results file. If end is NULL, Cilkview will
175// use the current values.
176#define __cilkview_report(start, end, label, flags) \
177    __cilkview_do_report(start, end, label, flags)
178
179// Control the workspan performance counters for the final report
180#define __cilkview_workspan_start() \
181    __cilkview_metacall(CV_METACALL_START, 0)
182#define __cilkview_workspan_stop() \
183    __cilkview_metacall(CV_METACALL_STOP, 0)
184#define __cilkview_workspan_reset() \
185    __cilkview_metacall(CV_METACALL_RESET, 0)
186#define __cilkview_workspan_suspend() \
187    __cilkview_metacall(CV_METACALL_SUSPEND, 0)
188#define __cilkview_workspan_resume() \
189    __cilkview_metacall(CV_METACALL_RESUME, 0)
190
191#define __cilkview_use_default_grain_size() \
192    __cilkview_metacall(CV_METACALL_USE_DEFAULT, 0)
193
194// Sets the int is_connected to 1 if Cilkview is active
195#define __cilkview_connected(is_connected) \
196    __cilkview_metacall(CV_METACALL_CONNECTED, &is_connected)
197
198
199#ifndef CILKVIEW_NO_REPORT
200
201// Stop Microsoft include files from complaining about getenv and fopen
202#define _CRT_SECURE_NO_WARNINGS
203
204#include <stdlib.h>
205#include <stdio.h>
206
207#ifdef _WIN32
208#pragma warning(push)
209#pragma warning(disable: 1786)	// Suppress warnings that getenv, fopen are deprecated
210#endif
211
212static void __cilkview_do_report(cilkview_data_t *start,
213                                 cilkview_data_t *end,
214                                 const char *label,
215                                 unsigned int flags)
216{
217    int under_cilkview = 0;
218    unsigned long long elapsed_ms;
219    int worker_count = 0;
220    char *nworkers;
221    char *outfile;
222    FILE *f;
223
224    // Check whether we're running under Cilkview
225    __cilkview_connected(under_cilkview);
226
227    // If we're running under Cilkview, let it do those things that need
228    // to be done
229    if (under_cilkview)
230    {
231        cilkview_report_t d = {start, end, label, flags};
232        __cilkview_metacall(CV_METACALL_REPORT, &d);
233        return;
234    }
235
236    // We're not running under Cilkview.
237    //
238    // If we weren't asked to write to the results file, we're done.
239    if (0 == (flags & CV_REPORT_WRITE_TO_RESULTS))
240        return;
241
242    // Calculate the elapse milliseconds
243    if (NULL == end)
244        elapsed_ms = __cilkview_getticks() - start->time;
245    else
246        elapsed_ms = end->time - start->time;
247
248    // Determine how many workers we're using for this trial run
249    nworkers = getenv("CILK_NWORKERS");
250    if (NULL != nworkers)
251        worker_count = atoi(nworkers);
252    if (0 == worker_count)
253        worker_count = 16;
254
255    // Open the output file and write the trial data to it
256    outfile = getenv("CILKVIEW_OUTFILE");
257    if (NULL == outfile)
258        outfile = (char *)"cilkview.out";
259
260    f = fopen(outfile, "a");
261    if (NULL == f)
262        fprintf(stderr, "__cilkview_do_report: unable to append to file %s\n", outfile);
263    else
264    {
265        fprintf(f, "%s trial %d %f\n", label,
266                worker_count,
267                ((float)elapsed_ms) / 1000.0f);
268        fclose(f);
269    }
270}
271#ifdef _WIN32
272#pragma warning(pop)
273#endif
274
275#endif  // CILKVIEW_NO_REPORT
276
277
278#endif /* ! defined(INCLUDED_CILKVIEW_H) */
279