/*
* 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 {
/* cause_id -> stat entry */
#define GROUP_CAUSE 0
/*
* A data collection hierarchy involving three entities - system, process
* and thread. The hierarchic relationship is as follows :
*
* 1 system -> 1 or more processes -> 1 or more threads
*/
struct _lt_stat_collection {
unsigned int lt_sc_id;
char *lt_sc_name;
/*
* The following fields: lt_sc_parent, lt_sc_children and
* lt_sc_check_child_func maintain the tree structure.
*/
};
/* Internal data structure to back up a stat_list */
struct _lt_stat_list {
int lt_sl_entry_count;
};
/* Root of the collection hierarchy: system level statistics */
/*
* Data structure to hold synchronization objects.
* We don't use normal "cause table" because this needs to be cleared
* every time we refresh in order to make sure that stale synchronization
* objects don't consume memory.
*/
typedef struct {
int lt_soi_type;
unsigned long long lt_soi_addr;
} lt_sobj_id_t;
typedef struct {
int lt_so_cause_id;
} lt_sobj_t;
static int sobj_table_len = 0;
/*
* Lower 32-bit of the address of synchronization objects is used to hash
* them.
*/
static guint
{
}
/*
* Test if two synchronization objects are the same.
*/
static gboolean
{
return (a->lt_soi_type == b->lt_soi_type &&
a->lt_soi_addr == b->lt_soi_addr);
}
/*
* Look up the cause_id of a synchronization object.
* Note that this cause_id is only unique in GROUP_SOBJ, and changes after
* a 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
{
}
/*
*/
/* ARGSUSED */
static gboolean
{
}
/*
* Helper function to free a stat node.
*/
static void
{
int i;
return;
}
for (i = 0; i < NGROUPS; ++i) {
}
}
}
}
}
/*
* Helper function to initialize a stat node.
*/
/* ARGSUSED */
static void
{
int i;
for (i = 0; i < NGROUPS; ++i) {
}
}
}
}
/*
* Update a collection with the given value.
* Recursively update parents in the hierarchy until the root is reached.
*/
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) {
++entry->lt_se_string;
}
break;
case GROUP_SOBJ:
break;
}
}
if (group_to_use == GROUP_SOBJ ||
CAUSE_FLAG_HIDE_IN_SUMMARY) == 0) {
value);
}
}
}
/*
* Identify the cause of latency from the given stack trace.
* Return cause_id.
*/
static void
{
int cause_temp;
int prio_temp;
int priority = 0;
int found = 0;
char *sep;
*sep = '\0';
}
&prio_temp);
cause = cause_temp;
}
*sep = ' ';
} else {
}
}
}
/*
* Create a new collection and 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) {
(const char *)name;
}
}
}
return (ret);
}
/*
* Find the "leaf" in the collection hierarchy, using the given pid and tid.
*/
static lt_stat_collection_t *
{
if (stat_system == NULL) {
stat_p = (lt_stat_collection_t *)
}
char *fname;
/*
* we could not get the executable name of the
* process; the process is probably already dead.
*/
return (NULL);
}
stat_t = (lt_stat_collection_t *)
}
char *tname;
}
return (stat_t);
}
/*
* Update statistics with the given cause_id. Values will be added to
* internal statistics.
*/
void
{
const char *string;
return;
}
/* Ignore this cause */
return;
}
/* Process must be dead. */
return;
}
}
/*
* Update statistics with the given stack trace.
* The stack trace is mapped to a cause and lt_stat_update_cause() is called
* to update statistics.
*/
void
{
int stack_priority = 0;
if (value == 0) {
return;
}
if (tag_priority != 0) {
if (tag_cause_id == INVALID_CAUSE) {
/* This must be a syscall tag */
}
}
if (cause_id == INVALID_CAUSE) {
/*
* We got an unmapped stack. Set SPECIAL flag to display it
* in pane 2. This makes it easier to find the cause.
*/
} else {
}
}
/*
* Zero out all statistics, but keep the data structures in memory
* to be used to hold new data immediately following.
*/
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 for 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. Return handle to a stat_list.
* Use pid = PID_SYS_GLOBAL to get global top list.
* Call lt_stat_list_free after use to clean up.
*/
void *
{
if (level == LT_LEVEL_GLOBAL) {
/* Use global entry */
/* Find process entry first */
if (level == LT_LEVEL_THREAD) {
/*
* If thread entry is requested, find it based on
* process entry.
*/
stat_c = (lt_stat_collection_t *)
} else {
/*
* Thread entry was not found; set it to NULL,
* so that we can 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 &&
CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
continue;
}
if (list_type == LT_LIST_SPECIALS &&
CAUSE_FLAG_SPECIAL) == 0) {
continue;
}
break;
}
}
return (ret);
}
/*
* Free memory allocated by lt_stat_list_create().
*/
void
{
return;
}
}
}
}
/*
* Check if the given list contains the given item.
*/
int
{
return (0);
}
return (1);
}
/*
* Get display name of the given item i in the given list.
*/
const char *
{
return (NULL);
}
}
/*
* Get maximum value of the given item i in the given list.
*/
{
return (0);
}
}
/*
* Get total value of the given item i in the given list.
*/
{
return (0);
}
}
/*
* Get count value of the given item i in the given list.
*/
{
return (0);
}
}
/*
* Get grand total of all latency in the list.
*/
{
return (0);
}
return (list->lt_sl_gtotal);
}
/*
* ============================================================================
* Process and thread list.
* They share a lot of the static variables that are used for keeping
* statistics, hence they are located in this file.
*/
/*
*/
static int
{
}
/*
* Get the current list of processes. Call lt_stat_proc_list_free after use
* to clean up.
*/
static int
{
}
return (ret);
}
/*
* Count the no. of threads currently present in a process.
* Only thread that have SSLEEP are counted.
*/
/* ARGSUSED */
static void
{
}
}
/*
* Get current list of processes and threads.
* Call lt_stat_proc_list_free after use to clean up.
*/
static int
{
int ret = 0;
int count = 0;
continue;
}
++count;
}
}
return (ret);
}
/*
* List of processes that are tracked by LatencyTOP.
*/
int
{
return (-1);
}
}
return (0);
}
return (plist_create(plist));
} else {
}
}
/*
* Free memory allocated by lt_stat_proc_list_create().
*/
void
{
}
}
}
/*
* Get executable name of the given process (ID).
*/
const char *
{
return (NULL);
}
return (stat_p->lt_sc_name);
} else {
return (NULL);
}
}
/*
* Get number of threads.
*/
int
{
return (0);
}
} else {
return (0);
}
}
/*
* Update statistics for synchronization objects.
*/
void
unsigned long long wchan,
{
int cause_id;
return;
}
return;
}
}