blob: e98489368af8b79b9a2603212027c5c065aacea5 [file] [log] [blame]
/* cilkview.h -*-C++-*-
*
*************************************************************************
*
* Copyright (C) 2010-2016, Intel Corporation
* All rights reserved.
*
* 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.
*
* 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.
*
* *********************************************************************
*
* PLEASE NOTE: This file is a downstream copy of a file mainitained in
* a repository at cilkplus.org. Changes made to this file that are not
* submitted through the contribution process detailed at
* http://www.cilkplus.org/submit-cilk-contribution will be lost the next
* time that a new version is released. Changes only submitted to the
* GNU compiler collection or posted to the git repository at
* https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
* not tracked.
*
* We welcome your contributions to this open source project. Thank you
* for your assistance in helping us improve Cilk Plus.
*
**************************************************************************/
#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) */