279 lines
9.1 KiB
C
279 lines
9.1 KiB
C
|
/* cilkview.h -*-C++-*-
|
||
|
*
|
||
|
*************************************************************************
|
||
|
*
|
||
|
* @copyright
|
||
|
* Copyright (C) 2010-2013, Intel Corporation
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* @copyright
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in
|
||
|
* the documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
* * Neither the name of Intel Corporation nor the names of its
|
||
|
* contributors may be used to endorse or promote products derived
|
||
|
* from this software without specific prior written permission.
|
||
|
*
|
||
|
* @copyright
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||
|
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
#ifndef INCLUDED_CILKVIEW_H
|
||
|
#define INCLUDED_CILKVIEW_H
|
||
|
|
||
|
#include <cilk/cilk_api.h>
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
# ifndef _WINBASE_
|
||
|
__CILKRTS_BEGIN_EXTERN_C
|
||
|
unsigned long __stdcall GetTickCount();
|
||
|
__CILKRTS_END_EXTERN_C
|
||
|
# endif
|
||
|
#endif // _WIN32
|
||
|
|
||
|
#if defined __unix__ || defined __APPLE__ || defined __VXWORKS__
|
||
|
# include <sys/time.h>
|
||
|
#endif // defined __unix__ || defined __APPLE__
|
||
|
|
||
|
/// @brief Return the system clock with millisecond resolution
|
||
|
///
|
||
|
/// This function returns a long integer representing the number of
|
||
|
/// milliseconds since an arbitrary starting point, e.g., since the system was
|
||
|
/// started or since the Unix Epoch. The result is meaningless by itself, but
|
||
|
/// the difference between two sequential calls to __cilkview_getticks()
|
||
|
/// represents the time interval that elapsed between them (in ms).
|
||
|
static inline unsigned long long __cilkview_getticks()
|
||
|
{
|
||
|
#if __INTEL_COMPILER > 1200
|
||
|
// When inlined, prevent code motion around this call
|
||
|
__notify_zc_intrinsic((void*) "test_getticks_start", 0);
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
// Return milliseconds elapsed since the system started
|
||
|
return GetTickCount();
|
||
|
#elif defined(__unix__) || defined(__APPLE__) || defined __VXWORKS__
|
||
|
// Return milliseconds elapsed since the Unix Epoch
|
||
|
// (1-Jan-1970 00:00:00.000 UTC)
|
||
|
struct timeval t;
|
||
|
gettimeofday(&t, 0);
|
||
|
return t.tv_sec * 1000ULL + t.tv_usec / 1000;
|
||
|
#else
|
||
|
# error test_getticks() not implemented for this OS
|
||
|
#endif
|
||
|
|
||
|
#if __INTEL_COMPILER > 1200
|
||
|
// When inlined, prevent code motion around this call
|
||
|
__notify_zc_intrinsic((void*) "test_getticks_end", 0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned int size; // Size of structure in bytes
|
||
|
unsigned int status; // 1 = success, 0 = failure
|
||
|
unsigned long long time; // Time in milliseconds
|
||
|
unsigned long long work;
|
||
|
unsigned long long span;
|
||
|
unsigned long long burdened_span;
|
||
|
unsigned long long spawns;
|
||
|
unsigned long long syncs;
|
||
|
unsigned long long strands;
|
||
|
unsigned long long atomic_ins;
|
||
|
unsigned long long frames;
|
||
|
} cilkview_data_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
cilkview_data_t *start; // Values at start of interval
|
||
|
cilkview_data_t *end; // Values at end of interval
|
||
|
const char *label; // Name for this interval
|
||
|
unsigned int flags; // What to do - see flags below
|
||
|
} cilkview_report_t;
|
||
|
|
||
|
// What __cilkview_report should do. The flags can be ORed together
|
||
|
enum
|
||
|
{
|
||
|
CV_REPORT_WRITE_TO_LOG = 1, // Write parallelism report to the log (xml or text)
|
||
|
CV_REPORT_WRITE_TO_RESULTS = 2 // Write parallelism data to results file
|
||
|
};
|
||
|
|
||
|
#ifndef CILKVIEW_NO_REPORT
|
||
|
static void __cilkview_do_report(cilkview_data_t *start,
|
||
|
cilkview_data_t *end,
|
||
|
const char *label,
|
||
|
unsigned int flags);
|
||
|
#endif /* CILKVIEW_NO_REPORT */
|
||
|
|
||
|
/*
|
||
|
* Metacall data
|
||
|
*
|
||
|
* A metacall is a way to pass data to a function implemented by a tool.
|
||
|
* Metacalls are always instrumented when the tool is loaded.
|
||
|
*/
|
||
|
|
||
|
// Tool code for Cilkview
|
||
|
#define METACALL_TOOL_CILKVIEW 2
|
||
|
|
||
|
// Metacall codes implemented by Cilkview
|
||
|
enum
|
||
|
{
|
||
|
CV_METACALL_PUTS,
|
||
|
CV_METACALL_QUERY,
|
||
|
CV_METACALL_START,
|
||
|
CV_METACALL_STOP,
|
||
|
CV_METACALL_RESET,
|
||
|
CV_METACALL_USE_DEFAULT_GRAIN,
|
||
|
CV_METACALL_CONNECTED,
|
||
|
CV_METACALL_SUSPEND,
|
||
|
CV_METACALL_RESUME,
|
||
|
CV_METACALL_REPORT
|
||
|
};
|
||
|
|
||
|
#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER)
|
||
|
# define __cilkview_metacall(code,data) \
|
||
|
__cilkrts_metacall(METACALL_TOOL_CILKVIEW, code, data)
|
||
|
#else
|
||
|
# define __cilkview_metacall(annotation,expr) (annotation, (void) (expr))
|
||
|
#endif
|
||
|
|
||
|
// Write arbitrary string to the log
|
||
|
#define __cilkview_puts(arg) \
|
||
|
__cilkview_metacall(CV_METACALL_PUTS, arg)
|
||
|
|
||
|
// Retrieve the Cilkview performance counters. The parameter must be a
|
||
|
// cilkview_data_t
|
||
|
#define __cilkview_query(d) \
|
||
|
do { \
|
||
|
d.size = sizeof(d); \
|
||
|
d.status = 0; \
|
||
|
__cilkview_metacall(CV_METACALL_QUERY, &d); \
|
||
|
if (0 == d.status) \
|
||
|
d.time = __cilkview_getticks(); \
|
||
|
} while (0)
|
||
|
|
||
|
// Write report to log or results file. If end is NULL, Cilkview will
|
||
|
// use the current values.
|
||
|
#define __cilkview_report(start, end, label, flags) \
|
||
|
__cilkview_do_report(start, end, label, flags)
|
||
|
|
||
|
// Control the workspan performance counters for the final report
|
||
|
#define __cilkview_workspan_start() \
|
||
|
__cilkview_metacall(CV_METACALL_START, 0)
|
||
|
#define __cilkview_workspan_stop() \
|
||
|
__cilkview_metacall(CV_METACALL_STOP, 0)
|
||
|
#define __cilkview_workspan_reset() \
|
||
|
__cilkview_metacall(CV_METACALL_RESET, 0)
|
||
|
#define __cilkview_workspan_suspend() \
|
||
|
__cilkview_metacall(CV_METACALL_SUSPEND, 0)
|
||
|
#define __cilkview_workspan_resume() \
|
||
|
__cilkview_metacall(CV_METACALL_RESUME, 0)
|
||
|
|
||
|
#define __cilkview_use_default_grain_size() \
|
||
|
__cilkview_metacall(CV_METACALL_USE_DEFAULT, 0)
|
||
|
|
||
|
// Sets the int is_connected to 1 if Cilkview is active
|
||
|
#define __cilkview_connected(is_connected) \
|
||
|
__cilkview_metacall(CV_METACALL_CONNECTED, &is_connected)
|
||
|
|
||
|
|
||
|
#ifndef CILKVIEW_NO_REPORT
|
||
|
|
||
|
// Stop Microsoft include files from complaining about getenv and fopen
|
||
|
#define _CRT_SECURE_NO_WARNINGS
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#pragma warning(push)
|
||
|
#pragma warning(disable: 1786) // Suppress warnings that getenv, fopen are deprecated
|
||
|
#endif
|
||
|
|
||
|
static void __cilkview_do_report(cilkview_data_t *start,
|
||
|
cilkview_data_t *end,
|
||
|
const char *label,
|
||
|
unsigned int flags)
|
||
|
{
|
||
|
int under_cilkview = 0;
|
||
|
unsigned long long elapsed_ms;
|
||
|
int worker_count = 0;
|
||
|
char *nworkers;
|
||
|
char *outfile;
|
||
|
FILE *f;
|
||
|
|
||
|
// Check whether we're running under Cilkview
|
||
|
__cilkview_connected(under_cilkview);
|
||
|
|
||
|
// If we're running under Cilkview, let it do those things that need
|
||
|
// to be done
|
||
|
if (under_cilkview)
|
||
|
{
|
||
|
cilkview_report_t d = {start, end, label, flags};
|
||
|
__cilkview_metacall(CV_METACALL_REPORT, &d);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// We're not running under Cilkview.
|
||
|
//
|
||
|
// If we weren't asked to write to the results file, we're done.
|
||
|
if (0 == (flags & CV_REPORT_WRITE_TO_RESULTS))
|
||
|
return;
|
||
|
|
||
|
// Calculate the elapse milliseconds
|
||
|
if (NULL == end)
|
||
|
elapsed_ms = __cilkview_getticks() - start->time;
|
||
|
else
|
||
|
elapsed_ms = end->time - start->time;
|
||
|
|
||
|
// Determine how many workers we're using for this trial run
|
||
|
nworkers = getenv("CILK_NWORKERS");
|
||
|
if (NULL != nworkers)
|
||
|
worker_count = atoi(nworkers);
|
||
|
if (0 == worker_count)
|
||
|
worker_count = 16;
|
||
|
|
||
|
// Open the output file and write the trial data to it
|
||
|
outfile = getenv("CILKVIEW_OUTFILE");
|
||
|
if (NULL == outfile)
|
||
|
outfile = (char *)"cilkview.out";
|
||
|
|
||
|
f = fopen(outfile, "a");
|
||
|
if (NULL == f)
|
||
|
fprintf(stderr, "__cilkview_do_report: unable to append to file %s\n", outfile);
|
||
|
else
|
||
|
{
|
||
|
fprintf(f, "%s trial %d %f\n", label,
|
||
|
worker_count,
|
||
|
((float)elapsed_ms) / 1000.0f);
|
||
|
fclose(f);
|
||
|
}
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
#pragma warning(pop)
|
||
|
#endif
|
||
|
|
||
|
#endif // CILKVIEW_NO_REPORT
|
||
|
|
||
|
|
||
|
#endif /* ! defined(INCLUDED_CILKVIEW_H) */
|