mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-09 14:09:10 -04:00
252 lines
6.1 KiB
C
252 lines
6.1 KiB
C
/* $NetBSD: iscsi_profile.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Wasabi Systems, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
|
*/
|
|
#include "iscsi_globals.h"
|
|
|
|
#ifdef ISCSI_PERFTEST
|
|
|
|
command_perf_t *perfdata = NULL;
|
|
int perf_active = 0;
|
|
|
|
static int perfcount = 0;
|
|
static int perfindex = 0;
|
|
static uint64_t ticks_per_100us = 0;
|
|
|
|
/*
|
|
* perf_begin_command:
|
|
* Start command profiling.
|
|
* Allocates space for a command entry, sets the data length and
|
|
* flags, and gets the begin cycle count.
|
|
* If no room is left in the data buffer, nothing is set.
|
|
*
|
|
* Note: The perf_index set in the CCB is the index + 1, so that 0 is
|
|
* reserved as profiling not active (this is the default state
|
|
* for CCB fields).
|
|
*
|
|
* This function must only be called if perf_active is nonzero.
|
|
* The wrapper macro checks for this condition.
|
|
*
|
|
* Parameter:
|
|
* ccb The associated CCB.
|
|
* nowait Nonzero if this is a no-wait command.
|
|
*/
|
|
|
|
void
|
|
perf_begin_command(ccb_t *ccb, int nowait)
|
|
{
|
|
int idx;
|
|
|
|
/* Only trace commands that actually transfer data so we don't skew results */
|
|
if (ccb->data_len < 512) {
|
|
return;
|
|
}
|
|
idx = perfindex++;
|
|
if (idx >= perfcount) {
|
|
--perfindex;
|
|
return;
|
|
}
|
|
perfdata[idx].datalen = ccb->data_len;
|
|
if (ccb->data_in) {
|
|
perfdata[idx].status |= PERF_FLG_READ;
|
|
}
|
|
if (nowait) {
|
|
perfdata[idx].status |= PERF_FLG_NOWAIT;
|
|
}
|
|
ccb->perf_index = ++idx;
|
|
perf_snap(idx, PERF_BEGIN_COMMAND);
|
|
}
|
|
|
|
|
|
/*
|
|
* perf_end_command:
|
|
* Ends command profiling.
|
|
* Gets the end cycle count, and sets the complete flag.
|
|
*
|
|
* Parameter:
|
|
* ccb The associated CCB.
|
|
*/
|
|
|
|
void
|
|
perf_end_command(ccb_t *ccb)
|
|
{
|
|
int idx = ccb->perf_index;
|
|
|
|
perf_snap(idx, PERF_END_COMMAND);
|
|
perfdata[idx - 1].status |=
|
|
(ccb->status & 0xffffff) | PERF_FLG_COMPLETE;
|
|
ccb->perf_index = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* perf_do_stop:
|
|
* Stops performance data collection (internal function).
|
|
* Clears perf_active, and waits until all commands have completed.
|
|
* The wait is limited to 5 seconds.
|
|
*/
|
|
|
|
STATIC void
|
|
perf_do_stop(void)
|
|
{
|
|
int i, n = 0;
|
|
|
|
perf_active = 0;
|
|
do {
|
|
for (i = 0; i < perfindex; i++) {
|
|
if (!(perfdata[i].status & PERF_FLG_COMPLETE)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i < perfindex) {
|
|
tsleep(&perfindex, PWAIT, "wait_perf", 1 * hz);
|
|
}
|
|
} while (n++ < 10 && i < perfindex);
|
|
}
|
|
|
|
|
|
/*
|
|
* perf_start:
|
|
* Starts performance data collection.
|
|
* If collection is already running, it is stopped.
|
|
* Allocates a buffer if necessary, clears the buffer, resets indices.
|
|
* Measures tick timing.
|
|
*
|
|
* Parameter:
|
|
* par The ioctl parameter specifying the number of elements.
|
|
*/
|
|
|
|
void
|
|
perf_start(iscsi_perf_startstop_parameters_t *par)
|
|
{
|
|
uint64_t rv, rv1, rv2;
|
|
int i, s;
|
|
|
|
if (par->num_elements <= 0) {
|
|
par->status = ISCSI_STATUS_PARAMETER_INVALID;
|
|
return;
|
|
}
|
|
if (perf_active)
|
|
perf_do_stop();
|
|
|
|
if (perfdata == NULL || perfcount < par->num_elements) {
|
|
if (perfdata != NULL) {
|
|
free(perfdata, M_DEVBUF);
|
|
}
|
|
perfdata = malloc(par->num_elements * sizeof(*perfdata),
|
|
M_DEVBUF, M_WAITOK);
|
|
if (perfdata == NULL) {
|
|
perfcount = 0;
|
|
par->status = ISCSI_STATUS_NO_RESOURCES;
|
|
return;
|
|
}
|
|
perfcount = par->num_elements;
|
|
}
|
|
|
|
(void) memset(perfdata, 0x0, perfcount * sizeof(*perfdata));
|
|
perfindex = 0;
|
|
|
|
rv = 0;
|
|
for (i = 0; i < 5; i++) {
|
|
s = splhigh();
|
|
|
|
__asm __volatile("rdtsc":"=A"(rv1));
|
|
delay(100);
|
|
__asm __volatile("rdtsc":"=A"(rv2));
|
|
|
|
splx(s);
|
|
rv += rv2 - rv1;
|
|
}
|
|
|
|
ticks_per_100us = rv / 5;
|
|
par->status = ISCSI_STATUS_SUCCESS;
|
|
|
|
perf_active = 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* perf_start:
|
|
* Stops performance data collection (external interface).
|
|
*
|
|
* Parameter:
|
|
* par The ioctl parameter receiving the number of
|
|
* elements collected.
|
|
*/
|
|
|
|
void
|
|
perf_stop(iscsi_perf_startstop_parameters_t *par)
|
|
{
|
|
if (perfdata == NULL || perfcount <= 0 || !perf_active) {
|
|
par->status = ISCSI_STATUS_GENERAL_ERROR;
|
|
return;
|
|
}
|
|
perf_do_stop();
|
|
par->num_elements = perfindex;
|
|
par->status = ISCSI_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* perf_get:
|
|
* Retrieves performance data.
|
|
*
|
|
* Parameter:
|
|
* par The ioctl parameter.
|
|
*/
|
|
|
|
void
|
|
perf_get(iscsi_perf_get_parameters_t *par)
|
|
{
|
|
int nelem;
|
|
|
|
if (perfdata == NULL || perfcount <= 0) {
|
|
par->status = ISCSI_STATUS_GENERAL_ERROR;
|
|
return;
|
|
}
|
|
par->status = ISCSI_STATUS_SUCCESS;
|
|
|
|
if (!par->buffersize) {
|
|
par->buffersize = perfindex * sizeof(command_perf_t);
|
|
par->num_elements = perfindex;
|
|
return;
|
|
}
|
|
nelem = par->buffersize / sizeof(command_perf_t);
|
|
if (!nelem) {
|
|
par->status = ISCSI_STATUS_PARAMETER_INVALID;
|
|
return;
|
|
}
|
|
nelem = min(nelem, perfindex);
|
|
copyout(perfdata, par->buffer, nelem * sizeof(command_perf_t));
|
|
par->num_elements = nelem;
|
|
par->ticks_per_100us = ticks_per_100us;
|
|
}
|
|
|
|
#endif
|