mirror of
https://github.com/ValveSoftware/Proton.git
synced 2024-12-30 16:45:36 +03:00
275 lines
7.2 KiB
C
275 lines
7.2 KiB
C
//*@@@+++@@@@******************************************************************
|
|
//
|
|
// Copyright © Microsoft Corp.
|
|
// 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.
|
|
//
|
|
// 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.
|
|
//
|
|
//*@@@---@@@@******************************************************************
|
|
|
|
//***************************************************************************
|
|
// Includes
|
|
//***************************************************************************
|
|
#include <time.h>
|
|
#include "strcodec.h"
|
|
#include "perfTimer.h"
|
|
|
|
|
|
#ifndef DISABLE_PERF_MEASUREMENT
|
|
|
|
|
|
//***************************************************************************
|
|
// Private Functions
|
|
//***************************************************************************
|
|
|
|
Bool AccumulateTime(PERFTIMERSTATE *pState, PERFTIMERTIME *ptAccumulator)
|
|
{
|
|
Bool fResult = FALSE;
|
|
clock_t iStopTime;
|
|
clock_t iIntervalTime;
|
|
iStopTime = clock();
|
|
|
|
// Check clock result
|
|
if ((clock_t)-1 == iStopTime)
|
|
{
|
|
TraceResult(WM_E_CLOCKFAILURE);
|
|
goto exit;
|
|
}
|
|
|
|
iIntervalTime = (iStopTime - (clock_t) pState->iPrevStartTime);
|
|
|
|
// Check for zero-time interval
|
|
if (0 == iIntervalTime)
|
|
pState->iZeroTimeIntervals += 1;
|
|
|
|
// Accumulate current interval's time
|
|
*ptAccumulator += iIntervalTime;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
return fResult;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
// Public Functions
|
|
//***************************************************************************
|
|
|
|
|
|
Bool PerfTimerNew(PERFTIMERSTATE **ppNewPerfTimer)
|
|
{
|
|
Bool fResult = FALSE;
|
|
PERFTIMERSTATE *pState = NULL;
|
|
clock_t ctResult;
|
|
|
|
// Check if this clock works
|
|
ctResult = clock();
|
|
if ((clock_t)-1 == ctResult)
|
|
{
|
|
TraceResult(WM_E_CLOCKFAILURE);
|
|
goto exit;
|
|
}
|
|
|
|
pState = malloc(sizeof(*pState));
|
|
if (NULL == pState)
|
|
{
|
|
TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
memset(pState, 0, sizeof(*pState));
|
|
pState->eState = CS_STOPPED;
|
|
pState->iElapsedTime = 0;
|
|
pState->iPrevStartTime = 0;
|
|
pState->iZeroTimeIntervals = 0;
|
|
|
|
*ppNewPerfTimer = pState;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
assert(fResult || NULL == pState); // If error, we need to free pState
|
|
return fResult;
|
|
} // PerfTimerNew
|
|
|
|
|
|
|
|
void PerfTimerDelete(PERFTIMERSTATE *pState)
|
|
{
|
|
free(pState);
|
|
} // PerfTimerDelete
|
|
|
|
|
|
|
|
Bool PerfTimerStart(PERFTIMERSTATE *pState)
|
|
{
|
|
Bool fResult = FALSE;
|
|
|
|
if (NULL == pState)
|
|
{
|
|
// Can happen because we typically ignore errors and use a single bool to
|
|
// control all perf timing (some of which can fail to init)
|
|
goto exit;
|
|
}
|
|
|
|
// Make sure we are in the right state
|
|
if (CS_STOPPED != pState->eState)
|
|
{
|
|
assert(FALSE);
|
|
goto exit;
|
|
}
|
|
|
|
pState->iPrevStartTime = clock();
|
|
|
|
// Check clock result
|
|
if ((clock_t)-1 == pState->iPrevStartTime)
|
|
{
|
|
TraceResult(WM_E_CLOCKFAILURE);
|
|
goto exit;
|
|
}
|
|
|
|
pState->eState = CS_RUNNING;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
return fResult;
|
|
} // PerfTimerStart
|
|
|
|
|
|
|
|
Bool PerfTimerStop(PERFTIMERSTATE *pState)
|
|
{
|
|
Bool fResult = FALSE;
|
|
|
|
if (NULL == pState)
|
|
{
|
|
// Can happen because we typically ignore errors and use a single bool to
|
|
// control all perf timing (some of which can fail to init)
|
|
goto exit;
|
|
}
|
|
|
|
// Make sure we are in the right state
|
|
if (CS_RUNNING != pState->eState)
|
|
{
|
|
assert(FALSE);
|
|
goto exit;
|
|
}
|
|
|
|
fResult = AccumulateTime(pState, &pState->iElapsedTime);
|
|
pState->eState = CS_STOPPED;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
return fResult;
|
|
} // PerfTimerStop
|
|
|
|
|
|
|
|
Bool PerfTimerGetResults(PERFTIMERSTATE *pState, PERFTIMERRESULTS *pResults)
|
|
{
|
|
Bool fResult = FALSE;
|
|
PERFTIMERTIME iElapsedTime;
|
|
|
|
if (NULL == pState)
|
|
{
|
|
// Can happen because we typically ignore errors and use a single bool to
|
|
// control all perf timing (some of which can fail to init)
|
|
goto exit;
|
|
}
|
|
|
|
// Make sure we are in the right state
|
|
if (CS_STOPPED != pState->eState && CS_RUNNING != pState->eState)
|
|
{
|
|
assert(FALSE);
|
|
goto exit;
|
|
}
|
|
|
|
iElapsedTime = pState->iElapsedTime;
|
|
if (CS_RUNNING == pState->eState)
|
|
{
|
|
// Must take a "checkpoint" time reading
|
|
fResult = AccumulateTime(pState, &iElapsedTime);
|
|
if (FALSE == fResult)
|
|
goto exit;
|
|
}
|
|
|
|
// Convert clock ticks to nanoseconds.
|
|
// Use floating point for ease of math. If your platform really blows
|
|
// with floating point, replace this with appropriate integer calculation
|
|
// based on your clock interval.
|
|
pResults->iElapsedTime = (PERFTIMERTIME)((float)iElapsedTime *
|
|
((float)NANOSECONDS_PER_SECOND / (float)CLOCKS_PER_SEC));
|
|
pResults->iTicksPerSecond = CLOCKS_PER_SEC;
|
|
pResults->iZeroTimeIntervals = pState->iZeroTimeIntervals;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
return fResult;
|
|
} // PerfTimerGetResults
|
|
|
|
|
|
|
|
Bool PerfTimerCopyStartTime(PERFTIMERSTATE *pDestPerfTimer,
|
|
PERFTIMERSTATE *pSrcPerfTimer)
|
|
{
|
|
Bool fResult = FALSE;
|
|
|
|
if (NULL == pDestPerfTimer)
|
|
{
|
|
TraceResult(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
if (NULL == pSrcPerfTimer)
|
|
{
|
|
TraceResult(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Check that both timers are in proper state - both must be running
|
|
if (CS_RUNNING != pDestPerfTimer->eState)
|
|
{
|
|
TraceResult(WM_E_INVALIDSTATE);
|
|
goto exit;
|
|
}
|
|
|
|
if (CS_RUNNING != pSrcPerfTimer->eState)
|
|
{
|
|
TraceResult(WM_E_INVALIDSTATE);
|
|
goto exit;
|
|
}
|
|
|
|
if (0 != pDestPerfTimer->iElapsedTime)
|
|
{
|
|
// If iElapsedTime is non-zero, caller won't get what he is expecting
|
|
// when he calls PerfTimerGetResults
|
|
TraceResult(WM_E_INVALIDSTATE);
|
|
goto exit;
|
|
}
|
|
|
|
pDestPerfTimer->iPrevStartTime = pSrcPerfTimer->iPrevStartTime;
|
|
fResult = TRUE;
|
|
|
|
exit:
|
|
return fResult;
|
|
} // PerfTimerCopyStartTime
|
|
|
|
#endif // DISABLE_PERF_MEASUREMENT
|