stat.c revision de3d2ce46fc25c7b67ccbae4afe5f15e5357568f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008-2009, Intel Corporation.
* All Rights Reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <limits.h>
#include "latencytop.h"
typedef struct _lt_stat_collection lt_stat_collection_t;
typedef struct {
/* cause_id -> stat entry */
#define NGROUPS 2
#define GROUP_CAUSE 0
#define GROUP_SOBJ 1
/*
* A data collection (i.e. a "bucket"). E.g. system, process or thread.
* Collections are hierarchic, 1 sys -> many processes -> more threads.
*/
struct _lt_stat_collection {
unsigned int id;
char *name;
/*
* The following fields: parent, children and check_child_func
* maintain the tree structure.
*/
};
/* Internal data struct backs up a stat_list */
typedef struct _lt_stat_list lt_stat_list_t;
typedef void (*free_list_func_t)(lt_stat_list_t *);
struct _lt_stat_list {
int entry_count;
};
/* The root collection: system level statistics */
/*
* The data structure which supports synchronization objects.
* We don't use normal "cause table" because this needs to be cleared
* every time we refresh, so that dead synchronization objects don't
* eat up memory little by little.
*/
typedef struct {
int sobj_type;
unsigned long long sobj_addr;
} lt_sobj_id_t;
typedef struct {
int cause_id;
} lt_sobj_t;
static int sobj_table_len = 0;
/*
* Hash synchronize object ID by returning lower 32bit of its address.
*/
static guint
{
}
/*
* Test if two synchronization objects are the same.
*/
static gboolean
{
}
/*
* Lookup the cause_id of an synchronization object.
* Note this cause_id is only unique in GROUP_SOBJ, and changes after refresh.
*/
static lt_sobj_t *
{
const char *stype_str[] = {
"None",
"Mutex",
"RWLock",
"CV",
"Sema",
"User",
"User_PI",
"Shuttle"
};
const int stype_str_len =
return (NULL);
}
if (sobj_table != NULL) {
} else {
}
}
return (ret);
}
/*
*/
/* ARGSUSED */
static gboolean
{
/* Don't remove (return FALSE) if file exists */
}
/*
*/
/* ARGSUSED */
static gboolean
{
/* Don't remove (return FALSE) if file exists */
}
/*
* Helper function to free a stat node.
*/
static void
{
int i;
return;
}
for (i = 0; i < NGROUPS; ++i) {
}
}
}
}
}
/*
* Helper function zeroing a stat node.
*/
/* ARGSUSED */
static void
{
int i;
for (i = 0; i < NGROUPS; ++i) {
}
}
}
}
/*
* Update a collection for the value given.
* Recursively update its parent until it reaches the root.
*/
static void
const char *string, int group_to_use)
{
return;
}
} else {
}
switch (group_to_use) {
case GROUP_CAUSE:
/* hide the first '#' */
& CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
}
break;
case GROUP_SOBJ:
break;
}
entry);
}
if (group_to_use == GROUP_SOBJ ||
}
}
}
/*
* Identify the cause from a stack trace.
* Returns the cause_id.
*/
static int
find_cause(char *stack)
{
int cause_temp;
int prio_temp;
int cause = INVALID_CAUSE;
int priority = 0;
int found = 0;
char *sep;
*sep = 0;
}
cause = cause_temp;
}
*sep = ' ';
} else {
}
}
return (cause);
}
/*
* Create a new collection, hook it to the parent.
*/
static lt_stat_collection_t *
{
int i;
ret = (lt_stat_collection_t *)
lt_zalloc(sizeof (lt_stat_collection_t));
for (i = 0; i < NGROUPS; ++i) {
}
}
}
return (ret);
}
/*
* Finds the "leaf" collection, use given pid and tid.
*/
static lt_stat_collection_t *
{
if (stat_system == NULL) {
stat_p = (lt_stat_collection_t *)
}
char *fname;
/*
* we cannot get process execname,
* process is probably already dead.
*/
return (NULL);
}
stat_t = (lt_stat_collection_t *)
}
char *tname;
}
return (stat_t);
}
/*
* Update the statistics given cause_id directly. Value will be added to
* internal statistics.
*/
void
{
const char *string;
return;
}
/* we don't care about this cause, ignore. */
return;
}
/* cannot get fname, process must be dead. */
return;
}
}
/*
* Update the statistics given the stack trace.
* Internally it will be mapped to a cause using lt_table_lookup_cause(),
* and call lt_stat_update_cause().
*/
void
{
int cause_id = INVALID_CAUSE;
if (value == 0) {
return;
}
if (cause_id == INVALID_CAUSE) {
} else {
}
}
/*
* Zero all statistics, but keep the data structure in memory
* to be filled with new data immediately after.
*/
void
lt_stat_clear_all(void)
{
if (stat_system != NULL) {
}
if (sobj_table != NULL) {
sobj_table = NULL;
}
}
/*
* Clean up function that frees all memory used by statistics.
*/
void
lt_stat_free_all(void)
{
if (stat_system != NULL) {
stat_system = NULL;
}
if (sobj_table != NULL) {
sobj_table = NULL;
}
}
/*
* Get top N causes of latency for a process. Returns handle to a stat_list.
* Use pid = PID_SYS_GLOBAL to get global top list.
* Call lt_stat_list_free after use.
*/
void *
{
if (level == LT_LEVEL_GLOBAL) {
/* Use global entry */
/* Find process entry first */
if (level == LT_LEVEL_THREAD) {
/*
* If we request thread entry, find it based on
* process entry.
*/
stat_c = (lt_stat_collection_t *)
} else {
/*
* Couldn't find thread entry, set it to NULL
* so we will return empty list later.
*/
}
}
}
/* empty list */
return (ret);
}
if (list_type == LT_LIST_SOBJ) {
} else {
}
/* empty list */
return (ret);
}
switch (sort_by) {
case LT_SORT_TOTAL:
break;
case LT_SORT_MAX:
break;
case LT_SORT_AVG:
break;
case LT_SORT_COUNT:
break;
}
if (list_type == LT_LIST_CAUSE &&
!= 0) {
continue;
}
if (list_type == LT_LIST_SPECIALS &&
== 0) {
continue;
}
break;
}
}
return (ret);
}
/*
* Free memory allocated by lt_stat_list_create().
*/
void
lt_stat_list_free(void *ptr)
{
return;
}
}
}
}
/*
* Check if the list has item number i.
*/
int
lt_stat_list_has_item(void *ptr, int i)
{
return (0);
}
return (1);
}
/*
* Get the display name of item number i in the list.
*/
const char *
lt_stat_list_get_reason(void *ptr, int i)
{
return (NULL);
}
}
/*
* Get the max. of item number i in the list.
*/
lt_stat_list_get_max(void *ptr, int i)
{
return (0);
}
}
/*
* Get the total of item number i in the list.
*/
lt_stat_list_get_sum(void *ptr, int i)
{
return (0);
}
}
/*
* Get the count of item number i in the list.
*/
lt_stat_list_get_count(void *ptr, int i)
{
return (0);
}
}
/*
* Get grand total of all latencies in the pid where the list is drawn.
*/
lt_stat_list_get_gtotal(void *ptr)
{
return (0);
}
}
/*
* ============================================================================
* Process and thread list.
* They share a lot of static variables as stat part does,
* so put them in the same file.
*/
/*
*/
static int
{
}
/*
* Get current list of processes. Call lt_stat_proc_list_free after use.
*/
static int
{
}
return (ret);
}
/*
* Count how many threads are found so far in a process.
* Only thread caused SSLEEP will be found.
*/
/* ARGSUSED */
static void
{
}
}
/*
* Get current list of processes+threads.
* Call lt_stat_proc_list_free after use.
*/
static int
{
int ret = 0;
int count = 0;
continue;
}
++count;
}
}
return (ret);
}
/*
* List processes that have been processed in LatencyTOP.
*/
int
{
return (-1);
}
}
return (0);
}
return (plist_create(plist));
} else {
}
}
/*
* Free memory allocated by lt_stat_proc_list_create().
*/
void
{
}
}
}
/*
* Get execname of a PID.
*/
const char *
{
return (NULL);
}
stat_p = (lt_stat_collection_t *)
} else {
return (NULL);
}
}
/*
* Get number of threads.
*/
int
{
return (0);
}
stat_p = (lt_stat_collection_t *)
} else {
return (0);
}
}
/*
* Update the statistics for synchronization objects.
*/
void
unsigned long long wchan,
{
int cause_id;
return;
}
return;
}
}