--- old/usr/src/cmd/dtrace/Makefile	Thu Apr 11 14:30:35 2024
+++ new/usr/src/cmd/dtrace/Makefile	Thu Apr 11 14:30:35 2024
@@ -23,32 +23,22 @@
 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG= dtrace
 
 include ../Makefile.cmd
 
-SUBDIRS=	$(MACH) demo test
-$(BUILD64)SUBDIRS += $(MACH64)
+SUBDIRS=	$(MACH64) demo test
 
 all	:=	TARGET = all
 install	:=	TARGET = install
 clean	:=	TARGET = clean
 clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
 
 .KEEP_STATE:
 
-all:	$(SUBDIRS)
+all clean clobber install:	$(SUBDIRS)
 
-clean clobber lint:	$(SUBDIRS)
-
-install:	$(SUBDIRS)
-	-$(RM) $(ROOTUSRSBINPROG)
-	-$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG)
-
 $(SUBDIRS):	FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
--- old/usr/src/cmd/dtrace/amd64/Makefile	Thu Apr 11 14:30:35 2024
+++ new/usr/src/cmd/dtrace/amd64/Makefile	Thu Apr 11 14:30:35 2024
@@ -23,10 +23,13 @@
 # Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 include ../Makefile.com
 include ../../Makefile.cmd.64
 
-install: all $(ROOTUSRSBINPROG64)
+ROOTLINK = $(PROG:%=$(ROOTUSRSBIN64)/%)
+
+install: all $(ROOTUSRSBINPROG) $(ROOTLINK)
+
+$(ROOTLINK): all
+	$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@
--- old/usr/src/cmd/dtrace/i386/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2003 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-
-install: all $(ROOTUSRSBINPROG32)
--- old/usr/src/cmd/dtrace/sparc/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2003 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-
-install: all $(ROOTUSRSBINPROG32)
--- old/usr/src/cmd/dtrace/sparcv9/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,31 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2003 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/intrstat/Makefile	Thu Apr 11 14:30:35 2024
+++ new/usr/src/cmd/intrstat/Makefile	Thu Apr 11 14:30:35 2024
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# 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
 # or http://www.opensolaris.org/os/licensing.
@@ -20,38 +19,50 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 
-PROG= intrstat
+PROG = intrstat
+OBJS = intrstat.o
 
 include ../Makefile.cmd
+include ../Makefile.cmd.64
 
-$(64ONLY)SUBDIRS= $(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
+STATCOMMONDIR = $(SRC)/cmd/stat/common
 
-all	:=	TARGET = all
-install	:=	TARGET = install
-clean	:=	TARGET = clean
-clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
+STAT_COMMON_OBJS = timestamp.o
+STAT_COMMON_SRCS = $(STAT_COMMON_OBJS:%.o=$(STATCOMMONDIR)/%.c)
 
+CPPFLAGS += -I$(STATCOMMONDIR)
+CFLAGS += $(CCVERBOSE)
+CERRWARN += $(CNOWARN_UNINIT)
+LDLIBS += -ldtrace
+
+FILEMODE = 0555
+
+CLEANFILES += $(OBJS) $(STAT_COMMON_OBJS)
+
+ROOTLINK = $(PROG:%=$(ROOTUSRSBIN64)/%)
+
 .KEEP_STATE:
 
-all:	$(SUBDIRS)
+all: $(PROG)
 
-clean clobber lint:	$(SUBDIRS)
+install: all $(ROOTUSRSBINPROG) $(ROOTLINK)
 
-install:	$(SUBDIRS)
-	-$(RM) $(ROOTUSRSBINPROG)
-	-$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG)
+$(ROOTLINK):
+	$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@
 
-$(SUBDIRS):	FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
+$(PROG): $(OBJS) $(STAT_COMMON_OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(STAT_COMMON_OBJS) $(LDLIBS)
+	$(POST_PROCESS) ; $(STRIP_STABS)
 
-FRC:
+%.o : $(STATCOMMONDIR)/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
 
+clean:
+	-$(RM) $(CLEANFILES)
+
 include ../Makefile.targ
--- old/usr/src/cmd/intrstat/Makefile.com	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,68 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-PROG = intrstat
-OBJS = intrstat.o
-SRCS = $(OBJS:%.o=../%.c)
-
-include ../../Makefile.cmd
-
-STATCOMMONDIR = $(SRC)/cmd/stat/common
-
-STAT_COMMON_OBJS = timestamp.o
-STAT_COMMON_SRCS = $(STAT_COMMON_OBJS:%.o=$(STATCOMMONDIR)/%.c)
-SRCS += $(STAT_COMMON_SRCS)
-
-CPPFLAGS += -I$(STATCOMMONDIR)
-CFLAGS += $(CCVERBOSE)
-CFLAGS64 += $(CCVERBOSE)
-CERRWARN += $(CNOWARN_UNINIT)
-LDLIBS += -ldtrace
-
-FILEMODE = 0555
-
-CLEANFILES += $(OBJS) $(STAT_COMMON_OBJS)
-
-.KEEP_STATE:
-
-all: $(PROG)
-
-$(PROG): $(OBJS) $(STAT_COMMON_OBJS)
-	$(LINK.c) -o $@ $(OBJS) $(STAT_COMMON_OBJS) $(LDLIBS)
-	$(POST_PROCESS) ; $(STRIP_STABS)
-
-%.o : $(STATCOMMONDIR)/%.c
-	$(COMPILE.c) -o $@ $<
-	$(POST_PROCESS_O)
-
-clean:
-	-$(RM) $(CLEANFILES)
-
-lint: lint_SRCS
-
-%.o: ../%.c
-	$(COMPILE.c) $<
-
-include ../../Makefile.targ
--- old/usr/src/cmd/intrstat/amd64/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,32 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/intrstat/i386/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2003 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-
-install: all $(ROOTUSRSBINPROG32)
--- old/usr/src/cmd/intrstat/sparcv9/Makefile	Thu Apr 11 14:30:35 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,31 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2003 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/latencytop/Makefile	Thu Apr 11 14:30:35 2024
+++ new/usr/src/cmd/latencytop/Makefile	Thu Apr 11 14:30:35 2024
@@ -18,30 +18,60 @@
 #
 # CDDL HEADER END
 #
+#
 # Copyright (c) 2008-2009, Intel Corporation.
 # All Rights Reserved.
 #
+# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
 
 PROG = latencytop
+OBJS = latencytop.o display.o dwrapper.o klog.o stat.o table.o util.o
 
 include ../Makefile.cmd
+include ../Makefile.cmd.64
 
-$(64ONLY)SUBDIRS= $(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
+CFLAGS += $(CCVERBOSE)
 
-all	:=	TARGET = all
-install	:=	TARGET = install
-clean	:=	TARGET = clean
-clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
+CERRWARN += $(CNOWARN_UNINIT)
 
+# smatch has problems parsing the glib header files
+SMATCH=off
+
+CPPFLAGS += -DEMBED_CONFIGS -I$(ADJUNCT_PROTO)/usr/include/glib-2.0 \
+	-I$(ADJUNCT_PROTO)/usr/lib/glib-2.0/include
+CSTD = $(CSTD_GNU99)
+LDLIBS += -lcurses -ldtrace
+NATIVE_LIBS += libglib-2.0.so
+all install	:= LDLIBS += -lglib-2.0
+
+FILEMODE = 0555
+
+WRAPOBJ = latencytop_wrap.o
+
+CLEANFILES += $(OBJS) $(WRAPOBJ) ./latencytop_d ./latencytop_trans
+
 .KEEP_STATE:
 
-all install clean clobber lint:	$(SUBDIRS)
+all: $(PROG)
 
-$(SUBDIRS):	FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
+install: all $(ROOTPROG)
 
-FRC:
+$(PROG): $(OBJS) $(WRAPOBJ)
+	$(LINK.c) -o $@ $(OBJS) $(WRAPOBJ) $(LDLIBS)
+	$(POST_PROCESS)
 
+latencytop_d: latencytop.d
+	$(CP) $^ $@
+
+latencytop_trans: latencytop.trans
+	$(CP) $^ $@
+
+$(WRAPOBJ): latencytop_d latencytop_trans
+	$(ELFWRAP) -64 -o $(WRAPOBJ) latencytop_d \
+		latencytop_trans
+
+clean:
+	$(RM) $(CLEANFILES)
+
 include ../Makefile.targ
--- old/usr/src/cmd/latencytop/Makefile.com	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,83 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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.
-#
-# Copyright (c) 2018, Joyent, Inc.
-# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
-
-PROG = latencytop
-OBJS = latencytop.o display.o dwrapper.o klog.o stat.o table.o util.o
-SRCS = $(OBJS:%.o=../common/%.c)
-
-include ../../Makefile.cmd
-
-CFLAGS += $(CCVERBOSE)
-CFLAGS64 += $(CCVERBOSE)
-
-CERRWARN += $(CNOWARN_UNINIT)
-
-# smatch has problems parsing the glib header files
-SMATCH=off
-
-CPPFLAGS += -DEMBED_CONFIGS -I$(ADJUNCT_PROTO)/usr/include/glib-2.0 \
-	-I$(ADJUNCT_PROTO)/usr/lib/glib-2.0/include
-CSTD = $(CSTD_GNU99)
-LDLIBS += -lcurses -ldtrace
-NATIVE_LIBS += libglib-2.0.so
-all install	:= LDLIBS += -lglib-2.0
-
-FILEMODE = 0555
-
-ELFWRAP = elfwrap
-WRAPOBJ = latencytop_wrap.o
-
-CLEANFILES += $(OBJS) $(WRAPOBJ) ./latencytop_d ./latencytop_trans
-
-.KEEP_STATE:
-
-all: $(PROG)
-
-install:        $(SUBDIRS)
-	-$(RM) $(ROOTPROG)
-	-$(LN) $(ISAEXEC) $(ROOTPROG)
-
-$(PROG): $(OBJS) $(WRAPOBJ)
-	$(LINK.c) -o $@ $(OBJS) $(WRAPOBJ) $(LDLIBS)
-	$(POST_PROCESS)
-
-$(WRAPOBJ): latencytop_d latencytop_trans
-	$(ELFWRAP) $(WRAPOPT) -o $(WRAPOBJ) latencytop_d latencytop_trans
-
-latencytop_d:
-	cp ../common/latencytop.d ./latencytop_d
-
-latencytop_trans:
-	cp ../common/latencytop.trans ./latencytop_trans
-
-clean:
-	$(RM) $(CLEANFILES)
-
-%.o: ../common/%.c
-	$(COMPILE.c) $<
-
-include ../../Makefile.targ
--- old/usr/src/cmd/latencytop/amd64/Makefile	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 ../Makefile.com
-include ../../Makefile.cmd.64
-
-WRAPOPT = -64
-
-install: all $(ROOTPROG64)
--- old/usr/src/cmd/latencytop/common/display.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,1068 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <curses.h>
-#include <time.h>
-#include <wchar.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <signal.h>
-
-#include "latencytop.h"
-
-#define	LT_WINDOW_X			80
-#define	LT_WINDOW_Y			24
-
-#define	LT_COLOR_DEFAULT		1
-#define	LT_COLOR_HEADER			2
-
-/* Windows created by libcurses */
-static WINDOW	*titlebar = NULL;
-static WINDOW	*captionbar = NULL;
-static WINDOW	*sysglobal_window = NULL;
-static WINDOW	*taskbar = NULL;
-static WINDOW	*process_window = NULL;
-static WINDOW	*hintbar = NULL;
-/* Screen dimension */
-static int	screen_width = 1, screen_height = 1;
-/* Is display initialized, i.e. are window pointers set up. */
-static int	display_initialized = FALSE;
-/* Is initscr() called */
-static int	curses_inited = FALSE;
-
-/* To handle user key presses */
-static pid_t selected_pid = INVALID_PID;
-static id_t selected_tid = INVALID_TID;
-static lt_sort_t sort_type = LT_SORT_TOTAL;
-static int thread_mode = FALSE;
-/* Type of list being displayed */
-static int current_list_type = LT_LIST_CAUSE;
-static int show_help = FALSE;
-
-/* Help functions that append/prepend a blank to the given string */
-#define	fill_space_right(a, b, c)	fill_space((a), (b), (c), TRUE)
-#define	fill_space_left(a, b, c)	fill_space((a), (b), (c), FALSE)
-
-static void
-fill_space(char *buffer, int len, int buffer_limit, int is_right)
-{
-	int i = 0;
-	int tofill;
-
-	if (len >= buffer_limit) {
-		len = buffer_limit - 1;
-	}
-
-	i = strlen(buffer);
-
-	if (i >= len) {
-		return;
-	}
-
-	tofill = len - i;
-
-	if (is_right) {
-		(void) memset(&buffer[i], ' ', tofill);
-		buffer[len] = '\0';
-	} else {
-		(void) memmove(&buffer[tofill], buffer, i+1);
-		(void) memset(buffer, ' ', tofill);
-	}
-}
-
-/* Convert the nanosecond value to a human readable string */
-static const char *
-get_time_string(double nanoseconds, char *buffer, int len, int fill_width)
-{
-	const double ONE_USEC = 1000.0;
-	const double ONE_MSEC = 1000000.0;
-	const double ONE_SEC  = 1000000000.0;
-
-	if (nanoseconds < (ONE_USEC - .5)) {
-		(void) snprintf(buffer, len, "%3.1f nsec", nanoseconds);
-	} else if (nanoseconds < (ONE_MSEC - .5 * ONE_USEC)) {
-		(void) snprintf(buffer, len,
-		    "%3.1f usec", nanoseconds / ONE_USEC);
-	} else if (nanoseconds < (ONE_SEC - .5 * ONE_MSEC)) {
-		(void) snprintf(buffer, len,
-		    "%3.1f msec", nanoseconds / ONE_MSEC);
-	} else if (nanoseconds < 999.5 * ONE_SEC) {
-		(void) snprintf(buffer, len,
-		    "%3.1f  sec", nanoseconds / ONE_SEC);
-	} else {
-		(void) snprintf(buffer, len,
-		    "%.0e sec", nanoseconds / ONE_SEC);
-	}
-
-	fill_space_left(buffer, fill_width, len);
-	return (buffer);
-}
-
-/* Used in print_statistics below */
-#define	WIDTH_REASON_STRING	36
-#define	WIDTH_COUNT		12
-#define	WIDTH_AVG		12
-#define	WIDTH_MAX		12
-#define	WIDTH_PCT		8
-#define	BEGIN_COUNT		WIDTH_REASON_STRING
-#define	BEGIN_AVG		(BEGIN_COUNT + WIDTH_COUNT)
-#define	BEGIN_MAX		(BEGIN_AVG + WIDTH_AVG)
-#define	BEGIN_PCT		(BEGIN_MAX + WIDTH_MAX)
-
-/*
- * Print statistics in global/process pane. Called by print_sysglobal
- * print_process.
- *
- * Parameters:
- *		window - the global or process statistics window.
- *		begin_line - where to start printing.
- *		count - how many lines should be printed.
- *		list - a stat_list.
- */
-static void
-print_statistics(WINDOW * window, int begin_line, int nlines, void *list)
-{
-	uint64_t total;
-	int i = 0;
-
-	if (!display_initialized) {
-		return;
-	}
-
-	total = lt_stat_list_get_gtotal(list);
-
-	if (total == 0) {
-		return;
-	}
-
-	while (i < nlines && lt_stat_list_has_item(list, i)) {
-
-		char tmp[WIDTH_REASON_STRING];
-		const char *reason = lt_stat_list_get_reason(list, i);
-		uint64_t count = lt_stat_list_get_count(list, i);
-
-		if (count == 0) {
-			continue;
-		}
-
-		(void) snprintf(tmp, sizeof (tmp), "%s", reason);
-		(void) mvwprintw(window, i + begin_line, 0, "%s", tmp);
-
-		(void) snprintf(tmp, sizeof (tmp), "%llu", count);
-		fill_space_left(tmp, WIDTH_COUNT, sizeof (tmp));
-		(void) mvwprintw(window, i + begin_line, BEGIN_COUNT,
-		    "%s", tmp);
-
-		(void) mvwprintw(window, i + begin_line, BEGIN_AVG,
-		    "%s", get_time_string(
-		    (double)lt_stat_list_get_sum(list, i) / count,
-		    tmp, sizeof (tmp), WIDTH_AVG));
-
-		(void) mvwprintw(window, i + begin_line, BEGIN_MAX,
-		    "%s", get_time_string(
-		    (double)lt_stat_list_get_max(list, i),
-		    tmp, sizeof (tmp), WIDTH_MAX));
-
-		if (LT_LIST_SPECIALS != current_list_type) {
-			(void) snprintf(tmp, sizeof (tmp), "%.1f %%",
-			    (double)lt_stat_list_get_sum(list, i)
-			    / total * 100.0);
-		} else {
-			(void) snprintf(tmp, sizeof (tmp), "--- ");
-		}
-
-		fill_space_left(tmp, WIDTH_PCT, sizeof (tmp));
-
-		(void) mvwprintw(window, i + begin_line, BEGIN_PCT,
-		    "%s", tmp);
-		i++;
-	}
-}
-
-/*
- * Print statistics in global pane.
- */
-static void
-print_sysglobal(void)
-{
-	void *list;
-	char header[256];
-
-	if (!display_initialized) {
-		return;
-	}
-
-	(void) werase(sysglobal_window);
-
-	(void) wattron(sysglobal_window, A_REVERSE);
-	(void) snprintf(header, sizeof (header),
-	    "%s", "System wide latencies");
-	fill_space_right(header, screen_width, sizeof (header));
-	(void) mvwprintw(sysglobal_window, 0, 0, "%s", header);
-	(void) wattroff(sysglobal_window, A_REVERSE);
-
-	list = lt_stat_list_create(current_list_type,
-	    LT_LEVEL_GLOBAL, 0, 0, 10, sort_type);
-	print_statistics(sysglobal_window, 1, 10, list);
-	lt_stat_list_free(list);
-
-	(void) wrefresh(sysglobal_window);
-}
-
-/*
- * Prints current operation mode. Mode is combination of:
- *
- * 	"Process or Thread", and "1 or 2 or 3".
- */
-static void
-print_current_mode()
-{
-	char type;
-
-	if (!display_initialized) {
-		return;
-	}
-
-	switch (current_list_type) {
-	case LT_LIST_CAUSE:
-		type = '1';
-		break;
-	case LT_LIST_SPECIALS:
-		type = '2';
-		break;
-	case LT_LIST_SOBJ:
-		type = '3';
-		break;
-	default:
-		type = '?';
-		break;
-	}
-
-	(void) mvwprintw(process_window, 0, screen_width - 8, "View: %c%c",
-	    type, thread_mode ? 'T' : 'P');
-}
-
-/*
- * Print process window bar when the list is empty.
- */
-static void
-print_empty_process_bar()
-{
-	char header[256];
-
-	if (!display_initialized) {
-		return;
-	}
-
-	(void) werase(process_window);
-	(void) wattron(process_window, A_REVERSE);
-	(void) snprintf(header, sizeof (header),
-	    "No process/thread data is available");
-	fill_space_right(header, screen_width, sizeof (header));
-	(void) mvwprintw(process_window, 0, 0, "%s", header);
-
-	print_current_mode();
-	(void) wattroff(process_window, A_REVERSE);
-
-	(void) wrefresh(process_window);
-}
-
-/*
- * Print per-process statistics in process pane.
- * This is called when mode of operation is process.
- */
-static void
-print_process(unsigned int pid)
-{
-	void *list;
-	char header[256];
-	char tmp[30];
-
-	if (!display_initialized) {
-		return;
-	}
-
-	list = lt_stat_list_create(current_list_type, LT_LEVEL_PROCESS,
-	    pid, 0, 8, sort_type);
-
-	(void) werase(process_window);
-	(void) wattron(process_window, A_REVERSE);
-	(void) snprintf(header, sizeof (header), "Process %s (%i), %d threads",
-	    lt_stat_proc_get_name(pid), pid, lt_stat_proc_get_nthreads(pid));
-	fill_space_right(header, screen_width, sizeof (header));
-	(void) mvwprintw(process_window, 0, 0, "%s", header);
-
-	if (current_list_type != LT_LIST_SPECIALS) {
-		(void) mvwprintw(process_window, 0, 48, "Total: %s",
-		    get_time_string((double)lt_stat_list_get_gtotal(list),
-		    tmp, sizeof (tmp), 12));
-	}
-
-	print_current_mode();
-	(void) wattroff(process_window, A_REVERSE);
-	print_statistics(process_window, 1, 8, list);
-	lt_stat_list_free(list);
-
-	(void) wrefresh(process_window);
-}
-
-/*
- * Display the list of processes that are tracked, in task bar.
- * This one is called when mode of operation is process.
- */
-static void
-print_taskbar_process(pid_t *pidlist, int pidlist_len, int pidlist_index)
-{
-	const int ITEM_WIDTH = 8;
-
-	int number_item;
-	int i;
-	int xpos = 0;
-
-	if (!display_initialized) {
-		return;
-	}
-
-	number_item = (screen_width / ITEM_WIDTH) - 1;
-	i = pidlist_index - (pidlist_index % number_item);
-
-	(void) werase(taskbar);
-
-	if (i != 0) {
-		(void) mvwprintw(taskbar, 0, xpos, "<-");
-	}
-
-	xpos = ITEM_WIDTH / 2;
-
-	while (xpos + ITEM_WIDTH <= screen_width && i < pidlist_len) {
-		char str[ITEM_WIDTH+1];
-		int slen;
-		const char *pname = lt_stat_proc_get_name(pidlist[i]);
-
-		if (pname && pname[0]) {
-			(void) snprintf(str, sizeof (str) - 1, "%s", pname);
-		} else {
-			(void) snprintf(str, sizeof (str) - 1,
-			    "<%d>", pidlist[i]);
-		}
-
-		slen = strlen(str);
-
-		if (slen < ITEM_WIDTH) {
-			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
-		}
-
-		str[sizeof (str) - 1] = '\0';
-
-		if (i == pidlist_index) {
-			(void) wattron(taskbar, A_REVERSE);
-		}
-
-		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
-
-		if (i == pidlist_index) {
-			(void) wattroff(taskbar, A_REVERSE);
-		}
-
-		xpos += ITEM_WIDTH;
-		i++;
-	}
-
-	if (i != pidlist_len) {
-		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
-	}
-
-	(void) wrefresh(taskbar);
-}
-
-/*
- * Display the list of processes that are tracked, in task bar.
- * This one is called when mode of operation is thread.
- */
-static void
-print_taskbar_thread(pid_t *pidlist, id_t *tidlist, int list_len,
-    int list_index)
-{
-	const int ITEM_WIDTH = 12;
-
-	int number_item;
-	int i;
-	int xpos = 0;
-	const char *pname = NULL;
-	pid_t last_pid = INVALID_PID;
-
-
-	if (!display_initialized) {
-		return;
-	}
-
-	number_item = (screen_width - 8) / ITEM_WIDTH;
-	i = list_index - (list_index % number_item);
-
-	(void) werase(taskbar);
-
-	if (i != 0) {
-		(void) mvwprintw(taskbar, 0, xpos, "<-");
-	}
-
-	xpos = 4;
-
-	while (xpos + ITEM_WIDTH <= screen_width && i < list_len) {
-		char str[ITEM_WIDTH+1];
-		int slen, tlen;
-
-		if (pidlist[i] != last_pid) {
-			pname = lt_stat_proc_get_name(pidlist[i]);
-			last_pid = pidlist[i];
-		}
-
-		/*
-		 * Calculate length of thread's ID; use shorter process name
-		 * in order to save space on the screen.
-		 */
-		tlen = snprintf(NULL, 0, "_%d", tidlist[i]);
-
-		if (pname && pname[0]) {
-			(void) snprintf(str, sizeof (str) - tlen - 1,
-			    "%s", pname);
-		} else {
-			(void) snprintf(str, sizeof (str) - tlen - 1,
-			    "<%d>", pidlist[i]);
-		}
-
-		slen = strlen(str);
-
-		(void) snprintf(&str[slen], sizeof (str) - slen,
-		    "_%d", tidlist[i]);
-
-		slen += tlen;
-
-		if (slen < ITEM_WIDTH) {
-			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
-		}
-
-		str[sizeof (str) - 1] = '\0';
-
-		if (i == list_index) {
-			(void) wattron(taskbar, A_REVERSE);
-		}
-
-		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
-
-		if (i == list_index) {
-			(void) wattroff(taskbar, A_REVERSE);
-		}
-
-		xpos += ITEM_WIDTH;
-		i++;
-	}
-
-	if (i != list_len) {
-		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
-	}
-
-	(void) wrefresh(taskbar);
-}
-
-/*
- * Print per-thread statistics in process pane.
- * This is called when mode of operation is thread.
- */
-static void
-print_thread(pid_t pid, id_t tid)
-{
-	void *list;
-	char header[256];
-	char tmp[30];
-
-	if (!display_initialized) {
-		return;
-	}
-
-	list = lt_stat_list_create(current_list_type, LT_LEVEL_THREAD,
-	    pid, tid, 8, sort_type);
-
-	(void) werase(process_window);
-	(void) wattron(process_window, A_REVERSE);
-	(void) snprintf(header, sizeof (header),
-	    "Process %s (%i), LWP %d",
-	    lt_stat_proc_get_name(pid), pid, tid);
-	fill_space_right(header, screen_width, sizeof (header));
-	(void) mvwprintw(process_window, 0, 0, "%s", header);
-
-	if (current_list_type != LT_LIST_SPECIALS) {
-		(void) mvwprintw(process_window, 0, 48, "Total: %s",
-		    get_time_string(
-		    (double)lt_stat_list_get_gtotal(list),
-		    tmp, sizeof (tmp), 12));
-	}
-
-	print_current_mode();
-	(void) wattroff(process_window, A_REVERSE);
-	print_statistics(process_window, 1, 8, list);
-	lt_stat_list_free(list);
-	(void) wrefresh(process_window);
-}
-
-/*
- * Update hint string at the bottom line. The message to print is stored in
- * hint. If hint is NULL, the function will display its own message.
- */
-static void
-print_hint(const char *hint)
-{
-	const char *HINTS[] =    {
-		"Press '<' or '>' to switch between processes.",
-		"Press 'q' to exit.",
-		"Press 'r' to refresh immediately.",
-		"Press 't' to toggle Process/Thread display mode.",
-		"Press 'h' for help.",
-		"Use 'c', 'a', 'm', 'p' to change sort criteria.",
-		"Use '1', '2', '3' to switch between windows."
-	};
-	const uint64_t update_interval = 5000; /* 5 seconds */
-
-	static int index = 0;
-	static uint64_t next_hint = 0;
-	uint64_t now = lt_millisecond();
-
-	if (!display_initialized) {
-		return;
-	}
-
-	if (hint == NULL) {
-		if (now < next_hint) {
-			return;
-		}
-
-		hint = HINTS[index];
-		index = (index + 1) % (sizeof (HINTS) / sizeof (HINTS[0]));
-		next_hint = now + update_interval;
-	} else {
-		/*
-		 * Important messages are displayed at least every 2 cycles.
-		 */
-		next_hint = now + update_interval * 2;
-	}
-
-	(void) werase(hintbar);
-	(void) mvwprintw(hintbar, 0, (screen_width - strlen(hint)) / 2,
-	    "%s", hint);
-	(void) wrefresh(hintbar);
-}
-
-/*
- * Create a PID list or a PID/TID list (if operation mode is thread) from
- * available statistics.
- */
-static void
-get_plist(pid_t **plist, id_t **tlist, int *list_len, int *list_index)
-{
-	if (!thread_mode) {
-		/* Per-process mode */
-		*list_len = lt_stat_proc_list_create(plist, NULL);
-		/* Search for previously selected PID */
-		for (*list_index = 0; *list_index < *list_len &&
-		    (*plist)[*list_index] != selected_pid;
-		    ++*list_index) {
-		}
-
-		if (*list_index >= *list_len) {
-			/*
-			 * The previously selected pid is gone.
-			 * Select the first one.
-			 */
-			*list_index = 0;
-		}
-	} else {
-		/* Per-thread mode */
-		*list_len = lt_stat_proc_list_create(plist, tlist);
-
-		/* Search for previously selected PID & TID */
-		for (*list_index = 0; *list_index < *list_len;
-		    ++*list_index) {
-			if ((*plist)[*list_index] == selected_pid &&
-			    (*tlist)[*list_index] == selected_tid) {
-				break;
-			}
-		}
-
-		if (*list_index >= *list_len) {
-			/*
-			 * The previously selected pid/tid is gone.
-			 * Select the first one.
-			 */
-			for (*list_index = 0;
-			    *list_index < *list_len &&
-			    (*plist)[*list_index] != selected_pid;
-			    ++*list_index) {
-			}
-		}
-
-		if (*list_index >= *list_len) {
-			/*
-			 * The previously selected pid is gone.
-			 * Select the first one
-			 */
-			*list_index = 0;
-		}
-	}
-}
-
-/* Print help message when user presses 'h' hot key */
-static void
-print_help(void)
-{
-	const char *HELP[] =    {
-		TITLE,
-		COPYRIGHT,
-		"",
-		"These single-character commands are available:",
-		"<       - Move to previous process/thread.",
-		">       - Move to next process/thread.",
-		"q       - Exit.",
-		"r       - Refresh.",
-		"t       - Toggle process/thread mode.",
-		"c       - Sort by count.",
-		"a       - Sort by average.",
-		"m       - Sort by maximum.",
-		"p       - Sort by percent.",
-		"1       - Show list by causes.",
-		"2       - Show list of special entries.",
-		"3       - Show list by synchronization objects.",
-		"h       - Show this help.",
-		"",
-		"Press any key to continue..."
-	};
-	int i;
-
-	if (!display_initialized) {
-		return;
-	}
-
-	for (i = 0; i < sizeof (HELP) / sizeof (HELP[0]); ++i) {
-		(void) mvwprintw(stdscr, i, 0, "%s", HELP[i]);
-	}
-
-	(void) refresh();
-}
-
-/*
- * Print title on screen
- */
-static void
-print_title(void)
-{
-	if (!display_initialized) {
-		return;
-	}
-
-	(void) wattrset(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
-	(void) wbkgd(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
-	(void) werase(titlebar);
-
-	(void) mvwprintw(titlebar, 0, (screen_width - strlen(TITLE)) / 2,
-	    "%s", TITLE);
-	(void) wrefresh(titlebar);
-
-	(void) werase(captionbar);
-	(void) mvwprintw(captionbar, 0, 0, "%s",
-	    "               Cause                    "
-	    "Count      Average     Maximum   Percent");
-	(void) wrefresh(captionbar);
-
-	(void) wattrset(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
-	(void) wbkgd(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
-}
-
-/*
- * Handle signal from terminal resize
- */
-/* ARGSUSED */
-static void
-on_resize(int sig)
-{
-	lt_gpipe_break("r");
-}
-
-/*
- * Initialize display. Display will be cleared when this function returns.
- */
-void
-lt_display_init(void)
-{
-	if (display_initialized) {
-		return;
-	}
-
-	/* Window resize signal */
-	(void) signal(SIGWINCH, on_resize);
-
-	/* Initialize curses library */
-	(void) initscr();
-	(void) start_color();
-	(void) keypad(stdscr, TRUE);
-	(void) nonl();
-	(void) cbreak();
-	(void) noecho();
-	(void) curs_set(0);
-
-	/* Set up color pairs */
-	(void) init_pair(LT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
-	(void) init_pair(LT_COLOR_HEADER, COLOR_BLACK, COLOR_WHITE);
-
-	curses_inited = TRUE;
-	getmaxyx(stdscr, screen_height, screen_width);
-
-	if (screen_width < LT_WINDOW_X || screen_height < LT_WINDOW_Y) {
-		(void) mvwprintw(stdscr, 0, 0, "Terminal size is too small.");
-		(void) mvwprintw(stdscr, 1, 0,
-		    "Please resize it to 80x24 or larger.");
-		(void) mvwprintw(stdscr, 2, 0, "Press q to quit.");
-		(void) refresh();
-		return;
-	}
-
-	/* Set up all window panes */
-	titlebar = subwin(stdscr, 1, screen_width, 0, 0);
-	captionbar = subwin(stdscr, 1, screen_width, 1, 0);
-	sysglobal_window = subwin(stdscr, screen_height / 2 - 1,
-	    screen_width, 2, 0);
-	process_window = subwin(stdscr, screen_height / 2 - 3,
-	    screen_width, screen_height / 2 + 1, 0);
-	taskbar = subwin(stdscr, 1, screen_width, screen_height - 2, 0);
-	hintbar = subwin(stdscr, 1, screen_width, screen_height - 1, 0);
-	(void) werase(stdscr);
-	(void) refresh();
-
-	display_initialized = TRUE;
-
-	print_title();
-}
-
-/*
- * The event loop for display. It displays data on screen and handles hotkey
- * presses.
- *
- * Parameter :
- *		duration - returns after 'duration'
- *
- * The function also returns if user presses 'q', 'Ctrl+C' or 'r'.
- *
- * Return value:
- *		0 - main() exits
- *		1 - main() calls it again
- */
-int
-lt_display_loop(int duration)
-{
-	uint64_t start;
-	int remaining;
-	struct timeval timeout;
-	fd_set read_fd;
-	int need_refresh = TRUE;
-	pid_t *plist = NULL;
-	id_t *tlist = NULL;
-	int list_len = 0;
-	int list_index = 0;
-	int retval = 1;
-	int next_snap;
-	int gpipe;
-
-	start = lt_millisecond();
-	gpipe = lt_gpipe_readfd();
-
-	if (!show_help) {
-		print_hint(NULL);
-		print_sysglobal();
-	}
-
-	get_plist(&plist, &tlist, &list_len, &list_index);
-
-	for (;;) {
-		if (need_refresh && !show_help) {
-			if (list_len != 0) {
-				if (!thread_mode) {
-					print_taskbar_process(plist, list_len,
-					    list_index);
-					print_process(plist[list_index]);
-				} else {
-					print_taskbar_thread(plist, tlist,
-					    list_len, list_index);
-					print_thread(plist[list_index],
-					    tlist[list_index]);
-				}
-			} else {
-				print_empty_process_bar();
-			}
-		}
-
-		need_refresh = TRUE;	/* Usually we need refresh. */
-		remaining = duration - (int)(lt_millisecond() - start);
-
-		if (remaining <= 0) {
-			break;
-		}
-
-		/* Embedded dtrace snap action here. */
-		next_snap = lt_dtrace_work(0);
-
-		if (next_snap == 0) {
-			/*
-			 * Just did a snap, check time for the next one.
-			 */
-			next_snap = lt_dtrace_work(0);
-		}
-
-		if (next_snap > 0 && remaining > next_snap) {
-			remaining = next_snap;
-		}
-
-		timeout.tv_sec = remaining / 1000;
-		timeout.tv_usec = (remaining % 1000) * 1000;
-
-		FD_ZERO(&read_fd);
-		FD_SET(0, &read_fd);
-		FD_SET(gpipe, &read_fd);
-
-		/* Wait for keyboard input, or signal from gpipe */
-		if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
-			int k = 0;
-
-			if (FD_ISSET(gpipe, &read_fd)) {
-				/* Data from pipe has priority */
-				char ch;
-				(void) read(gpipe, &ch, 1);
-				k = ch; /* Need this for big-endianness */
-			} else {
-				k = getch();
-			}
-
-			/*
-			 * Check if we need to update the hint line whenever we
-			 * get a chance.
-			 * NOTE: current implementation depends on
-			 * g_config.lt_cfg_snap_interval, but it's OK because it
-			 * doesn't have to be precise.
-			 */
-			print_hint(NULL);
-			/*
-			 * If help is on display right now, and a key press
-			 * happens, we need to clear the help and continue.
-			 */
-			if (show_help) {
-				(void) werase(stdscr);
-				(void) refresh();
-				print_title();
-				print_sysglobal();
-				show_help = FALSE;
-				/* Drop this key and continue */
-				continue;
-			}
-
-			switch (k) {
-			case 'Q':
-			case 'q':
-				retval = 0;
-				goto quit;
-			case 'R':
-			case 'r':
-				lt_display_deinit();
-				lt_display_init();
-				goto quit;
-			case 'H':
-			case 'h':
-				show_help = TRUE;
-				(void) werase(stdscr);
-				(void) refresh();
-				print_help();
-				break;
-			case ',':
-			case '<':
-			case KEY_LEFT:
-				--list_index;
-
-				if (list_index < 0) {
-					list_index = 0;
-				}
-
-				break;
-			case '.':
-			case '>':
-			case KEY_RIGHT:
-				++list_index;
-
-				if (list_index >= list_len) {
-					list_index = list_len - 1;
-				}
-
-				break;
-			case 'a':
-			case 'A':
-				sort_type = LT_SORT_AVG;
-				print_sysglobal();
-				break;
-			case 'p':
-			case 'P':
-				sort_type = LT_SORT_TOTAL;
-				print_sysglobal();
-				break;
-			case 'm':
-			case 'M':
-				sort_type = LT_SORT_MAX;
-				print_sysglobal();
-				break;
-			case 'c':
-			case 'C':
-				sort_type = LT_SORT_COUNT;
-				print_sysglobal();
-				break;
-			case 't':
-			case 'T':
-				if (plist != NULL) {
-					selected_pid = plist[list_index];
-				}
-
-				selected_tid = INVALID_TID;
-				thread_mode = !thread_mode;
-				get_plist(&plist, &tlist,
-				    &list_len, &list_index);
-				break;
-			case '1':
-			case '!':
-				current_list_type = LT_LIST_CAUSE;
-				print_sysglobal();
-				break;
-			case '2':
-			case '@':
-				if (g_config.lt_cfg_low_overhead_mode) {
-					lt_display_error("Switching mode is "
-					    "not available for '-f low'.");
-				} else {
-					current_list_type = LT_LIST_SPECIALS;
-					print_sysglobal();
-				}
-
-				break;
-			case '3':
-			case '#':
-				if (g_config.lt_cfg_trace_syncobj) {
-					current_list_type = LT_LIST_SOBJ;
-					print_sysglobal();
-				} else if (g_config.lt_cfg_low_overhead_mode) {
-					lt_display_error("Switching mode is "
-					    "not available for '-f low'.");
-				} else {
-					lt_display_error("Tracing "
-					    "synchronization objects is "
-					    "disabled.");
-				}
-
-				break;
-			default:
-				/* Wake up for nothing; no refresh is needed */
-				need_refresh = FALSE;
-				break;
-			}
-		} else {
-			need_refresh = FALSE;
-		}
-	}
-
-quit:
-	if (plist != NULL) {
-		selected_pid = plist[list_index];
-	}
-
-	if (tlist != NULL) {
-		selected_tid = tlist[list_index];
-	}
-
-	lt_stat_proc_list_free(plist, tlist);
-
-	return (retval);
-}
-
-/*
- * Clean up display.
- */
-void
-lt_display_deinit(void)
-{
-	if (curses_inited) {
-		(void) clear();
-		(void) refresh();
-		(void) endwin();
-	}
-
-	titlebar = NULL;
-	captionbar = NULL;
-	sysglobal_window = NULL;
-	taskbar = NULL;
-	process_window = NULL;
-	hintbar = NULL;
-	screen_width = 1;
-	screen_height = 1;
-
-	display_initialized = FALSE;
-	curses_inited = FALSE;
-}
-
-/*
- * Print message when display error happens.
- */
-/* ARGSUSED */
-void
-lt_display_error(const char *fmt, ...)
-{
-	va_list vl;
-	char tmp[81];
-	int l;
-
-	va_start(vl, fmt);
-	(void) vsnprintf(tmp, sizeof (tmp), fmt, vl);
-	va_end(vl);
-
-	l = strlen(tmp);
-
-	while (l > 0 && (tmp[l - 1] == '\n' || tmp[l - 1] == '\r')) {
-		tmp[l - 1] = '\0';
-		--l;
-	}
-
-	if (!display_initialized) {
-		(void) fprintf(stderr, "%s\n", tmp);
-	} else if (!show_help) {
-		print_hint(tmp);
-	}
-
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/display.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,1068 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <curses.h>
+#include <time.h>
+#include <wchar.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include "latencytop.h"
+
+#define	LT_WINDOW_X			80
+#define	LT_WINDOW_Y			24
+
+#define	LT_COLOR_DEFAULT		1
+#define	LT_COLOR_HEADER			2
+
+/* Windows created by libcurses */
+static WINDOW	*titlebar = NULL;
+static WINDOW	*captionbar = NULL;
+static WINDOW	*sysglobal_window = NULL;
+static WINDOW	*taskbar = NULL;
+static WINDOW	*process_window = NULL;
+static WINDOW	*hintbar = NULL;
+/* Screen dimension */
+static int	screen_width = 1, screen_height = 1;
+/* Is display initialized, i.e. are window pointers set up. */
+static int	display_initialized = FALSE;
+/* Is initscr() called */
+static int	curses_inited = FALSE;
+
+/* To handle user key presses */
+static pid_t selected_pid = INVALID_PID;
+static id_t selected_tid = INVALID_TID;
+static lt_sort_t sort_type = LT_SORT_TOTAL;
+static int thread_mode = FALSE;
+/* Type of list being displayed */
+static int current_list_type = LT_LIST_CAUSE;
+static int show_help = FALSE;
+
+/* Help functions that append/prepend a blank to the given string */
+#define	fill_space_right(a, b, c)	fill_space((a), (b), (c), TRUE)
+#define	fill_space_left(a, b, c)	fill_space((a), (b), (c), FALSE)
+
+static void
+fill_space(char *buffer, int len, int buffer_limit, int is_right)
+{
+	int i = 0;
+	int tofill;
+
+	if (len >= buffer_limit) {
+		len = buffer_limit - 1;
+	}
+
+	i = strlen(buffer);
+
+	if (i >= len) {
+		return;
+	}
+
+	tofill = len - i;
+
+	if (is_right) {
+		(void) memset(&buffer[i], ' ', tofill);
+		buffer[len] = '\0';
+	} else {
+		(void) memmove(&buffer[tofill], buffer, i+1);
+		(void) memset(buffer, ' ', tofill);
+	}
+}
+
+/* Convert the nanosecond value to a human readable string */
+static const char *
+get_time_string(double nanoseconds, char *buffer, int len, int fill_width)
+{
+	const double ONE_USEC = 1000.0;
+	const double ONE_MSEC = 1000000.0;
+	const double ONE_SEC  = 1000000000.0;
+
+	if (nanoseconds < (ONE_USEC - .5)) {
+		(void) snprintf(buffer, len, "%3.1f nsec", nanoseconds);
+	} else if (nanoseconds < (ONE_MSEC - .5 * ONE_USEC)) {
+		(void) snprintf(buffer, len,
+		    "%3.1f usec", nanoseconds / ONE_USEC);
+	} else if (nanoseconds < (ONE_SEC - .5 * ONE_MSEC)) {
+		(void) snprintf(buffer, len,
+		    "%3.1f msec", nanoseconds / ONE_MSEC);
+	} else if (nanoseconds < 999.5 * ONE_SEC) {
+		(void) snprintf(buffer, len,
+		    "%3.1f  sec", nanoseconds / ONE_SEC);
+	} else {
+		(void) snprintf(buffer, len,
+		    "%.0e sec", nanoseconds / ONE_SEC);
+	}
+
+	fill_space_left(buffer, fill_width, len);
+	return (buffer);
+}
+
+/* Used in print_statistics below */
+#define	WIDTH_REASON_STRING	36
+#define	WIDTH_COUNT		12
+#define	WIDTH_AVG		12
+#define	WIDTH_MAX		12
+#define	WIDTH_PCT		8
+#define	BEGIN_COUNT		WIDTH_REASON_STRING
+#define	BEGIN_AVG		(BEGIN_COUNT + WIDTH_COUNT)
+#define	BEGIN_MAX		(BEGIN_AVG + WIDTH_AVG)
+#define	BEGIN_PCT		(BEGIN_MAX + WIDTH_MAX)
+
+/*
+ * Print statistics in global/process pane. Called by print_sysglobal
+ * print_process.
+ *
+ * Parameters:
+ *		window - the global or process statistics window.
+ *		begin_line - where to start printing.
+ *		count - how many lines should be printed.
+ *		list - a stat_list.
+ */
+static void
+print_statistics(WINDOW * window, int begin_line, int nlines, void *list)
+{
+	uint64_t total;
+	int i = 0;
+
+	if (!display_initialized) {
+		return;
+	}
+
+	total = lt_stat_list_get_gtotal(list);
+
+	if (total == 0) {
+		return;
+	}
+
+	while (i < nlines && lt_stat_list_has_item(list, i)) {
+
+		char tmp[WIDTH_REASON_STRING];
+		const char *reason = lt_stat_list_get_reason(list, i);
+		uint64_t count = lt_stat_list_get_count(list, i);
+
+		if (count == 0) {
+			continue;
+		}
+
+		(void) snprintf(tmp, sizeof (tmp), "%s", reason);
+		(void) mvwprintw(window, i + begin_line, 0, "%s", tmp);
+
+		(void) snprintf(tmp, sizeof (tmp), "%llu", count);
+		fill_space_left(tmp, WIDTH_COUNT, sizeof (tmp));
+		(void) mvwprintw(window, i + begin_line, BEGIN_COUNT,
+		    "%s", tmp);
+
+		(void) mvwprintw(window, i + begin_line, BEGIN_AVG,
+		    "%s", get_time_string(
+		    (double)lt_stat_list_get_sum(list, i) / count,
+		    tmp, sizeof (tmp), WIDTH_AVG));
+
+		(void) mvwprintw(window, i + begin_line, BEGIN_MAX,
+		    "%s", get_time_string(
+		    (double)lt_stat_list_get_max(list, i),
+		    tmp, sizeof (tmp), WIDTH_MAX));
+
+		if (LT_LIST_SPECIALS != current_list_type) {
+			(void) snprintf(tmp, sizeof (tmp), "%.1f %%",
+			    (double)lt_stat_list_get_sum(list, i)
+			    / total * 100.0);
+		} else {
+			(void) snprintf(tmp, sizeof (tmp), "--- ");
+		}
+
+		fill_space_left(tmp, WIDTH_PCT, sizeof (tmp));
+
+		(void) mvwprintw(window, i + begin_line, BEGIN_PCT,
+		    "%s", tmp);
+		i++;
+	}
+}
+
+/*
+ * Print statistics in global pane.
+ */
+static void
+print_sysglobal(void)
+{
+	void *list;
+	char header[256];
+
+	if (!display_initialized) {
+		return;
+	}
+
+	(void) werase(sysglobal_window);
+
+	(void) wattron(sysglobal_window, A_REVERSE);
+	(void) snprintf(header, sizeof (header),
+	    "%s", "System wide latencies");
+	fill_space_right(header, screen_width, sizeof (header));
+	(void) mvwprintw(sysglobal_window, 0, 0, "%s", header);
+	(void) wattroff(sysglobal_window, A_REVERSE);
+
+	list = lt_stat_list_create(current_list_type,
+	    LT_LEVEL_GLOBAL, 0, 0, 10, sort_type);
+	print_statistics(sysglobal_window, 1, 10, list);
+	lt_stat_list_free(list);
+
+	(void) wrefresh(sysglobal_window);
+}
+
+/*
+ * Prints current operation mode. Mode is combination of:
+ *
+ *	"Process or Thread", and "1 or 2 or 3".
+ */
+static void
+print_current_mode()
+{
+	char type;
+
+	if (!display_initialized) {
+		return;
+	}
+
+	switch (current_list_type) {
+	case LT_LIST_CAUSE:
+		type = '1';
+		break;
+	case LT_LIST_SPECIALS:
+		type = '2';
+		break;
+	case LT_LIST_SOBJ:
+		type = '3';
+		break;
+	default:
+		type = '?';
+		break;
+	}
+
+	(void) mvwprintw(process_window, 0, screen_width - 8, "View: %c%c",
+	    type, thread_mode ? 'T' : 'P');
+}
+
+/*
+ * Print process window bar when the list is empty.
+ */
+static void
+print_empty_process_bar()
+{
+	char header[256];
+
+	if (!display_initialized) {
+		return;
+	}
+
+	(void) werase(process_window);
+	(void) wattron(process_window, A_REVERSE);
+	(void) snprintf(header, sizeof (header),
+	    "No process/thread data is available");
+	fill_space_right(header, screen_width, sizeof (header));
+	(void) mvwprintw(process_window, 0, 0, "%s", header);
+
+	print_current_mode();
+	(void) wattroff(process_window, A_REVERSE);
+
+	(void) wrefresh(process_window);
+}
+
+/*
+ * Print per-process statistics in process pane.
+ * This is called when mode of operation is process.
+ */
+static void
+print_process(unsigned int pid)
+{
+	void *list;
+	char header[256];
+	char tmp[30];
+
+	if (!display_initialized) {
+		return;
+	}
+
+	list = lt_stat_list_create(current_list_type, LT_LEVEL_PROCESS,
+	    pid, 0, 8, sort_type);
+
+	(void) werase(process_window);
+	(void) wattron(process_window, A_REVERSE);
+	(void) snprintf(header, sizeof (header), "Process %s (%i), %d threads",
+	    lt_stat_proc_get_name(pid), pid, lt_stat_proc_get_nthreads(pid));
+	fill_space_right(header, screen_width, sizeof (header));
+	(void) mvwprintw(process_window, 0, 0, "%s", header);
+
+	if (current_list_type != LT_LIST_SPECIALS) {
+		(void) mvwprintw(process_window, 0, 48, "Total: %s",
+		    get_time_string((double)lt_stat_list_get_gtotal(list),
+		    tmp, sizeof (tmp), 12));
+	}
+
+	print_current_mode();
+	(void) wattroff(process_window, A_REVERSE);
+	print_statistics(process_window, 1, 8, list);
+	lt_stat_list_free(list);
+
+	(void) wrefresh(process_window);
+}
+
+/*
+ * Display the list of processes that are tracked, in task bar.
+ * This one is called when mode of operation is process.
+ */
+static void
+print_taskbar_process(pid_t *pidlist, int pidlist_len, int pidlist_index)
+{
+	const int ITEM_WIDTH = 8;
+
+	int number_item;
+	int i;
+	int xpos = 0;
+
+	if (!display_initialized) {
+		return;
+	}
+
+	number_item = (screen_width / ITEM_WIDTH) - 1;
+	i = pidlist_index - (pidlist_index % number_item);
+
+	(void) werase(taskbar);
+
+	if (i != 0) {
+		(void) mvwprintw(taskbar, 0, xpos, "<-");
+	}
+
+	xpos = ITEM_WIDTH / 2;
+
+	while (xpos + ITEM_WIDTH <= screen_width && i < pidlist_len) {
+		char str[ITEM_WIDTH+1];
+		int slen;
+		const char *pname = lt_stat_proc_get_name(pidlist[i]);
+
+		if (pname && pname[0]) {
+			(void) snprintf(str, sizeof (str) - 1, "%s", pname);
+		} else {
+			(void) snprintf(str, sizeof (str) - 1,
+			    "<%d>", pidlist[i]);
+		}
+
+		slen = strlen(str);
+
+		if (slen < ITEM_WIDTH) {
+			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
+		}
+
+		str[sizeof (str) - 1] = '\0';
+
+		if (i == pidlist_index) {
+			(void) wattron(taskbar, A_REVERSE);
+		}
+
+		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
+
+		if (i == pidlist_index) {
+			(void) wattroff(taskbar, A_REVERSE);
+		}
+
+		xpos += ITEM_WIDTH;
+		i++;
+	}
+
+	if (i != pidlist_len) {
+		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
+	}
+
+	(void) wrefresh(taskbar);
+}
+
+/*
+ * Display the list of processes that are tracked, in task bar.
+ * This one is called when mode of operation is thread.
+ */
+static void
+print_taskbar_thread(pid_t *pidlist, id_t *tidlist, int list_len,
+    int list_index)
+{
+	const int ITEM_WIDTH = 12;
+
+	int number_item;
+	int i;
+	int xpos = 0;
+	const char *pname = NULL;
+	pid_t last_pid = INVALID_PID;
+
+
+	if (!display_initialized) {
+		return;
+	}
+
+	number_item = (screen_width - 8) / ITEM_WIDTH;
+	i = list_index - (list_index % number_item);
+
+	(void) werase(taskbar);
+
+	if (i != 0) {
+		(void) mvwprintw(taskbar, 0, xpos, "<-");
+	}
+
+	xpos = 4;
+
+	while (xpos + ITEM_WIDTH <= screen_width && i < list_len) {
+		char str[ITEM_WIDTH+1];
+		int slen, tlen;
+
+		if (pidlist[i] != last_pid) {
+			pname = lt_stat_proc_get_name(pidlist[i]);
+			last_pid = pidlist[i];
+		}
+
+		/*
+		 * Calculate length of thread's ID; use shorter process name
+		 * in order to save space on the screen.
+		 */
+		tlen = snprintf(NULL, 0, "_%d", tidlist[i]);
+
+		if (pname && pname[0]) {
+			(void) snprintf(str, sizeof (str) - tlen - 1,
+			    "%s", pname);
+		} else {
+			(void) snprintf(str, sizeof (str) - tlen - 1,
+			    "<%d>", pidlist[i]);
+		}
+
+		slen = strlen(str);
+
+		(void) snprintf(&str[slen], sizeof (str) - slen,
+		    "_%d", tidlist[i]);
+
+		slen += tlen;
+
+		if (slen < ITEM_WIDTH) {
+			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
+		}
+
+		str[sizeof (str) - 1] = '\0';
+
+		if (i == list_index) {
+			(void) wattron(taskbar, A_REVERSE);
+		}
+
+		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
+
+		if (i == list_index) {
+			(void) wattroff(taskbar, A_REVERSE);
+		}
+
+		xpos += ITEM_WIDTH;
+		i++;
+	}
+
+	if (i != list_len) {
+		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
+	}
+
+	(void) wrefresh(taskbar);
+}
+
+/*
+ * Print per-thread statistics in process pane.
+ * This is called when mode of operation is thread.
+ */
+static void
+print_thread(pid_t pid, id_t tid)
+{
+	void *list;
+	char header[256];
+	char tmp[30];
+
+	if (!display_initialized) {
+		return;
+	}
+
+	list = lt_stat_list_create(current_list_type, LT_LEVEL_THREAD,
+	    pid, tid, 8, sort_type);
+
+	(void) werase(process_window);
+	(void) wattron(process_window, A_REVERSE);
+	(void) snprintf(header, sizeof (header),
+	    "Process %s (%i), LWP %d",
+	    lt_stat_proc_get_name(pid), pid, tid);
+	fill_space_right(header, screen_width, sizeof (header));
+	(void) mvwprintw(process_window, 0, 0, "%s", header);
+
+	if (current_list_type != LT_LIST_SPECIALS) {
+		(void) mvwprintw(process_window, 0, 48, "Total: %s",
+		    get_time_string(
+		    (double)lt_stat_list_get_gtotal(list),
+		    tmp, sizeof (tmp), 12));
+	}
+
+	print_current_mode();
+	(void) wattroff(process_window, A_REVERSE);
+	print_statistics(process_window, 1, 8, list);
+	lt_stat_list_free(list);
+	(void) wrefresh(process_window);
+}
+
+/*
+ * Update hint string at the bottom line. The message to print is stored in
+ * hint. If hint is NULL, the function will display its own message.
+ */
+static void
+print_hint(const char *hint)
+{
+	const char *HINTS[] =    {
+		"Press '<' or '>' to switch between processes.",
+		"Press 'q' to exit.",
+		"Press 'r' to refresh immediately.",
+		"Press 't' to toggle Process/Thread display mode.",
+		"Press 'h' for help.",
+		"Use 'c', 'a', 'm', 'p' to change sort criteria.",
+		"Use '1', '2', '3' to switch between windows."
+	};
+	const uint64_t update_interval = 5000; /* 5 seconds */
+
+	static int index = 0;
+	static uint64_t next_hint = 0;
+	uint64_t now = lt_millisecond();
+
+	if (!display_initialized) {
+		return;
+	}
+
+	if (hint == NULL) {
+		if (now < next_hint) {
+			return;
+		}
+
+		hint = HINTS[index];
+		index = (index + 1) % (sizeof (HINTS) / sizeof (HINTS[0]));
+		next_hint = now + update_interval;
+	} else {
+		/*
+		 * Important messages are displayed at least every 2 cycles.
+		 */
+		next_hint = now + update_interval * 2;
+	}
+
+	(void) werase(hintbar);
+	(void) mvwprintw(hintbar, 0, (screen_width - strlen(hint)) / 2,
+	    "%s", hint);
+	(void) wrefresh(hintbar);
+}
+
+/*
+ * Create a PID list or a PID/TID list (if operation mode is thread) from
+ * available statistics.
+ */
+static void
+get_plist(pid_t **plist, id_t **tlist, int *list_len, int *list_index)
+{
+	if (!thread_mode) {
+		/* Per-process mode */
+		*list_len = lt_stat_proc_list_create(plist, NULL);
+		/* Search for previously selected PID */
+		for (*list_index = 0; *list_index < *list_len &&
+		    (*plist)[*list_index] != selected_pid;
+		    ++*list_index) {
+		}
+
+		if (*list_index >= *list_len) {
+			/*
+			 * The previously selected pid is gone.
+			 * Select the first one.
+			 */
+			*list_index = 0;
+		}
+	} else {
+		/* Per-thread mode */
+		*list_len = lt_stat_proc_list_create(plist, tlist);
+
+		/* Search for previously selected PID & TID */
+		for (*list_index = 0; *list_index < *list_len;
+		    ++*list_index) {
+			if ((*plist)[*list_index] == selected_pid &&
+			    (*tlist)[*list_index] == selected_tid) {
+				break;
+			}
+		}
+
+		if (*list_index >= *list_len) {
+			/*
+			 * The previously selected pid/tid is gone.
+			 * Select the first one.
+			 */
+			for (*list_index = 0;
+			    *list_index < *list_len &&
+			    (*plist)[*list_index] != selected_pid;
+			    ++*list_index) {
+			}
+		}
+
+		if (*list_index >= *list_len) {
+			/*
+			 * The previously selected pid is gone.
+			 * Select the first one
+			 */
+			*list_index = 0;
+		}
+	}
+}
+
+/* Print help message when user presses 'h' hot key */
+static void
+print_help(void)
+{
+	const char *HELP[] =    {
+		TITLE,
+		COPYRIGHT,
+		"",
+		"These single-character commands are available:",
+		"<       - Move to previous process/thread.",
+		">       - Move to next process/thread.",
+		"q       - Exit.",
+		"r       - Refresh.",
+		"t       - Toggle process/thread mode.",
+		"c       - Sort by count.",
+		"a       - Sort by average.",
+		"m       - Sort by maximum.",
+		"p       - Sort by percent.",
+		"1       - Show list by causes.",
+		"2       - Show list of special entries.",
+		"3       - Show list by synchronization objects.",
+		"h       - Show this help.",
+		"",
+		"Press any key to continue..."
+	};
+	int i;
+
+	if (!display_initialized) {
+		return;
+	}
+
+	for (i = 0; i < sizeof (HELP) / sizeof (HELP[0]); ++i) {
+		(void) mvwprintw(stdscr, i, 0, "%s", HELP[i]);
+	}
+
+	(void) refresh();
+}
+
+/*
+ * Print title on screen
+ */
+static void
+print_title(void)
+{
+	if (!display_initialized) {
+		return;
+	}
+
+	(void) wattrset(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
+	(void) wbkgd(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
+	(void) werase(titlebar);
+
+	(void) mvwprintw(titlebar, 0, (screen_width - strlen(TITLE)) / 2,
+	    "%s", TITLE);
+	(void) wrefresh(titlebar);
+
+	(void) werase(captionbar);
+	(void) mvwprintw(captionbar, 0, 0, "%s",
+	    "               Cause                    "
+	    "Count      Average     Maximum   Percent");
+	(void) wrefresh(captionbar);
+
+	(void) wattrset(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
+	(void) wbkgd(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
+}
+
+/*
+ * Handle signal from terminal resize
+ */
+/* ARGSUSED */
+static void
+on_resize(int sig)
+{
+	lt_gpipe_break("r");
+}
+
+/*
+ * Initialize display. Display will be cleared when this function returns.
+ */
+void
+lt_display_init(void)
+{
+	if (display_initialized) {
+		return;
+	}
+
+	/* Window resize signal */
+	(void) signal(SIGWINCH, on_resize);
+
+	/* Initialize curses library */
+	(void) initscr();
+	(void) start_color();
+	(void) keypad(stdscr, TRUE);
+	(void) nonl();
+	(void) cbreak();
+	(void) noecho();
+	(void) curs_set(0);
+
+	/* Set up color pairs */
+	(void) init_pair(LT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
+	(void) init_pair(LT_COLOR_HEADER, COLOR_BLACK, COLOR_WHITE);
+
+	curses_inited = TRUE;
+	getmaxyx(stdscr, screen_height, screen_width);
+
+	if (screen_width < LT_WINDOW_X || screen_height < LT_WINDOW_Y) {
+		(void) mvwprintw(stdscr, 0, 0, "Terminal size is too small.");
+		(void) mvwprintw(stdscr, 1, 0,
+		    "Please resize it to 80x24 or larger.");
+		(void) mvwprintw(stdscr, 2, 0, "Press q to quit.");
+		(void) refresh();
+		return;
+	}
+
+	/* Set up all window panes */
+	titlebar = subwin(stdscr, 1, screen_width, 0, 0);
+	captionbar = subwin(stdscr, 1, screen_width, 1, 0);
+	sysglobal_window = subwin(stdscr, screen_height / 2 - 1,
+	    screen_width, 2, 0);
+	process_window = subwin(stdscr, screen_height / 2 - 3,
+	    screen_width, screen_height / 2 + 1, 0);
+	taskbar = subwin(stdscr, 1, screen_width, screen_height - 2, 0);
+	hintbar = subwin(stdscr, 1, screen_width, screen_height - 1, 0);
+	(void) werase(stdscr);
+	(void) refresh();
+
+	display_initialized = TRUE;
+
+	print_title();
+}
+
+/*
+ * The event loop for display. It displays data on screen and handles hotkey
+ * presses.
+ *
+ * Parameter :
+ *		duration - returns after 'duration'
+ *
+ * The function also returns if user presses 'q', 'Ctrl+C' or 'r'.
+ *
+ * Return value:
+ *		0 - main() exits
+ *		1 - main() calls it again
+ */
+int
+lt_display_loop(int duration)
+{
+	uint64_t start;
+	int remaining;
+	struct timeval timeout;
+	fd_set read_fd;
+	int need_refresh = TRUE;
+	pid_t *plist = NULL;
+	id_t *tlist = NULL;
+	int list_len = 0;
+	int list_index = 0;
+	int retval = 1;
+	int next_snap;
+	int gpipe;
+
+	start = lt_millisecond();
+	gpipe = lt_gpipe_readfd();
+
+	if (!show_help) {
+		print_hint(NULL);
+		print_sysglobal();
+	}
+
+	get_plist(&plist, &tlist, &list_len, &list_index);
+
+	for (;;) {
+		if (need_refresh && !show_help) {
+			if (list_len != 0) {
+				if (!thread_mode) {
+					print_taskbar_process(plist, list_len,
+					    list_index);
+					print_process(plist[list_index]);
+				} else {
+					print_taskbar_thread(plist, tlist,
+					    list_len, list_index);
+					print_thread(plist[list_index],
+					    tlist[list_index]);
+				}
+			} else {
+				print_empty_process_bar();
+			}
+		}
+
+		need_refresh = TRUE;	/* Usually we need refresh. */
+		remaining = duration - (int)(lt_millisecond() - start);
+
+		if (remaining <= 0) {
+			break;
+		}
+
+		/* Embedded dtrace snap action here. */
+		next_snap = lt_dtrace_work(0);
+
+		if (next_snap == 0) {
+			/*
+			 * Just did a snap, check time for the next one.
+			 */
+			next_snap = lt_dtrace_work(0);
+		}
+
+		if (next_snap > 0 && remaining > next_snap) {
+			remaining = next_snap;
+		}
+
+		timeout.tv_sec = remaining / 1000;
+		timeout.tv_usec = (remaining % 1000) * 1000;
+
+		FD_ZERO(&read_fd);
+		FD_SET(0, &read_fd);
+		FD_SET(gpipe, &read_fd);
+
+		/* Wait for keyboard input, or signal from gpipe */
+		if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
+			int k = 0;
+
+			if (FD_ISSET(gpipe, &read_fd)) {
+				/* Data from pipe has priority */
+				char ch;
+				(void) read(gpipe, &ch, 1);
+				k = ch; /* Need this for big-endianness */
+			} else {
+				k = getch();
+			}
+
+			/*
+			 * Check if we need to update the hint line whenever we
+			 * get a chance.
+			 * NOTE: current implementation depends on
+			 * g_config.lt_cfg_snap_interval, but it's OK because it
+			 * doesn't have to be precise.
+			 */
+			print_hint(NULL);
+			/*
+			 * If help is on display right now, and a key press
+			 * happens, we need to clear the help and continue.
+			 */
+			if (show_help) {
+				(void) werase(stdscr);
+				(void) refresh();
+				print_title();
+				print_sysglobal();
+				show_help = FALSE;
+				/* Drop this key and continue */
+				continue;
+			}
+
+			switch (k) {
+			case 'Q':
+			case 'q':
+				retval = 0;
+				goto quit;
+			case 'R':
+			case 'r':
+				lt_display_deinit();
+				lt_display_init();
+				goto quit;
+			case 'H':
+			case 'h':
+				show_help = TRUE;
+				(void) werase(stdscr);
+				(void) refresh();
+				print_help();
+				break;
+			case ',':
+			case '<':
+			case KEY_LEFT:
+				--list_index;
+
+				if (list_index < 0) {
+					list_index = 0;
+				}
+
+				break;
+			case '.':
+			case '>':
+			case KEY_RIGHT:
+				++list_index;
+
+				if (list_index >= list_len) {
+					list_index = list_len - 1;
+				}
+
+				break;
+			case 'a':
+			case 'A':
+				sort_type = LT_SORT_AVG;
+				print_sysglobal();
+				break;
+			case 'p':
+			case 'P':
+				sort_type = LT_SORT_TOTAL;
+				print_sysglobal();
+				break;
+			case 'm':
+			case 'M':
+				sort_type = LT_SORT_MAX;
+				print_sysglobal();
+				break;
+			case 'c':
+			case 'C':
+				sort_type = LT_SORT_COUNT;
+				print_sysglobal();
+				break;
+			case 't':
+			case 'T':
+				if (plist != NULL) {
+					selected_pid = plist[list_index];
+				}
+
+				selected_tid = INVALID_TID;
+				thread_mode = !thread_mode;
+				get_plist(&plist, &tlist,
+				    &list_len, &list_index);
+				break;
+			case '1':
+			case '!':
+				current_list_type = LT_LIST_CAUSE;
+				print_sysglobal();
+				break;
+			case '2':
+			case '@':
+				if (g_config.lt_cfg_low_overhead_mode) {
+					lt_display_error("Switching mode is "
+					    "not available for '-f low'.");
+				} else {
+					current_list_type = LT_LIST_SPECIALS;
+					print_sysglobal();
+				}
+
+				break;
+			case '3':
+			case '#':
+				if (g_config.lt_cfg_trace_syncobj) {
+					current_list_type = LT_LIST_SOBJ;
+					print_sysglobal();
+				} else if (g_config.lt_cfg_low_overhead_mode) {
+					lt_display_error("Switching mode is "
+					    "not available for '-f low'.");
+				} else {
+					lt_display_error("Tracing "
+					    "synchronization objects is "
+					    "disabled.");
+				}
+
+				break;
+			default:
+				/* Wake up for nothing; no refresh is needed */
+				need_refresh = FALSE;
+				break;
+			}
+		} else {
+			need_refresh = FALSE;
+		}
+	}
+
+quit:
+	if (plist != NULL) {
+		selected_pid = plist[list_index];
+	}
+
+	if (tlist != NULL) {
+		selected_tid = tlist[list_index];
+	}
+
+	lt_stat_proc_list_free(plist, tlist);
+
+	return (retval);
+}
+
+/*
+ * Clean up display.
+ */
+void
+lt_display_deinit(void)
+{
+	if (curses_inited) {
+		(void) clear();
+		(void) refresh();
+		(void) endwin();
+	}
+
+	titlebar = NULL;
+	captionbar = NULL;
+	sysglobal_window = NULL;
+	taskbar = NULL;
+	process_window = NULL;
+	hintbar = NULL;
+	screen_width = 1;
+	screen_height = 1;
+
+	display_initialized = FALSE;
+	curses_inited = FALSE;
+}
+
+/*
+ * Print message when display error happens.
+ */
+/* ARGSUSED */
+void
+lt_display_error(const char *fmt, ...)
+{
+	va_list vl;
+	char tmp[81];
+	int l;
+
+	va_start(vl, fmt);
+	(void) vsnprintf(tmp, sizeof (tmp), fmt, vl);
+	va_end(vl);
+
+	l = strlen(tmp);
+
+	while (l > 0 && (tmp[l - 1] == '\n' || tmp[l - 1] == '\r')) {
+		tmp[l - 1] = '\0';
+		--l;
+	}
+
+	if (!display_initialized) {
+		(void) fprintf(stderr, "%s\n", tmp);
+	} else if (!show_help) {
+		print_hint(tmp);
+	}
+
+}
--- old/usr/src/cmd/latencytop/common/dwrapper.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,604 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <unistd.h>
-#include <stdio.h>
-#include <dtrace.h>
-#include <string.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <limits.h>
-
-#include "latencytop.h"
-
-static dtrace_hdl_t *g_dtp = NULL;	/* dtrace handle */
-static pid_t pid_self = -1;		/* PID of our own process */
-
-/*
- * Ignore sched if sched is not tracked.
- * Also ignore ourselves (i.e., latencytop).
- */
-#define	SHOULD_IGNORE(pid)		\
-	((!g_config.lt_cfg_trace_sched && 0 == (pid)) || pid_self == (pid))
-
-/*
- * Get an integer value from dtrace record.
- */
-static uint64_t
-rec_get_value(void *a, size_t b)
-{
-	uint64_t ret = 0;
-
-	switch (b) {
-	case sizeof (uint64_t):
-		ret = *((uint64_t *)(a));
-		break;
-	case sizeof (uint32_t):
-		ret = *((uint32_t *)(a));
-		break;
-	case sizeof (uint16_t):
-		ret = *((uint16_t *)(a));
-		break;
-	case sizeof (uint8_t):
-		ret = *((uint8_t *)(a));
-		break;
-	default:
-		break;
-	}
-
-	return (ret);
-}
-
-/*
- * Callback to process aggregation lt_call_* (related to on/off cpu
- * activities) in the snapshot.
- */
-static int
-aggwalk_call(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
-{
-	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
-	dtrace_syminfo_t dts;
-	GElf_Sym sym;
-	caddr_t addr;
-	pid_t pid;
-	id_t tid;
-	unsigned int stack_depth;
-	unsigned int pc_size;
-	uint64_t pc;
-	uint64_t agg_value;
-	char *ptr = NULL;
-	char *buffer = NULL;
-	int ptrsize;
-	unsigned int buffersize;
-	char *tag = NULL;
-	unsigned int priority;
-	enum { REC_PID = 1, REC_TID, REC_STACK, REC_TAG, REC_PRIO, REC_AGG,
-	    NREC };
-
-	/* Check action type */
-	if ((aggdesc->dtagd_nrecs < NREC) ||
-	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_TAG].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_PRIO].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action)) ||
-	    (aggdesc->dtagd_rec[REC_STACK].dtrd_action != DTRACEACT_STACK)) {
-
-		return (-1);
-	}
-
-	pid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
-
-	if (SHOULD_IGNORE(pid)) {
-		return (0);
-	}
-
-	tid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
-
-	/* Parse stack array from dtagd_rec */
-	stack_depth = aggdesc->dtagd_rec[REC_STACK].dtrd_arg;
-	pc_size = aggdesc->dtagd_rec[REC_STACK].dtrd_size / stack_depth;
-	addr = data->dtada_data + aggdesc->dtagd_rec[REC_STACK].dtrd_offset;
-	buffersize = (stack_depth * (2 * PATH_MAX + 2) + 1) * sizeof (char);
-	buffer = (char *)lt_malloc(buffersize);
-	ptr = buffer;
-	ptrsize = buffersize;
-
-	/* Print the stack */
-	while (stack_depth > 0) {
-		pc = rec_get_value(addr, pc_size);
-
-		if (pc == 0) {
-			break;
-		}
-
-		addr += pc_size;
-
-		if (dtrace_lookup_by_addr(g_dtp, pc, &sym, &dts) == 0) {
-			int len;
-			len = snprintf(ptr, ptrsize,
-			    "%s`%s ", dts.dts_object, dts.dts_name);
-			ptrsize -= len;
-
-			if (ptrsize <= 0) {
-				/*
-				 * snprintf returns "desired" length, so
-				 * reaching here means our buffer is full.
-				 * Move ptr to the last byte of the buffer and
-				 * break.
-				 */
-				ptr = &buffer[buffersize-1];
-				break;
-			} else {
-				ptr += len;
-			}
-		}
-	}
-
-	if (ptr != buffer) {
-		/*
-		 * We have printed something, so it is safe to remove
-		 * the last ' '.
-		 */
-		*(ptr-1) = '\0';
-	}
-
-	tag = (char *)data->dtada_data +
-	    aggdesc->dtagd_rec[REC_TAG].dtrd_offset;
-
-	priority = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_PRIO].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_PRIO].dtrd_size);
-
-	agg_value = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
-
-	lt_stat_update(pid, tid, buffer, tag, priority, stat_type, agg_value);
-
-	if (buffer != NULL)  {
-		free(buffer);
-	}
-
-	return (0);
-}
-
-/*
- * Callback to process aggregation lt_named_* (related to lock spinning etc.),
- * in the snapshot.
- */
-static int
-aggwalk_named(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
-{
-	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
-	pid_t pid;
-	id_t tid;
-	uint64_t agg_value;
-	int cause_id;
-	char *type = NULL;
-	enum { REC_PID = 1, REC_TID, REC_TYPE, REC_AGG, NREC };
-
-	/* Check action type */
-	if ((aggdesc->dtagd_nrecs < NREC) ||
-	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_TYPE].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action))) {
-
-		return (-1);
-	}
-
-	pid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
-
-	if (SHOULD_IGNORE(pid)) {
-		return (0);
-	}
-
-	tid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
-
-	type = (char *)data->dtada_data
-	    + aggdesc->dtagd_rec[REC_TYPE].dtrd_offset;
-	cause_id = lt_table_cause_from_name(type, 1, CAUSE_FLAG_SPECIAL);
-
-	agg_value = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
-
-	lt_stat_update_cause(pid, tid, cause_id, stat_type, agg_value);
-
-	return (0);
-
-}
-
-/*
- * Callback to process aggregation lt_sync_* (related to synchronization
- * objects), in the snapshot.
- */
-static int
-aggwalk_sync(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
-{
-	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
-	pid_t pid;
-	id_t tid;
-	uint64_t agg_value;
-	int stype;
-	unsigned long long wchan;
-	enum { REC_PID = 1, REC_TID, REC_STYPE, REC_WCHAN, REC_AGG, NREC };
-
-	/* Check action type */
-	if ((aggdesc->dtagd_nrecs < NREC) ||
-	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_STYPE].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (aggdesc->dtagd_rec[REC_WCHAN].dtrd_action != DTRACEACT_DIFEXPR) ||
-	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action))) {
-
-		return (-1);
-	}
-
-	pid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
-
-	if (SHOULD_IGNORE(pid)) {
-		return (0);
-	}
-
-	tid = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
-
-	stype = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_STYPE].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_STYPE].dtrd_size);
-
-	wchan = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_WCHAN].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_WCHAN].dtrd_size);
-
-	agg_value = rec_get_value(
-	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
-	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
-
-	lt_stat_update_sobj(pid, tid, stype, wchan, stat_type, agg_value);
-
-	return (0);
-}
-
-/*
- * Callback to process various aggregations in the snapshot. Called by
- * different aggwalk_* functions.
- */
-/* ARGSUSED */
-static int
-aggwalk(const dtrace_aggdata_t *data, void *arg)
-{
-	char *tmp;
-	char buffer[32];
-	lt_stat_type_t stat_type;
-	int (*func)(const dtrace_aggdata_t *, lt_stat_type_t);
-
-	(void) strncpy(buffer, data->dtada_desc->dtagd_name, sizeof (buffer));
-	buffer[sizeof (buffer) - 1] = '\0';
-	tmp = strtok(buffer, "_");
-
-	if (tmp == NULL || strcmp(tmp, "lt") != 0) {
-		goto done;
-	}
-
-	tmp = strtok(NULL, "_");
-
-	if (tmp == NULL) {
-		goto done;
-	} else if (strcmp(tmp, "call") == 0) {
-		func = aggwalk_call;
-	} else if (strcmp(tmp, "named") == 0) {
-		func = aggwalk_named;
-	} else if (strcmp(tmp, "sync") == 0) {
-		func = aggwalk_sync;
-	} else {
-		goto done;
-	}
-
-	tmp = strtok(NULL, "_");
-
-	if (tmp == NULL) {
-		goto done;
-	} else if (strcmp(tmp, "count") == 0) {
-		stat_type = LT_STAT_COUNT;
-	} else if (strcmp(tmp, "sum") == 0) {
-		stat_type = LT_STAT_SUM;
-	} else if (strcmp(tmp, "max") == 0) {
-		stat_type = LT_STAT_MAX;
-	} else {
-		goto done;
-	}
-
-	(void) func(data, stat_type);
-
-done:
-	/* We have our data, so remove it from DTrace now */
-	return (DTRACE_AGGWALK_REMOVE);
-}
-
-/*
- * Callback to handle event caused by DTrace dropping data.
- */
-/*ARGSUSED*/
-static int
-drop_handler(const dtrace_dropdata_t *data, void *user)
-{
-	lt_display_error("Drop: %s\n", data->dtdda_msg);
-	lt_drop_detected = B_TRUE;
-
-	/* Pretend nothing happened, so just continue */
-	return (DTRACE_HANDLE_OK);
-}
-
-#ifndef EMBED_CONFIGS
-/*
- * Copy the content from a "real" file into a temp file.
- */
-static int
-copy_tmp_file(const char *src, FILE *dst)
-{
-	FILE *tmp = NULL;
-	char buffer[256];
-	int bytes;
-
-	if ((tmp = fopen(src, "r")) == NULL) {
-		return (-1);
-	}
-
-	while ((bytes = fread(buffer, 1, sizeof (buffer), tmp)) > 0) {
-		if (fwrite(buffer, bytes, 1, dst) != 1) {
-			return (-1);
-		}
-	}
-
-	(void) fclose(tmp);
-
-	return (0);
-}
-#endif
-
-/*
- * DTrace initialization. D script starts running when this function returns.
- */
-int
-lt_dtrace_init(void)
-{
-	dtrace_prog_t *prog;
-	dtrace_proginfo_t info;
-	int err;
-	FILE *fp_script = NULL;
-	char tmp[64];
-
-	pid_self = getpid();
-
-	if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
-		lt_display_error("Cannot open dtrace library: %s\n",
-		    dtrace_errmsg(NULL, err));
-		return (-1);
-	}
-
-	if (dtrace_handle_drop(g_dtp, &drop_handler, NULL) == -1) {
-		lt_display_error("Cannot install DTrace handle: %s\n",
-		    dtrace_errmsg(NULL, err));
-		return (-1);
-	}
-
-	if (g_config.lt_cfg_enable_filter) {
-		if ((err = dtrace_setopt(g_dtp, "define",
-		    "ENABLE_FILTER")) != 0) {
-			lt_display_error(
-			    "Failed to set option ENABLE_FILTER.\n");
-			return (err);
-		}
-	}
-
-	if (g_config.lt_cfg_trace_syncobj) {
-		if ((err = dtrace_setopt(g_dtp, "define",
-		    "ENABLE_SYNCOBJ")) != 0) {
-			lt_display_error(
-			    "Failed to set option ENABLE_SYNCOBJ.\n");
-			return (err);
-		}
-	}
-
-	if (g_config.lt_cfg_trace_sched) {
-		if ((err = dtrace_setopt(g_dtp, "define",
-		    "ENABLE_SCHED")) != 0) {
-			lt_display_error(
-			    "Failed to set option ENABLE_SCHED.\n");
-			return (err);
-		}
-	}
-
-	if (g_config.lt_cfg_trace_pid != 0) {
-		(void) snprintf(tmp, sizeof (tmp), "TRACE_PID=%u",
-		    g_config.lt_cfg_trace_pid);
-		if ((err = dtrace_setopt(g_dtp, "define", tmp)) != 0) {
-			lt_display_error(
-			    "Failed to set option TRACE_PID.\n");
-			return (err);
-		}
-	}
-
-	if (g_config.lt_cfg_trace_pgid != 0) {
-		(void) snprintf(tmp, sizeof (tmp), "TRACE_PGID=%u",
-		    g_config.lt_cfg_trace_pgid);
-		if ((err = dtrace_setopt(g_dtp, "define", tmp)) != 0) {
-			lt_display_error(
-			    "Failed to set option TRACE_PGID.\n");
-			return (err);
-		}
-	}
-
-	if (g_config.lt_cfg_low_overhead_mode) {
-		if ((err = dtrace_setopt(g_dtp, "define",
-		    "ENABLE_LOW_OVERHEAD")) != 0) {
-			lt_display_error(
-			    "Failed to set option ENABLE_LOW_OVERHEAD.\n");
-			return (err);
-		}
-	}
-
-	/* Create a temp file; libdtrace needs it for cpp(1) */
-	if ((fp_script = tmpfile()) == NULL) {
-		lt_display_error("Cannot create tmp file\n");
-		return (-1);
-	}
-
-	/* Copy the main D script into the temp file */
-#ifdef EMBED_CONFIGS
-	if (fwrite(&latencytop_d_start,
-	    (size_t)(&latencytop_d_end - &latencytop_d_start), 1, fp_script)
-	    != 1) {
-		lt_display_error("Could not copy D script, fwrite() failed\n");
-		(void) fclose(fp_script);
-		return (-1);
-	}
-#else
-	if (copy_tmp_file(DEFAULT_D_SCRIPT_NAME, fp_script) != 0) {
-		lt_display_error("Cannot open script file %s\n",
-		    DEFAULT_D_SCRIPT_NAME);
-		(void) fclose(fp_script);
-		return (-1);
-	}
-#endif	/* EMBED_CONFIGS */
-
-	if (lt_table_append_trans(fp_script) != 0) {
-		(void) fclose(fp_script);
-		return (-1);
-	}
-
-	(void) fseek(fp_script, 0, SEEK_SET);
-
-	if ((prog = dtrace_program_fcompile(g_dtp, fp_script,
-	    DTRACE_C_CPP, 0, NULL)) == NULL) {
-		lt_display_error("Failed to compile D script.\n");
-		(void) fclose(fp_script);
-		return (dtrace_errno(g_dtp));
-	}
-
-	(void) fclose(fp_script);
-
-	/* Execute the D script */
-	if (dtrace_program_exec(g_dtp, prog, &info) == -1) {
-		lt_display_error("Failed to enable probes.\n");
-		return (dtrace_errno(g_dtp));
-	}
-
-	if (dtrace_go(g_dtp) != 0) {
-		lt_display_error("Failed to run D script.\n");
-		return (dtrace_errno(g_dtp));
-	}
-
-	return (0);
-}
-
-/*
- * Worker function to move aggregate data to user space. Called periodically
- * to prevent the kernel from running out of memory.
- */
-int
-lt_dtrace_work(int force)
-{
-	static uint64_t last_snap = 0;
-	uint64_t now = lt_millisecond();
-
-	if (!force && now - last_snap < g_config.lt_cfg_snap_interval) {
-		return (last_snap + g_config.lt_cfg_snap_interval - now);
-	}
-
-	if (dtrace_status(g_dtp) == -1) {
-		lt_display_error("Failed when getting status: %s\n",
-		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
-		return (-1);
-	}
-
-	if (dtrace_aggregate_snap(g_dtp) != 0) {
-		lt_display_error("Failed to snap aggregate: %s\n",
-		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
-		return (-1);
-	}
-
-	last_snap = now;
-	return (0);
-}
-
-/*
- * Walk through dtrace aggregator and collect data for latencytop to display.
- * Called immediately before UI update.
- */
-int
-lt_dtrace_collect(void)
-{
-	if (lt_dtrace_work(1) != 0) {
-		return (-1);
-	}
-
-	if (dtrace_aggregate_walk(g_dtp, aggwalk, NULL) != 0) {
-		lt_display_error("Failed to sort aggregate: %s\n",
-		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
-		return (-1);
-	}
-
-	/*
-	 * Probably we don't need to clear again, because we have removed
-	 * everything. Paranoid ?
-	 */
-	dtrace_aggregate_clear(g_dtp);
-
-	return (0);
-}
-
-/*
- * dtrace clean up.
- */
-int
-lt_dtrace_deinit(void)
-{
-	int ret = 0;
-
-	if (dtrace_stop(g_dtp) != 0) {
-		lt_display_error("dtrace_stop failed: %s\n",
-		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
-		ret = -1;
-	}
-
-	dtrace_close(g_dtp);
-
-	return (ret);
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/dwrapper.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,604 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <dtrace.h>
+#include <string.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <limits.h>
+
+#include "latencytop.h"
+
+static dtrace_hdl_t *g_dtp = NULL;	/* dtrace handle */
+static pid_t pid_self = -1;		/* PID of our own process */
+
+/*
+ * Ignore sched if sched is not tracked.
+ * Also ignore ourselves (i.e., latencytop).
+ */
+#define	SHOULD_IGNORE(pid)		\
+	((!g_config.lt_cfg_trace_sched && 0 == (pid)) || pid_self == (pid))
+
+/*
+ * Get an integer value from dtrace record.
+ */
+static uint64_t
+rec_get_value(void *a, size_t b)
+{
+	uint64_t ret = 0;
+
+	switch (b) {
+	case sizeof (uint64_t):
+		ret = *((uint64_t *)(a));
+		break;
+	case sizeof (uint32_t):
+		ret = *((uint32_t *)(a));
+		break;
+	case sizeof (uint16_t):
+		ret = *((uint16_t *)(a));
+		break;
+	case sizeof (uint8_t):
+		ret = *((uint8_t *)(a));
+		break;
+	default:
+		break;
+	}
+
+	return (ret);
+}
+
+/*
+ * Callback to process aggregation lt_call_* (related to on/off cpu
+ * activities) in the snapshot.
+ */
+static int
+aggwalk_call(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
+{
+	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
+	dtrace_syminfo_t dts;
+	GElf_Sym sym;
+	caddr_t addr;
+	pid_t pid;
+	id_t tid;
+	unsigned int stack_depth;
+	unsigned int pc_size;
+	uint64_t pc;
+	uint64_t agg_value;
+	char *ptr = NULL;
+	char *buffer = NULL;
+	int ptrsize;
+	unsigned int buffersize;
+	char *tag = NULL;
+	unsigned int priority;
+	enum { REC_PID = 1, REC_TID, REC_STACK, REC_TAG, REC_PRIO, REC_AGG,
+	    NREC };
+
+	/* Check action type */
+	if ((aggdesc->dtagd_nrecs < NREC) ||
+	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_TAG].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_PRIO].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action)) ||
+	    (aggdesc->dtagd_rec[REC_STACK].dtrd_action != DTRACEACT_STACK)) {
+
+		return (-1);
+	}
+
+	pid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
+
+	if (SHOULD_IGNORE(pid)) {
+		return (0);
+	}
+
+	tid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
+
+	/* Parse stack array from dtagd_rec */
+	stack_depth = aggdesc->dtagd_rec[REC_STACK].dtrd_arg;
+	pc_size = aggdesc->dtagd_rec[REC_STACK].dtrd_size / stack_depth;
+	addr = data->dtada_data + aggdesc->dtagd_rec[REC_STACK].dtrd_offset;
+	buffersize = (stack_depth * (2 * PATH_MAX + 2) + 1) * sizeof (char);
+	buffer = (char *)lt_malloc(buffersize);
+	ptr = buffer;
+	ptrsize = buffersize;
+
+	/* Print the stack */
+	while (stack_depth > 0) {
+		pc = rec_get_value(addr, pc_size);
+
+		if (pc == 0) {
+			break;
+		}
+
+		addr += pc_size;
+
+		if (dtrace_lookup_by_addr(g_dtp, pc, &sym, &dts) == 0) {
+			int len;
+			len = snprintf(ptr, ptrsize,
+			    "%s`%s ", dts.dts_object, dts.dts_name);
+			ptrsize -= len;
+
+			if (ptrsize <= 0) {
+				/*
+				 * snprintf returns "desired" length, so
+				 * reaching here means our buffer is full.
+				 * Move ptr to the last byte of the buffer and
+				 * break.
+				 */
+				ptr = &buffer[buffersize-1];
+				break;
+			} else {
+				ptr += len;
+			}
+		}
+	}
+
+	if (ptr != buffer) {
+		/*
+		 * We have printed something, so it is safe to remove
+		 * the last ' '.
+		 */
+		*(ptr-1) = '\0';
+	}
+
+	tag = (char *)data->dtada_data +
+	    aggdesc->dtagd_rec[REC_TAG].dtrd_offset;
+
+	priority = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_PRIO].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_PRIO].dtrd_size);
+
+	agg_value = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
+
+	lt_stat_update(pid, tid, buffer, tag, priority, stat_type, agg_value);
+
+	if (buffer != NULL)  {
+		free(buffer);
+	}
+
+	return (0);
+}
+
+/*
+ * Callback to process aggregation lt_named_* (related to lock spinning etc.),
+ * in the snapshot.
+ */
+static int
+aggwalk_named(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
+{
+	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
+	pid_t pid;
+	id_t tid;
+	uint64_t agg_value;
+	int cause_id;
+	char *type = NULL;
+	enum { REC_PID = 1, REC_TID, REC_TYPE, REC_AGG, NREC };
+
+	/* Check action type */
+	if ((aggdesc->dtagd_nrecs < NREC) ||
+	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_TYPE].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action))) {
+
+		return (-1);
+	}
+
+	pid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
+
+	if (SHOULD_IGNORE(pid)) {
+		return (0);
+	}
+
+	tid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
+
+	type = (char *)data->dtada_data
+	    + aggdesc->dtagd_rec[REC_TYPE].dtrd_offset;
+	cause_id = lt_table_cause_from_name(type, 1, CAUSE_FLAG_SPECIAL);
+
+	agg_value = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
+
+	lt_stat_update_cause(pid, tid, cause_id, stat_type, agg_value);
+
+	return (0);
+
+}
+
+/*
+ * Callback to process aggregation lt_sync_* (related to synchronization
+ * objects), in the snapshot.
+ */
+static int
+aggwalk_sync(const dtrace_aggdata_t *data, lt_stat_type_t stat_type)
+{
+	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
+	pid_t pid;
+	id_t tid;
+	uint64_t agg_value;
+	int stype;
+	unsigned long long wchan;
+	enum { REC_PID = 1, REC_TID, REC_STYPE, REC_WCHAN, REC_AGG, NREC };
+
+	/* Check action type */
+	if ((aggdesc->dtagd_nrecs < NREC) ||
+	    (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_STYPE].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (aggdesc->dtagd_rec[REC_WCHAN].dtrd_action != DTRACEACT_DIFEXPR) ||
+	    (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action))) {
+
+		return (-1);
+	}
+
+	pid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_PID].dtrd_size);
+
+	if (SHOULD_IGNORE(pid)) {
+		return (0);
+	}
+
+	tid = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_TID].dtrd_size);
+
+	stype = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_STYPE].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_STYPE].dtrd_size);
+
+	wchan = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_WCHAN].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_WCHAN].dtrd_size);
+
+	agg_value = rec_get_value(
+	    data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset,
+	    aggdesc->dtagd_rec[REC_AGG].dtrd_size);
+
+	lt_stat_update_sobj(pid, tid, stype, wchan, stat_type, agg_value);
+
+	return (0);
+}
+
+/*
+ * Callback to process various aggregations in the snapshot. Called by
+ * different aggwalk_* functions.
+ */
+/* ARGSUSED */
+static int
+aggwalk(const dtrace_aggdata_t *data, void *arg)
+{
+	char *tmp;
+	char buffer[32];
+	lt_stat_type_t stat_type;
+	int (*func)(const dtrace_aggdata_t *, lt_stat_type_t);
+
+	(void) strncpy(buffer, data->dtada_desc->dtagd_name, sizeof (buffer));
+	buffer[sizeof (buffer) - 1] = '\0';
+	tmp = strtok(buffer, "_");
+
+	if (tmp == NULL || strcmp(tmp, "lt") != 0) {
+		goto done;
+	}
+
+	tmp = strtok(NULL, "_");
+
+	if (tmp == NULL) {
+		goto done;
+	} else if (strcmp(tmp, "call") == 0) {
+		func = aggwalk_call;
+	} else if (strcmp(tmp, "named") == 0) {
+		func = aggwalk_named;
+	} else if (strcmp(tmp, "sync") == 0) {
+		func = aggwalk_sync;
+	} else {
+		goto done;
+	}
+
+	tmp = strtok(NULL, "_");
+
+	if (tmp == NULL) {
+		goto done;
+	} else if (strcmp(tmp, "count") == 0) {
+		stat_type = LT_STAT_COUNT;
+	} else if (strcmp(tmp, "sum") == 0) {
+		stat_type = LT_STAT_SUM;
+	} else if (strcmp(tmp, "max") == 0) {
+		stat_type = LT_STAT_MAX;
+	} else {
+		goto done;
+	}
+
+	(void) func(data, stat_type);
+
+done:
+	/* We have our data, so remove it from DTrace now */
+	return (DTRACE_AGGWALK_REMOVE);
+}
+
+/*
+ * Callback to handle event caused by DTrace dropping data.
+ */
+/*ARGSUSED*/
+static int
+drop_handler(const dtrace_dropdata_t *data, void *user)
+{
+	lt_display_error("Drop: %s\n", data->dtdda_msg);
+	lt_drop_detected = B_TRUE;
+
+	/* Pretend nothing happened, so just continue */
+	return (DTRACE_HANDLE_OK);
+}
+
+#ifndef EMBED_CONFIGS
+/*
+ * Copy the content from a "real" file into a temp file.
+ */
+static int
+copy_tmp_file(const char *src, FILE *dst)
+{
+	FILE *tmp = NULL;
+	char buffer[256];
+	int bytes;
+
+	if ((tmp = fopen(src, "r")) == NULL) {
+		return (-1);
+	}
+
+	while ((bytes = fread(buffer, 1, sizeof (buffer), tmp)) > 0) {
+		if (fwrite(buffer, bytes, 1, dst) != 1) {
+			return (-1);
+		}
+	}
+
+	(void) fclose(tmp);
+
+	return (0);
+}
+#endif
+
+/*
+ * DTrace initialization. D script starts running when this function returns.
+ */
+int
+lt_dtrace_init(void)
+{
+	dtrace_prog_t *prog;
+	dtrace_proginfo_t info;
+	int err;
+	FILE *fp_script = NULL;
+	char tmp[64];
+
+	pid_self = getpid();
+
+	if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
+		lt_display_error("Cannot open dtrace library: %s\n",
+		    dtrace_errmsg(NULL, err));
+		return (-1);
+	}
+
+	if (dtrace_handle_drop(g_dtp, &drop_handler, NULL) == -1) {
+		lt_display_error("Cannot install DTrace handle: %s\n",
+		    dtrace_errmsg(NULL, err));
+		return (-1);
+	}
+
+	if (g_config.lt_cfg_enable_filter) {
+		if ((err = dtrace_setopt(g_dtp, "define",
+		    "ENABLE_FILTER")) != 0) {
+			lt_display_error(
+			    "Failed to set option ENABLE_FILTER.\n");
+			return (err);
+		}
+	}
+
+	if (g_config.lt_cfg_trace_syncobj) {
+		if ((err = dtrace_setopt(g_dtp, "define",
+		    "ENABLE_SYNCOBJ")) != 0) {
+			lt_display_error(
+			    "Failed to set option ENABLE_SYNCOBJ.\n");
+			return (err);
+		}
+	}
+
+	if (g_config.lt_cfg_trace_sched) {
+		if ((err = dtrace_setopt(g_dtp, "define",
+		    "ENABLE_SCHED")) != 0) {
+			lt_display_error(
+			    "Failed to set option ENABLE_SCHED.\n");
+			return (err);
+		}
+	}
+
+	if (g_config.lt_cfg_trace_pid != 0) {
+		(void) snprintf(tmp, sizeof (tmp), "TRACE_PID=%u",
+		    g_config.lt_cfg_trace_pid);
+		if ((err = dtrace_setopt(g_dtp, "define", tmp)) != 0) {
+			lt_display_error(
+			    "Failed to set option TRACE_PID.\n");
+			return (err);
+		}
+	}
+
+	if (g_config.lt_cfg_trace_pgid != 0) {
+		(void) snprintf(tmp, sizeof (tmp), "TRACE_PGID=%u",
+		    g_config.lt_cfg_trace_pgid);
+		if ((err = dtrace_setopt(g_dtp, "define", tmp)) != 0) {
+			lt_display_error(
+			    "Failed to set option TRACE_PGID.\n");
+			return (err);
+		}
+	}
+
+	if (g_config.lt_cfg_low_overhead_mode) {
+		if ((err = dtrace_setopt(g_dtp, "define",
+		    "ENABLE_LOW_OVERHEAD")) != 0) {
+			lt_display_error(
+			    "Failed to set option ENABLE_LOW_OVERHEAD.\n");
+			return (err);
+		}
+	}
+
+	/* Create a temp file; libdtrace needs it for cpp(1) */
+	if ((fp_script = tmpfile()) == NULL) {
+		lt_display_error("Cannot create tmp file\n");
+		return (-1);
+	}
+
+	/* Copy the main D script into the temp file */
+#ifdef EMBED_CONFIGS
+	if (fwrite(&latencytop_d_start,
+	    (size_t)(&latencytop_d_end - &latencytop_d_start), 1, fp_script)
+	    != 1) {
+		lt_display_error("Could not copy D script, fwrite() failed\n");
+		(void) fclose(fp_script);
+		return (-1);
+	}
+#else
+	if (copy_tmp_file(DEFAULT_D_SCRIPT_NAME, fp_script) != 0) {
+		lt_display_error("Cannot open script file %s\n",
+		    DEFAULT_D_SCRIPT_NAME);
+		(void) fclose(fp_script);
+		return (-1);
+	}
+#endif	/* EMBED_CONFIGS */
+
+	if (lt_table_append_trans(fp_script) != 0) {
+		(void) fclose(fp_script);
+		return (-1);
+	}
+
+	(void) fseek(fp_script, 0, SEEK_SET);
+
+	if ((prog = dtrace_program_fcompile(g_dtp, fp_script,
+	    DTRACE_C_CPP, 0, NULL)) == NULL) {
+		lt_display_error("Failed to compile D script.\n");
+		(void) fclose(fp_script);
+		return (dtrace_errno(g_dtp));
+	}
+
+	(void) fclose(fp_script);
+
+	/* Execute the D script */
+	if (dtrace_program_exec(g_dtp, prog, &info) == -1) {
+		lt_display_error("Failed to enable probes.\n");
+		return (dtrace_errno(g_dtp));
+	}
+
+	if (dtrace_go(g_dtp) != 0) {
+		lt_display_error("Failed to run D script.\n");
+		return (dtrace_errno(g_dtp));
+	}
+
+	return (0);
+}
+
+/*
+ * Worker function to move aggregate data to user space. Called periodically
+ * to prevent the kernel from running out of memory.
+ */
+int
+lt_dtrace_work(int force)
+{
+	static uint64_t last_snap = 0;
+	uint64_t now = lt_millisecond();
+
+	if (!force && now - last_snap < g_config.lt_cfg_snap_interval) {
+		return (last_snap + g_config.lt_cfg_snap_interval - now);
+	}
+
+	if (dtrace_status(g_dtp) == -1) {
+		lt_display_error("Failed when getting status: %s\n",
+		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+		return (-1);
+	}
+
+	if (dtrace_aggregate_snap(g_dtp) != 0) {
+		lt_display_error("Failed to snap aggregate: %s\n",
+		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+		return (-1);
+	}
+
+	last_snap = now;
+	return (0);
+}
+
+/*
+ * Walk through dtrace aggregator and collect data for latencytop to display.
+ * Called immediately before UI update.
+ */
+int
+lt_dtrace_collect(void)
+{
+	if (lt_dtrace_work(1) != 0) {
+		return (-1);
+	}
+
+	if (dtrace_aggregate_walk(g_dtp, aggwalk, NULL) != 0) {
+		lt_display_error("Failed to sort aggregate: %s\n",
+		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+		return (-1);
+	}
+
+	/*
+	 * Probably we don't need to clear again, because we have removed
+	 * everything. Paranoid ?
+	 */
+	dtrace_aggregate_clear(g_dtp);
+
+	return (0);
+}
+
+/*
+ * dtrace clean up.
+ */
+int
+lt_dtrace_deinit(void)
+{
+	int ret = 0;
+
+	if (dtrace_stop(g_dtp) != 0) {
+		lt_display_error("dtrace_stop failed: %s\n",
+		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
+		ret = -1;
+	}
+
+	dtrace_close(g_dtp);
+
+	return (ret);
+}
--- old/usr/src/cmd/latencytop/i386/Makefile	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,29 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 ../Makefile.com
-
-WRAPOPT =
-
-install: all $(ROOTPROG32)
--- old/usr/src/cmd/latencytop/common/klog.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,226 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <string.h>
-#include <procfs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include "latencytop.h"
-
-static GHashTable *proc_table = NULL; /* pid -> char * */
-static GHashTable *klog_table = NULL; /* char * -> uint64_t total */
-static char klog_filename[PATH_MAX] = DEFAULT_KLOG_FILE;
-static int klog_level = LT_KLOG_LEVEL_NONE;
-
-static void
-print_proc(void *key, const char *args, FILE *fp)
-{
-	(void) fprintf(fp, "%-8ld \"%s\"\n", (long)key, args);
-}
-
-static void
-print_stat(const char *key, lt_stat_data_t *log, FILE *fp)
-{
-	(void) fprintf(fp, "%lld, %lld, %lld, %s\n",
-	    (long long)log->lt_s_total,
-	    (long long)log->lt_s_count,
-	    (long long)log->lt_s_max,
-	    key);
-}
-
-/*
- * Initialization for kernel logging.
- */
-void
-lt_klog_init(void)
-{
-	if (klog_table != NULL || proc_table != NULL) {
-		return;
-	}
-
-	klog_table = g_hash_table_new_full(g_str_hash, g_str_equal,
-	    (GDestroyNotify)free, (GDestroyNotify)free);
-	lt_check_null(klog_table);
-
-	proc_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-	    NULL, (GDestroyNotify)free);
-	lt_check_null(proc_table);
-}
-
-/*
- * Set log file path.
- */
-int
-lt_klog_set_log_file(const char *filename)
-{
-	FILE *fp;
-	int file_exist;
-
-	g_assert(strlen(filename) < sizeof (klog_filename));
-
-	file_exist = lt_file_exist(filename);
-	/* Test if we can write to the file */
-	fp = fopen(filename, "a");
-
-	if (fp == NULL) {
-		return (-2);
-	}
-
-	(void) fclose(fp);
-	/* Don't leave empty file around */
-	if (!file_exist) {
-		(void) unlink(filename);
-	}
-
-	(void) strncpy(klog_filename, filename,
-	    sizeof (klog_filename));
-
-	return (0);
-}
-
-/*
- * Set log level.
- */
-int
-lt_klog_set_log_level(int level)
-{
-	if (level < 0 || level > (int)LT_KLOG_LEVEL_ALL) {
-		return (-1);
-	}
-
-	klog_level = level;
-
-	return (0);
-}
-
-/*
- * Write content to log file.
- */
-void
-lt_klog_write(void)
-{
-	FILE *fp;
-	char buffer[32];
-
-	if (klog_level == LT_KLOG_LEVEL_NONE) {
-		return;
-	}
-
-	g_assert(klog_table != NULL && proc_table != NULL);
-	fp = fopen(klog_filename, "a");
-
-	if (fp == NULL) {
-		return;
-	}
-
-	lt_time_str(buffer, sizeof (buffer));
-
-	(void) fprintf(fp, "# Log generated at %s by %s\n", buffer, TITLE);
-	(void) fprintf(fp, "# List of processes\n");
-	(void) fprintf(fp, "PID, CMD\n");
-	g_hash_table_foreach(proc_table, (GHFunc)print_proc, fp);
-
-	(void) fprintf(fp, "# Statistics\n");
-	(void) fprintf(fp, "TOTAL, COUNT, MAX, PID, KSTACK\n");
-	g_hash_table_foreach(klog_table, (GHFunc)print_stat, fp);
-
-	(void) fclose(fp);
-}
-
-/*
- * Clean up. It flushes all log content in memory to log file.
- */
-void
-lt_klog_deinit(void)
-{
-	if (klog_table != NULL) {
-		g_hash_table_destroy(klog_table);
-		klog_table = NULL;
-	}
-
-	if (proc_table != NULL) {
-		g_hash_table_destroy(proc_table);
-		proc_table = NULL;
-	}
-}
-
-/*
- * Write a kernel stack and its statistics to log file. Only "total" will
- * be logged, others are internally discarded.
- */
-/* ARGSUSED */
-void
-lt_klog_log(int level, pid_t pid, char *stack,
-	lt_stat_type_t type, uint64_t value)
-{
-	lt_stat_data_t *entry = NULL;
-	char *psargs;
-	char *str;
-	int str_len;
-
-	if ((level & klog_level) == 0) {
-		return;
-	}
-
-	g_assert(klog_table != NULL && proc_table != NULL);
-	psargs = (char *)g_hash_table_lookup(proc_table,
-	    LT_INT_TO_POINTER(pid));
-
-	if (psargs == NULL) {
-		psargs = lt_get_proc_field(pid, LT_FIELD_PSARGS);
-
-		if (psargs == NULL) {
-			psargs = lt_get_proc_field(pid, LT_FIELD_FNAME);
-		}
-
-		if (psargs == NULL) {
-			return;
-		}
-
-		g_hash_table_insert(proc_table,
-		    LT_INT_TO_POINTER(pid), psargs);
-	}
-
-	str_len = strlen(stack) + 20;
-	str = lt_malloc(str_len);
-	(void) snprintf(str, str_len, "%ld, \"%s\"", pid, stack);
-	entry = (lt_stat_data_t *)g_hash_table_lookup(klog_table, str);
-
-	if (entry == NULL) {
-		entry = (lt_stat_data_t *)lt_zalloc(sizeof (lt_stat_data_t));
-		g_hash_table_insert(klog_table, str, entry);
-	} else {
-		free(str);
-	}
-
-	lt_update_stat_value(entry, type, value);
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/klog.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,226 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <procfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "latencytop.h"
+
+static GHashTable *proc_table = NULL; /* pid -> char * */
+static GHashTable *klog_table = NULL; /* char * -> uint64_t total */
+static char klog_filename[PATH_MAX] = DEFAULT_KLOG_FILE;
+static int klog_level = LT_KLOG_LEVEL_NONE;
+
+static void
+print_proc(void *key, const char *args, FILE *fp)
+{
+	(void) fprintf(fp, "%-8ld \"%s\"\n", (long)key, args);
+}
+
+static void
+print_stat(const char *key, lt_stat_data_t *log, FILE *fp)
+{
+	(void) fprintf(fp, "%lld, %lld, %lld, %s\n",
+	    (long long)log->lt_s_total,
+	    (long long)log->lt_s_count,
+	    (long long)log->lt_s_max,
+	    key);
+}
+
+/*
+ * Initialization for kernel logging.
+ */
+void
+lt_klog_init(void)
+{
+	if (klog_table != NULL || proc_table != NULL) {
+		return;
+	}
+
+	klog_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+	    (GDestroyNotify)free, (GDestroyNotify)free);
+	lt_check_null(klog_table);
+
+	proc_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+	    NULL, (GDestroyNotify)free);
+	lt_check_null(proc_table);
+}
+
+/*
+ * Set log file path.
+ */
+int
+lt_klog_set_log_file(const char *filename)
+{
+	FILE *fp;
+	int file_exist;
+
+	g_assert(strlen(filename) < sizeof (klog_filename));
+
+	file_exist = lt_file_exist(filename);
+	/* Test if we can write to the file */
+	fp = fopen(filename, "a");
+
+	if (fp == NULL) {
+		return (-2);
+	}
+
+	(void) fclose(fp);
+	/* Don't leave empty file around */
+	if (!file_exist) {
+		(void) unlink(filename);
+	}
+
+	(void) strncpy(klog_filename, filename,
+	    sizeof (klog_filename));
+
+	return (0);
+}
+
+/*
+ * Set log level.
+ */
+int
+lt_klog_set_log_level(int level)
+{
+	if (level < 0 || level > (int)LT_KLOG_LEVEL_ALL) {
+		return (-1);
+	}
+
+	klog_level = level;
+
+	return (0);
+}
+
+/*
+ * Write content to log file.
+ */
+void
+lt_klog_write(void)
+{
+	FILE *fp;
+	char buffer[32];
+
+	if (klog_level == LT_KLOG_LEVEL_NONE) {
+		return;
+	}
+
+	g_assert(klog_table != NULL && proc_table != NULL);
+	fp = fopen(klog_filename, "a");
+
+	if (fp == NULL) {
+		return;
+	}
+
+	lt_time_str(buffer, sizeof (buffer));
+
+	(void) fprintf(fp, "# Log generated at %s by %s\n", buffer, TITLE);
+	(void) fprintf(fp, "# List of processes\n");
+	(void) fprintf(fp, "PID, CMD\n");
+	g_hash_table_foreach(proc_table, (GHFunc)print_proc, fp);
+
+	(void) fprintf(fp, "# Statistics\n");
+	(void) fprintf(fp, "TOTAL, COUNT, MAX, PID, KSTACK\n");
+	g_hash_table_foreach(klog_table, (GHFunc)print_stat, fp);
+
+	(void) fclose(fp);
+}
+
+/*
+ * Clean up. It flushes all log content in memory to log file.
+ */
+void
+lt_klog_deinit(void)
+{
+	if (klog_table != NULL) {
+		g_hash_table_destroy(klog_table);
+		klog_table = NULL;
+	}
+
+	if (proc_table != NULL) {
+		g_hash_table_destroy(proc_table);
+		proc_table = NULL;
+	}
+}
+
+/*
+ * Write a kernel stack and its statistics to log file. Only "total" will
+ * be logged, others are internally discarded.
+ */
+/* ARGSUSED */
+void
+lt_klog_log(int level, pid_t pid, char *stack,
+    lt_stat_type_t type, uint64_t value)
+{
+	lt_stat_data_t *entry = NULL;
+	char *psargs;
+	char *str;
+	int str_len;
+
+	if ((level & klog_level) == 0) {
+		return;
+	}
+
+	g_assert(klog_table != NULL && proc_table != NULL);
+	psargs = (char *)g_hash_table_lookup(proc_table,
+	    LT_INT_TO_POINTER(pid));
+
+	if (psargs == NULL) {
+		psargs = lt_get_proc_field(pid, LT_FIELD_PSARGS);
+
+		if (psargs == NULL) {
+			psargs = lt_get_proc_field(pid, LT_FIELD_FNAME);
+		}
+
+		if (psargs == NULL) {
+			return;
+		}
+
+		g_hash_table_insert(proc_table,
+		    LT_INT_TO_POINTER(pid), psargs);
+	}
+
+	str_len = strlen(stack) + 20;
+	str = lt_malloc(str_len);
+	(void) snprintf(str, str_len, "%ld, \"%s\"", pid, stack);
+	entry = (lt_stat_data_t *)g_hash_table_lookup(klog_table, str);
+
+	if (entry == NULL) {
+		entry = (lt_stat_data_t *)lt_zalloc(sizeof (lt_stat_data_t));
+		g_hash_table_insert(klog_table, str, entry);
+	} else {
+		free(str);
+	}
+
+	lt_update_stat_value(entry, type, value);
+}
--- old/usr/src/cmd/latencytop/common/latencytop.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,569 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <unistd.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <libgen.h>
-#include <signal.h>
-#include "latencytop.h"
-
-#define	CMPOPT(a, b)	strncmp((a), (b), sizeof (b))
-
-/*
- * This variable is used to check if "dynamic variable drop" in dtrace
- * has happened.
- */
-boolean_t lt_drop_detected = 0;
-
-lt_config_t g_config;
-
-typedef enum {
-	LT_CMDOPT_INTERVAL,
-	LT_CMDOPT_LOG_FILE,
-	LT_CMDOPT_LOG_LEVEL,
-	LT_CMDOPT_LOG_INTERVAL,
-	LT_CMDOPT_CONFIG_FILE,
-	LT_CMDOPT_F_FILTER,
-	LT_CMDOPT_F_SCHED,
-	LT_CMDOPT_F_SOBJ,
-	LT_CMDOPT_F_LOW,
-	LT_CMDOPT_SELECT,
-	LT_CMDOPT__LAST	/* Must be the last one */
-} lt_cmd_option_id_t;
-
-/*
- * Check for duplicate command line options.
- * Returns TRUE if duplicate options with different values are found,
- * returns FALSE otherwise.
- */
-static int
-check_opt_dup(lt_cmd_option_id_t id, uint64_t value) {
-
-	static int opt_set[(int)LT_CMDOPT__LAST];
-	static uint64_t opt_val[(int)LT_CMDOPT__LAST];
-
-	const char *errmsg[] = {
-		"-t is set more than once with different values.",
-		"-o is set more than once.",
-		"-k is set more than once with different values.",
-		"-l is set more than once with different values.",
-		"-c is set more than once.",
-		"-f [no]filter is set more than once with different values.",
-		"-f [no]sched is set more than once with different values.",
-		"-f [no]sobj is set more than once with different values.",
-		"-f [no]low is set more than once with different values.",
-		"-s is set more than once with different values."
-	};
-
-	g_assert(sizeof (errmsg)/sizeof (errmsg[0]) == (int)LT_CMDOPT__LAST);
-
-	if (!opt_set[(int)id]) {
-		opt_set[(int)id] = TRUE;
-		opt_val[(int)id] = value;
-		return (FALSE);
-	}
-
-	if (opt_val[(int)id] != value) {
-		(void) fprintf(stderr, "%s\n", errmsg[(int)id]);
-		return (TRUE);
-	}
-
-	return (FALSE);
-}
-
-/*
- * Print command-line help message.
- */
-static void
-print_usage(const char *execname, int long_help)
-{
-	char buffer[PATH_MAX];
-	(void) snprintf(buffer, sizeof (buffer), "%s", execname);
-
-	if (!long_help) {
-		/* Print short help to stderr. */
-		(void) fprintf(stderr, "Usage: %s [option(s)], ",
-		    basename(buffer));
-		(void) fprintf(stderr, "use '%s -h' for details.\n",
-		    basename(buffer));
-		return;
-	}
-
-	(void) printf("Usage: %s [option(s)]\n", basename(buffer));
-	(void) printf("Options:\n"
-	    "    -h, --help\n"
-	    "        Print this help.\n"
-	    "    -t, --interval TIME\n"
-	    "        Set refresh interval to TIME. "
-	    "Valid range [1...60] seconds, default = 5\n"
-	/*
-	 * Option "-c, --config FILE" is not user-visible for now.
-	 * When we have chance to properly document the format of translation
-	 * rules, we'll make it user-visible.
-	 */
-	    "    -o, --output-log-file FILE\n"
-	    "        Output kernel log to FILE. Default = "
-	    DEFAULT_KLOG_FILE "\n"
-	    "    -k, --kernel-log-level LEVEL\n"
-	    "        Set kernel log level to LEVEL.\n"
-	    "        0(default) = None, 1 = Unmapped, 2 = Mapped, 3 = All.\n"
-	    "    -f, --feature [no]feature1,[no]feature2,...\n"
-	    "        Enable/disable features in LatencyTOP.\n"
-	    "        [no]filter:\n"
-	    "        Filter large interruptible latencies, e.g. sleep.\n"
-	    "        [no]sched:\n"
-	    "        Monitors sched (PID=0).\n"
-	    "        [no]sobj:\n"
-	    "        Monitors synchronization objects.\n"
-	    "        [no]low:\n"
-	    "        Lower overhead by sampling small latencies.\n"
-	    "    -l, --log-period TIME\n"
-	    "        Write and restart log every TIME seconds, TIME >= 60\n"
-	    "    -s --select [ pid=<pid> | pgid=<pgid> ]\n"
-	    "        Monitor only the given process or processes in the "
-	    "given process group.\n");
-}
-
-/*
- * Properly exit latencytop when it receives SIGINT or SIGTERM.
- */
-/* ARGSUSED */
-static void
-signal_handler(int sig)
-{
-	lt_gpipe_break("q");
-}
-
-/*
- * Convert string to integer. It returns error if extra characters are found.
- */
-static int
-to_int(const char *str, int *result)
-{
-	char *tail = NULL;
-	long ret;
-
-	if (str == NULL || result == NULL) {
-		return (-1);
-	}
-
-	ret = strtol(str, &tail, 10);
-
-	if (tail != NULL && *tail != '\0') {
-		return (-1);
-	}
-
-	*result = (int)ret;
-
-	return (0);
-}
-
-/*
- * The main function.
- */
-int
-main(int argc, char *argv[])
-{
-	const char *opt_string = "t:o:k:hf:l:c:s:";
-	struct option const longopts[] = {
-		{"interval", required_argument, NULL, 't'},
-		{"output-log-file", required_argument, NULL, 'o'},
-		{"kernel-log-level", required_argument, NULL, 'k'},
-		{"help", no_argument, NULL, 'h'},
-		{"feature", required_argument, NULL, 'f'},
-		{"log-period", required_argument, NULL, 'l'},
-		{"config", required_argument, NULL, 'c'},
-		{"select", required_argument, NULL, 's'},
-		{NULL, 0, NULL, 0}
-	};
-
-	int optc;
-	int longind = 0;
-	int running = 1;
-	int unknown_option = FALSE;
-	int refresh_interval = 5;
-	int klog_level = 0;
-	int log_interval = 0;
-	long long last_logged = 0;
-	char *token = NULL;
-	int retval = 0;
-	int gpipe;
-	int err;
-	uint64_t collect_end;
-	uint64_t current_time;
-	uint64_t delta_time;
-	char logfile[PATH_MAX] = "";
-	int select_id;
-	int select_value;
-	char *select_str;
-	boolean_t no_dtrace_cleanup = B_TRUE;
-
-	lt_gpipe_init();
-	(void) signal(SIGINT, signal_handler);
-	(void) signal(SIGTERM, signal_handler);
-
-	/* Default global settings */
-	g_config.lt_cfg_enable_filter = 0;
-	g_config.lt_cfg_trace_sched = 0;
-	g_config.lt_cfg_trace_syncobj = 1;
-	g_config.lt_cfg_low_overhead_mode = 0;
-	g_config.lt_cfg_trace_pid = 0;
-	g_config.lt_cfg_trace_pgid = 0;
-	/* dtrace snapshot every 1 second */
-	g_config.lt_cfg_snap_interval = 1000;
-#ifdef EMBED_CONFIGS
-	g_config.lt_cfg_config_name = NULL;
-#else
-	g_config.lt_cfg_config_name = lt_strdup(DEFAULT_CONFIG_NAME);
-#endif
-
-	/* Parse command line arguments. */
-	while ((optc = getopt_long(argc, argv, opt_string,
-	    longopts, &longind)) != -1) {
-		switch (optc) {
-		case 'h':
-			print_usage(argv[0], TRUE);
-			goto end_none;
-		case 't':
-			if (to_int(optarg, &refresh_interval) != 0 ||
-			    refresh_interval < 1 || refresh_interval > 60) {
-				lt_display_error(
-				    "Invalid refresh interval: %s\n", optarg);
-				unknown_option = TRUE;
-			} else if (check_opt_dup(LT_CMDOPT_INTERVAL,
-			    refresh_interval)) {
-				unknown_option = TRUE;
-			}
-
-			break;
-		case 'k':
-			if (to_int(optarg, &klog_level) != 0 ||
-			    lt_klog_set_log_level(klog_level) != 0) {
-				lt_display_error(
-				    "Invalid log level: %s\n", optarg);
-				unknown_option = TRUE;
-			} else if (check_opt_dup(LT_CMDOPT_LOG_LEVEL,
-			    refresh_interval)) {
-				unknown_option = TRUE;
-			}
-
-			break;
-		case 'o':
-			if (check_opt_dup(LT_CMDOPT_LOG_FILE, optind)) {
-				unknown_option = TRUE;
-			} else if (strlen(optarg) >= sizeof (logfile)) {
-				lt_display_error(
-				    "Log file name is too long: %s\n",
-				    optarg);
-				unknown_option = TRUE;
-			} else {
-				(void) strncpy(logfile, optarg,
-				    sizeof (logfile));
-			}
-
-			break;
-		case 'f':
-			for (token = strtok(optarg, ","); token != NULL;
-			    token = strtok(NULL, ",")) {
-				int v = TRUE;
-
-				if (strncmp(token, "no", 2) == 0) {
-					v = FALSE;
-					token = &token[2];
-				}
-
-				if (CMPOPT(token, "filter") == 0) {
-					if (check_opt_dup(LT_CMDOPT_F_FILTER,
-					    v)) {
-						unknown_option = TRUE;
-					} else {
-						g_config.lt_cfg_enable_filter
-						    = v;
-					}
-				} else if (CMPOPT(token, "sched") == 0) {
-					if (check_opt_dup(LT_CMDOPT_F_SCHED,
-					    v)) {
-						unknown_option = TRUE;
-					} else {
-						g_config.lt_cfg_trace_sched
-						    = v;
-					}
-				} else if (CMPOPT(token, "sobj") == 0) {
-					if (check_opt_dup(LT_CMDOPT_F_SOBJ,
-					    v)) {
-						unknown_option = TRUE;
-					} else {
-						g_config.lt_cfg_trace_syncobj
-						    = v;
-					}
-				} else if (CMPOPT(token, "low") == 0) {
-					if (check_opt_dup(LT_CMDOPT_F_LOW,
-					    v)) {
-						unknown_option = TRUE;
-					} else {
-						g_config.
-						    lt_cfg_low_overhead_mode
-						    = v;
-					}
-				} else {
-					lt_display_error(
-					    "Unknown feature: %s\n", token);
-					unknown_option = TRUE;
-				}
-			}
-
-			break;
-		case 'l':
-			if (to_int(optarg, &log_interval) != 0 ||
-			    log_interval < 60) {
-				lt_display_error(
-				    "Invalid log interval: %s\n", optarg);
-				unknown_option = TRUE;
-			} else if (check_opt_dup(LT_CMDOPT_LOG_INTERVAL,
-			    log_interval)) {
-				unknown_option = TRUE;
-			}
-
-			break;
-		case 'c':
-			if (strlen(optarg) >= PATH_MAX) {
-				lt_display_error(
-				    "Configuration name is too long.\n");
-				unknown_option = TRUE;
-			} else if (check_opt_dup(LT_CMDOPT_CONFIG_FILE,
-			    optind)) {
-				unknown_option = TRUE;
-			} else {
-				g_config.lt_cfg_config_name =
-				    lt_strdup(optarg);
-			}
-
-			break;
-		case 's':
-			if (strncmp(optarg, "pid=", 4) == 0) {
-				select_id = 0;
-				select_str = &optarg[4];
-			} else if (strncmp(optarg, "pgid=", 5) == 0) {
-				select_id = 1;
-				select_str = &optarg[5];
-			} else {
-				lt_display_error(
-				    "Invalid select option: %s\n", optarg);
-				unknown_option = TRUE;
-				break;
-			}
-
-			if (to_int(select_str, &select_value) != 0) {
-				lt_display_error(
-				    "Invalid select option: %s\n", optarg);
-				unknown_option = TRUE;
-				break;
-			}
-
-			if (select_value <= 0) {
-				lt_display_error(
-				    "Process/process group ID must be "
-				    "greater than 0: %s\n", optarg);
-				unknown_option = TRUE;
-				break;
-			}
-
-			if (check_opt_dup(LT_CMDOPT_SELECT,
-			    (((uint64_t)select_id) << 32) | select_value)) {
-				unknown_option = TRUE;
-				break;
-			}
-
-			if (select_id == 0) {
-				g_config.lt_cfg_trace_pid = select_value;
-			} else {
-				g_config.lt_cfg_trace_pgid = select_value;
-			}
-			break;
-		default:
-			unknown_option = TRUE;
-			break;
-		}
-	}
-
-	if (!unknown_option && strlen(logfile) > 0) {
-		err = lt_klog_set_log_file(logfile);
-
-		if (err == -1) {
-			lt_display_error("Log file name is too long: %s\n",
-			    logfile);
-			unknown_option = TRUE;
-		} else if (err == -2) {
-			lt_display_error("Cannot write to log file: %s\n",
-			    logfile);
-			unknown_option = TRUE;
-		}
-	}
-
-	/* Throw error for invalid/junk arguments */
-	if (optind  < argc) {
-		int tmpind = optind;
-		(void) fprintf(stderr, "Unknown option(s): ");
-
-		while (tmpind < argc) {
-			(void) fprintf(stderr, "%s ", argv[tmpind++]);
-		}
-
-		(void) fprintf(stderr, "\n");
-		unknown_option = TRUE;
-	}
-
-	if (unknown_option) {
-		print_usage(argv[0], FALSE);
-		retval = 1;
-		goto end_none;
-	}
-
-	(void) printf("%s\n%s\n", TITLE, COPYRIGHT);
-
-	/*
-	 * Initialization
-	 */
-	lt_klog_init();
-
-	if (lt_table_init() != 0) {
-		lt_display_error("Unable to load configuration table.\n");
-		retval = 1;
-		goto end_notable;
-	}
-
-	if (lt_dtrace_init() != 0) {
-		lt_display_error("Unable to initialize dtrace.\n");
-		retval = 1;
-		goto end_nodtrace;
-	}
-
-	last_logged = lt_millisecond();
-
-	(void) printf("Collecting data for %d seconds...\n",
-	    refresh_interval);
-
-	gpipe = lt_gpipe_readfd();
-	collect_end = last_logged + refresh_interval * 1000;
-	for (;;) {
-		fd_set read_fd;
-		struct timeval timeout;
-		int tsleep = collect_end - lt_millisecond();
-
-		if (tsleep <= 0) {
-			break;
-		}
-
-		/*
-		 * Interval when we call dtrace_status() and collect
-		 * aggregated data.
-		 */
-		if (tsleep > g_config.lt_cfg_snap_interval) {
-			tsleep = g_config.lt_cfg_snap_interval;
-		}
-
-		timeout.tv_sec = tsleep / 1000;
-		timeout.tv_usec = (tsleep % 1000) * 1000;
-
-		FD_ZERO(&read_fd);
-		FD_SET(gpipe, &read_fd);
-
-		if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
-			goto end_ubreak;
-		}
-
-		(void) lt_dtrace_work(0);
-	}
-
-	lt_display_init();
-
-	do {
-		current_time = lt_millisecond();
-
-		lt_stat_clear_all();
-		(void) lt_dtrace_collect();
-
-		delta_time = current_time;
-		current_time = lt_millisecond();
-		delta_time = current_time - delta_time;
-
-		if (log_interval > 0 &&
-		    current_time - last_logged > log_interval * 1000) {
-			lt_klog_write();
-			last_logged = current_time;
-		}
-
-		running = lt_display_loop(refresh_interval * 1000 -
-		    delta_time);
-
-		/*
-		 * This is to avoid dynamic variable drop
-		 * in DTrace.
-		 */
-		if (lt_drop_detected == B_TRUE) {
-			if (lt_dtrace_deinit() != 0) {
-				no_dtrace_cleanup = B_FALSE;
-				retval = 1;
-				break;
-			}
-
-			lt_drop_detected = B_FALSE;
-			if (lt_dtrace_init() != 0) {
-				retval = 1;
-				break;
-			}
-		}
-	} while (running != 0);
-
-	lt_klog_write();
-
-	/* Cleanup */
-	lt_display_deinit();
-
-end_ubreak:
-	if (no_dtrace_cleanup == B_FALSE || lt_dtrace_deinit() != 0)
-		retval = 1;
-
-	lt_stat_free_all();
-
-end_nodtrace:
-	lt_table_deinit();
-
-end_notable:
-	lt_klog_deinit();
-
-end_none:
-	lt_gpipe_deinit();
-
-	if (g_config.lt_cfg_config_name != NULL) {
-		free(g_config.lt_cfg_config_name);
-	}
-
-	return (retval);
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/latencytop.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,570 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <libgen.h>
+#include <signal.h>
+#include "latencytop.h"
+
+#define	CMPOPT(a, b)	strncmp((a), (b), sizeof (b))
+
+/*
+ * This variable is used to check if "dynamic variable drop" in dtrace
+ * has happened.
+ */
+boolean_t lt_drop_detected = 0;
+
+lt_config_t g_config;
+
+typedef enum {
+	LT_CMDOPT_INTERVAL,
+	LT_CMDOPT_LOG_FILE,
+	LT_CMDOPT_LOG_LEVEL,
+	LT_CMDOPT_LOG_INTERVAL,
+	LT_CMDOPT_CONFIG_FILE,
+	LT_CMDOPT_F_FILTER,
+	LT_CMDOPT_F_SCHED,
+	LT_CMDOPT_F_SOBJ,
+	LT_CMDOPT_F_LOW,
+	LT_CMDOPT_SELECT,
+	LT_CMDOPT__LAST	/* Must be the last one */
+} lt_cmd_option_id_t;
+
+/*
+ * Check for duplicate command line options.
+ * Returns TRUE if duplicate options with different values are found,
+ * returns FALSE otherwise.
+ */
+static int
+check_opt_dup(lt_cmd_option_id_t id, uint64_t value)
+{
+
+	static int opt_set[(int)LT_CMDOPT__LAST];
+	static uint64_t opt_val[(int)LT_CMDOPT__LAST];
+
+	const char *errmsg[] = {
+		"-t is set more than once with different values.",
+		"-o is set more than once.",
+		"-k is set more than once with different values.",
+		"-l is set more than once with different values.",
+		"-c is set more than once.",
+		"-f [no]filter is set more than once with different values.",
+		"-f [no]sched is set more than once with different values.",
+		"-f [no]sobj is set more than once with different values.",
+		"-f [no]low is set more than once with different values.",
+		"-s is set more than once with different values."
+	};
+
+	g_assert(sizeof (errmsg)/sizeof (errmsg[0]) == (int)LT_CMDOPT__LAST);
+
+	if (!opt_set[(int)id]) {
+		opt_set[(int)id] = TRUE;
+		opt_val[(int)id] = value;
+		return (FALSE);
+	}
+
+	if (opt_val[(int)id] != value) {
+		(void) fprintf(stderr, "%s\n", errmsg[(int)id]);
+		return (TRUE);
+	}
+
+	return (FALSE);
+}
+
+/*
+ * Print command-line help message.
+ */
+static void
+print_usage(const char *execname, int long_help)
+{
+	char buffer[PATH_MAX];
+	(void) snprintf(buffer, sizeof (buffer), "%s", execname);
+
+	if (!long_help) {
+		/* Print short help to stderr. */
+		(void) fprintf(stderr, "Usage: %s [option(s)], ",
+		    basename(buffer));
+		(void) fprintf(stderr, "use '%s -h' for details.\n",
+		    basename(buffer));
+		return;
+	}
+
+	(void) printf("Usage: %s [option(s)]\n", basename(buffer));
+	(void) printf("Options:\n"
+	    "    -h, --help\n"
+	    "        Print this help.\n"
+	    "    -t, --interval TIME\n"
+	    "        Set refresh interval to TIME. "
+	    "Valid range [1...60] seconds, default = 5\n"
+	/*
+	 * Option "-c, --config FILE" is not user-visible for now.
+	 * When we have chance to properly document the format of translation
+	 * rules, we'll make it user-visible.
+	 */
+	    "    -o, --output-log-file FILE\n"
+	    "        Output kernel log to FILE. Default = "
+	    DEFAULT_KLOG_FILE "\n"
+	    "    -k, --kernel-log-level LEVEL\n"
+	    "        Set kernel log level to LEVEL.\n"
+	    "        0(default) = None, 1 = Unmapped, 2 = Mapped, 3 = All.\n"
+	    "    -f, --feature [no]feature1,[no]feature2,...\n"
+	    "        Enable/disable features in LatencyTOP.\n"
+	    "        [no]filter:\n"
+	    "        Filter large interruptible latencies, e.g. sleep.\n"
+	    "        [no]sched:\n"
+	    "        Monitors sched (PID=0).\n"
+	    "        [no]sobj:\n"
+	    "        Monitors synchronization objects.\n"
+	    "        [no]low:\n"
+	    "        Lower overhead by sampling small latencies.\n"
+	    "    -l, --log-period TIME\n"
+	    "        Write and restart log every TIME seconds, TIME >= 60\n"
+	    "    -s --select [ pid=<pid> | pgid=<pgid> ]\n"
+	    "        Monitor only the given process or processes in the "
+	    "given process group.\n");
+}
+
+/*
+ * Properly exit latencytop when it receives SIGINT or SIGTERM.
+ */
+/* ARGSUSED */
+static void
+signal_handler(int sig)
+{
+	lt_gpipe_break("q");
+}
+
+/*
+ * Convert string to integer. It returns error if extra characters are found.
+ */
+static int
+to_int(const char *str, int *result)
+{
+	char *tail = NULL;
+	long ret;
+
+	if (str == NULL || result == NULL) {
+		return (-1);
+	}
+
+	ret = strtol(str, &tail, 10);
+
+	if (tail != NULL && *tail != '\0') {
+		return (-1);
+	}
+
+	*result = (int)ret;
+
+	return (0);
+}
+
+/*
+ * The main function.
+ */
+int
+main(int argc, char *argv[])
+{
+	const char *opt_string = "t:o:k:hf:l:c:s:";
+	struct option const longopts[] = {
+		{"interval", required_argument, NULL, 't'},
+		{"output-log-file", required_argument, NULL, 'o'},
+		{"kernel-log-level", required_argument, NULL, 'k'},
+		{"help", no_argument, NULL, 'h'},
+		{"feature", required_argument, NULL, 'f'},
+		{"log-period", required_argument, NULL, 'l'},
+		{"config", required_argument, NULL, 'c'},
+		{"select", required_argument, NULL, 's'},
+		{NULL, 0, NULL, 0}
+	};
+
+	int optc;
+	int longind = 0;
+	int running = 1;
+	int unknown_option = FALSE;
+	int refresh_interval = 5;
+	int klog_level = 0;
+	int log_interval = 0;
+	long long last_logged = 0;
+	char *token = NULL;
+	int retval = 0;
+	int gpipe;
+	int err;
+	uint64_t collect_end;
+	uint64_t current_time;
+	uint64_t delta_time;
+	char logfile[PATH_MAX] = "";
+	int select_id;
+	int select_value;
+	char *select_str;
+	boolean_t no_dtrace_cleanup = B_TRUE;
+
+	lt_gpipe_init();
+	(void) signal(SIGINT, signal_handler);
+	(void) signal(SIGTERM, signal_handler);
+
+	/* Default global settings */
+	g_config.lt_cfg_enable_filter = 0;
+	g_config.lt_cfg_trace_sched = 0;
+	g_config.lt_cfg_trace_syncobj = 1;
+	g_config.lt_cfg_low_overhead_mode = 0;
+	g_config.lt_cfg_trace_pid = 0;
+	g_config.lt_cfg_trace_pgid = 0;
+	/* dtrace snapshot every 1 second */
+	g_config.lt_cfg_snap_interval = 1000;
+#ifdef EMBED_CONFIGS
+	g_config.lt_cfg_config_name = NULL;
+#else
+	g_config.lt_cfg_config_name = lt_strdup(DEFAULT_CONFIG_NAME);
+#endif
+
+	/* Parse command line arguments. */
+	while ((optc = getopt_long(argc, argv, opt_string,
+	    longopts, &longind)) != -1) {
+		switch (optc) {
+		case 'h':
+			print_usage(argv[0], TRUE);
+			goto end_none;
+		case 't':
+			if (to_int(optarg, &refresh_interval) != 0 ||
+			    refresh_interval < 1 || refresh_interval > 60) {
+				lt_display_error(
+				    "Invalid refresh interval: %s\n", optarg);
+				unknown_option = TRUE;
+			} else if (check_opt_dup(LT_CMDOPT_INTERVAL,
+			    refresh_interval)) {
+				unknown_option = TRUE;
+			}
+
+			break;
+		case 'k':
+			if (to_int(optarg, &klog_level) != 0 ||
+			    lt_klog_set_log_level(klog_level) != 0) {
+				lt_display_error(
+				    "Invalid log level: %s\n", optarg);
+				unknown_option = TRUE;
+			} else if (check_opt_dup(LT_CMDOPT_LOG_LEVEL,
+			    refresh_interval)) {
+				unknown_option = TRUE;
+			}
+
+			break;
+		case 'o':
+			if (check_opt_dup(LT_CMDOPT_LOG_FILE, optind)) {
+				unknown_option = TRUE;
+			} else if (strlen(optarg) >= sizeof (logfile)) {
+				lt_display_error(
+				    "Log file name is too long: %s\n",
+				    optarg);
+				unknown_option = TRUE;
+			} else {
+				(void) strncpy(logfile, optarg,
+				    sizeof (logfile));
+			}
+
+			break;
+		case 'f':
+			for (token = strtok(optarg, ","); token != NULL;
+			    token = strtok(NULL, ",")) {
+				int v = TRUE;
+
+				if (strncmp(token, "no", 2) == 0) {
+					v = FALSE;
+					token = &token[2];
+				}
+
+				if (CMPOPT(token, "filter") == 0) {
+					if (check_opt_dup(LT_CMDOPT_F_FILTER,
+					    v)) {
+						unknown_option = TRUE;
+					} else {
+						g_config.lt_cfg_enable_filter
+						    = v;
+					}
+				} else if (CMPOPT(token, "sched") == 0) {
+					if (check_opt_dup(LT_CMDOPT_F_SCHED,
+					    v)) {
+						unknown_option = TRUE;
+					} else {
+						g_config.lt_cfg_trace_sched
+						    = v;
+					}
+				} else if (CMPOPT(token, "sobj") == 0) {
+					if (check_opt_dup(LT_CMDOPT_F_SOBJ,
+					    v)) {
+						unknown_option = TRUE;
+					} else {
+						g_config.lt_cfg_trace_syncobj
+						    = v;
+					}
+				} else if (CMPOPT(token, "low") == 0) {
+					if (check_opt_dup(LT_CMDOPT_F_LOW,
+					    v)) {
+						unknown_option = TRUE;
+					} else {
+						g_config.
+						    lt_cfg_low_overhead_mode
+						    = v;
+					}
+				} else {
+					lt_display_error(
+					    "Unknown feature: %s\n", token);
+					unknown_option = TRUE;
+				}
+			}
+
+			break;
+		case 'l':
+			if (to_int(optarg, &log_interval) != 0 ||
+			    log_interval < 60) {
+				lt_display_error(
+				    "Invalid log interval: %s\n", optarg);
+				unknown_option = TRUE;
+			} else if (check_opt_dup(LT_CMDOPT_LOG_INTERVAL,
+			    log_interval)) {
+				unknown_option = TRUE;
+			}
+
+			break;
+		case 'c':
+			if (strlen(optarg) >= PATH_MAX) {
+				lt_display_error(
+				    "Configuration name is too long.\n");
+				unknown_option = TRUE;
+			} else if (check_opt_dup(LT_CMDOPT_CONFIG_FILE,
+			    optind)) {
+				unknown_option = TRUE;
+			} else {
+				g_config.lt_cfg_config_name =
+				    lt_strdup(optarg);
+			}
+
+			break;
+		case 's':
+			if (strncmp(optarg, "pid=", 4) == 0) {
+				select_id = 0;
+				select_str = &optarg[4];
+			} else if (strncmp(optarg, "pgid=", 5) == 0) {
+				select_id = 1;
+				select_str = &optarg[5];
+			} else {
+				lt_display_error(
+				    "Invalid select option: %s\n", optarg);
+				unknown_option = TRUE;
+				break;
+			}
+
+			if (to_int(select_str, &select_value) != 0) {
+				lt_display_error(
+				    "Invalid select option: %s\n", optarg);
+				unknown_option = TRUE;
+				break;
+			}
+
+			if (select_value <= 0) {
+				lt_display_error(
+				    "Process/process group ID must be "
+				    "greater than 0: %s\n", optarg);
+				unknown_option = TRUE;
+				break;
+			}
+
+			if (check_opt_dup(LT_CMDOPT_SELECT,
+			    (((uint64_t)select_id) << 32) | select_value)) {
+				unknown_option = TRUE;
+				break;
+			}
+
+			if (select_id == 0) {
+				g_config.lt_cfg_trace_pid = select_value;
+			} else {
+				g_config.lt_cfg_trace_pgid = select_value;
+			}
+			break;
+		default:
+			unknown_option = TRUE;
+			break;
+		}
+	}
+
+	if (!unknown_option && strlen(logfile) > 0) {
+		err = lt_klog_set_log_file(logfile);
+
+		if (err == -1) {
+			lt_display_error("Log file name is too long: %s\n",
+			    logfile);
+			unknown_option = TRUE;
+		} else if (err == -2) {
+			lt_display_error("Cannot write to log file: %s\n",
+			    logfile);
+			unknown_option = TRUE;
+		}
+	}
+
+	/* Throw error for invalid/junk arguments */
+	if (optind  < argc) {
+		int tmpind = optind;
+		(void) fprintf(stderr, "Unknown option(s): ");
+
+		while (tmpind < argc) {
+			(void) fprintf(stderr, "%s ", argv[tmpind++]);
+		}
+
+		(void) fprintf(stderr, "\n");
+		unknown_option = TRUE;
+	}
+
+	if (unknown_option) {
+		print_usage(argv[0], FALSE);
+		retval = 1;
+		goto end_none;
+	}
+
+	(void) printf("%s\n%s\n", TITLE, COPYRIGHT);
+
+	/*
+	 * Initialization
+	 */
+	lt_klog_init();
+
+	if (lt_table_init() != 0) {
+		lt_display_error("Unable to load configuration table.\n");
+		retval = 1;
+		goto end_notable;
+	}
+
+	if (lt_dtrace_init() != 0) {
+		lt_display_error("Unable to initialize dtrace.\n");
+		retval = 1;
+		goto end_nodtrace;
+	}
+
+	last_logged = lt_millisecond();
+
+	(void) printf("Collecting data for %d seconds...\n",
+	    refresh_interval);
+
+	gpipe = lt_gpipe_readfd();
+	collect_end = last_logged + refresh_interval * 1000;
+	for (;;) {
+		fd_set read_fd;
+		struct timeval timeout;
+		int tsleep = collect_end - lt_millisecond();
+
+		if (tsleep <= 0) {
+			break;
+		}
+
+		/*
+		 * Interval when we call dtrace_status() and collect
+		 * aggregated data.
+		 */
+		if (tsleep > g_config.lt_cfg_snap_interval) {
+			tsleep = g_config.lt_cfg_snap_interval;
+		}
+
+		timeout.tv_sec = tsleep / 1000;
+		timeout.tv_usec = (tsleep % 1000) * 1000;
+
+		FD_ZERO(&read_fd);
+		FD_SET(gpipe, &read_fd);
+
+		if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
+			goto end_ubreak;
+		}
+
+		(void) lt_dtrace_work(0);
+	}
+
+	lt_display_init();
+
+	do {
+		current_time = lt_millisecond();
+
+		lt_stat_clear_all();
+		(void) lt_dtrace_collect();
+
+		delta_time = current_time;
+		current_time = lt_millisecond();
+		delta_time = current_time - delta_time;
+
+		if (log_interval > 0 &&
+		    current_time - last_logged > log_interval * 1000) {
+			lt_klog_write();
+			last_logged = current_time;
+		}
+
+		running = lt_display_loop(refresh_interval * 1000 -
+		    delta_time);
+
+		/*
+		 * This is to avoid dynamic variable drop
+		 * in DTrace.
+		 */
+		if (lt_drop_detected == B_TRUE) {
+			if (lt_dtrace_deinit() != 0) {
+				no_dtrace_cleanup = B_FALSE;
+				retval = 1;
+				break;
+			}
+
+			lt_drop_detected = B_FALSE;
+			if (lt_dtrace_init() != 0) {
+				retval = 1;
+				break;
+			}
+		}
+	} while (running != 0);
+
+	lt_klog_write();
+
+	/* Cleanup */
+	lt_display_deinit();
+
+end_ubreak:
+	if (no_dtrace_cleanup == B_FALSE || lt_dtrace_deinit() != 0)
+		retval = 1;
+
+	lt_stat_free_all();
+
+end_nodtrace:
+	lt_table_deinit();
+
+end_notable:
+	lt_klog_deinit();
+
+end_none:
+	lt_gpipe_deinit();
+
+	if (g_config.lt_cfg_config_name != NULL) {
+		free(g_config.lt_cfg_config_name);
+	}
+
+	return (retval);
+}
--- old/usr/src/cmd/latencytop/common/latencytop.d	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,421 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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.
- */
-
-#define	MAX_TAG		8
-#define	MAX_STACK	64
-
-#pragma D option aggsize=8m
-#pragma D option bufsize=16m
-#pragma D option dynvarsize=16m
-#pragma D option aggrate=0
-#pragma D option stackframes=MAX_STACK
-/*
- * Our D script needs to compile even if some of the TRANSLATE probes cannot
- * be found. Missing probes can be caused by older kernel, different
- * architecture, unloaded modules etc.
- */
-#pragma D option zdefs
-
-#if defined(ENABLE_SCHED)
-#if defined(TRACE_PID)
-#define TRACE_FILTER    / pid == 0 || pid == TRACE_PID /
-#define TRACE_FILTER_COND(a)    / (pid == 0 || pid == TRACE_PID) && (a) /
-#elif defined(TRACE_PGID)
-#define TRACE_FILTER    / pid == 0 || curpsinfo->pr_pgid == TRACE_PGID /
-#define TRACE_FILTER_COND(a)
-    / (pid == 0 || curpsinfo->pr_pgid == TRACE_PGID) && (a) /
-#else
-#define TRACE_FILTER
-#define TRACE_FILTER_COND(a)	/ (a) /
-#endif
-#else	/* ENABLE_SCHED */
-#if defined(TRACE_PID)
-#define TRACE_FILTER    / pid == TRACE_PID /
-#define TRACE_FILTER_COND(a)    / (pid == TRACE_PID) && (a) /
-#elif defined(TRACE_PGID)
-#define TRACE_FILTER    / curpsinfo->pr_pgid == TRACE_PGID /
-#define TRACE_FILTER_COND(a)    / (curpsinfo->pr_pgid == TRACE_PGID) && (a) /
-#else
-#define TRACE_FILTER	/ pid != 0 /
-#define TRACE_FILTER_COND(a)    / (pid != 0) && (a) /
-#endif
-#endif /* ENABLE_SCHED */
-
-/* Threshold to filter WAKEABLE latencies. */
-#define FILTER_THRESHOLD	5000000
-/* From thread.h */
-#define T_WAKEABLE		2
-
-/*
- * This array is used to store timestamp of when threads are enqueued
- * to dispatch queue.
- * self-> is not accessible when enqueue happens.
- */
-unsigned long long lt_timestamps[int, int];
-
-self unsigned int lt_is_block_wakeable;
-self unsigned long long lt_sleep_start;
-self unsigned long long lt_sleep_duration;
-self unsigned long long lt_sch_delay;
-self unsigned int lt_counter;		/* only used in low overhead */
-self unsigned long long lt_timestamp;	/* only used in low overhead */
-self unsigned int lt_stackp;
-self unsigned int lt_prio[int];
-self string lt_cause[int];
-
-this unsigned int priority;
-this string cause;
-
-/*
- * Clean up everything, otherwise we will run out of memory.
- */
-proc:::lwp-exit
-{
-	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0;
-
-	self->lt_sleep_start = 0;
-	self->lt_is_block_wakeable = 0;
-	self->lt_counter = 0;
-	self->lt_timestamp = 0;
-
-	/*
-	 * Workaround: no way to clear associative array.
-	 * We have to manually clear 0 ~ (MAX_TAG-1).
-	 */
-
-	self->lt_prio[0] = 0;
-	self->lt_prio[1] = 0;
-	self->lt_prio[2] = 0;
-	self->lt_prio[3] = 0;
-	self->lt_prio[4] = 0;
-	self->lt_prio[5] = 0;
-	self->lt_prio[6] = 0;
-	self->lt_prio[7] = 0;
-
-	self->lt_cause[0] = 0;
-	self->lt_cause[1] = 0;
-	self->lt_cause[2] = 0;
-	self->lt_cause[3] = 0;
-	self->lt_cause[4] = 0;
-	self->lt_cause[5] = 0;
-	self->lt_cause[6] = 0;
-	self->lt_cause[7] = 0;
-}
-
-#if !defined(ENABLE_LOW_OVERHEAD)
-/*
- * Log timestamp when a thread is taken off the CPU.
- */
-sched::resume:off-cpu
-TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP)
-{
-	self->lt_sleep_start = timestamp;
-	self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE;
-
-	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] =
-	    self->lt_sleep_start;
-}
-
-/*
- * Log timestamp when a thread is put on a dispatch queue and becomes runnable.
- */
-sched:::enqueue
-/lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/
-{
-	lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] = timestamp;
-}
-
-/*
- * Calculate latency when the thread is actually on the CPU.
- * This is necessary in order to get the right stack.
- */
-this unsigned long long end;
-this unsigned long long now;
-sched::resume:on-cpu
-/self->lt_sleep_start != 0/
-{
-	this->end = lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid];
-	this->now = timestamp;
-	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0;
-	this->end = (this->end != 0 && this->end != self->lt_sleep_start)
-	    ? this->end : this->now;
-
-	self->lt_sch_delay = this->now - this->end;
-	self->lt_sleep_duration = this->end - self->lt_sleep_start;
-	self->lt_sleep_start = 0;
-}
-
-/*
- * Filter: drop all "large" latency when it is interruptible, i.e., sleep()
- * etc.
- */
-#if defined(ENABLE_FILTER)
-sched::resume:on-cpu
-/self->lt_sleep_duration > FILTER_THRESHOLD &&
-  self->lt_is_block_wakeable != 0/
-{
-	self->lt_sch_delay = 0;
-	self->lt_sleep_duration = 0;
-	self->lt_is_block_wakeable = 0;
-}
-#endif /* defined(ENABLE_FILTER) */
-
-/*
- * Write sleep time to the aggregation.
- * lt_sleep_duration is the duration between the time when a thread is taken
- * off the CPU and the time when it is enqueued again.
- */
-sched::resume:on-cpu
-/self->lt_sleep_duration != 0/
-{
-	this->cause = self->lt_stackp > 0 ?
-	    self->lt_cause[self->lt_stackp - 1] : "";
-	this->priority = self->lt_stackp > 0 ?
-	    self->lt_prio[self->lt_stackp - 1] : 0;
-
-	@lt_call_count[pid, tid, stack(), this->cause,
-	    this->priority] = count();
-	@lt_call_sum[pid, tid, stack(), this->cause,
-	    this->priority] = sum(self->lt_sleep_duration);
-	@lt_call_max[pid, tid, stack(),  this->cause,
-	    this->priority] = max(self->lt_sleep_duration);
-
-	self->lt_is_block_wakeable = 0;	/* Clear the flag to avoid leak */
-	self->lt_sleep_duration = 0;
-}
-
-/*
- * Write time spent in queue to the aggregation.
- * lt_sch_delay is the interval between the time when a thread becomes
- * runnable and the time when it is actually on the CPU.
- */
-sched::resume:on-cpu
-/self->lt_sch_delay != 0/
-{
-	@lt_named_count[pid, tid, "Wait for available CPU"] = count();
-	@lt_named_sum[pid, tid, "Wait for available CPU"] =
-	    sum(self->lt_sch_delay);
-	@lt_named_max[pid, tid, "Wait for available CPU"] =
-	    max(self->lt_sch_delay);
-
-	self->lt_sch_delay = 0;
-}
-
-/*
- * Probes to track latency caused by spinning on a lock.
- */
-lockstat:::adaptive-spin
-TRACE_FILTER
-{
-	@lt_named_count[pid, tid, "Adapt. lock spin"] = count();
-	@lt_named_sum[pid, tid, "Adapt. lock spin"] = sum(arg1);
-	@lt_named_max[pid, tid, "Adapt. lock spin"] = max(arg1);
-}
-
-lockstat:::spin-spin
-TRACE_FILTER
-{
-	@lt_named_count[pid, tid, "Spinlock spin"] = count();
-	@lt_named_sum[pid, tid, "Spinlock spin"] = sum(arg1);
-	@lt_named_max[pid, tid, "Spinlock spin"] = max(arg1);
-}
-
-/*
- * Probes to track latency caused by blocking on a lock.
- */
-lockstat:::adaptive-block
-TRACE_FILTER
-{
-	@lt_named_count[pid, tid, "#Adapt. lock block"] = count();
-	@lt_named_sum[pid, tid, "#Adapt. lock block"] = sum(arg1);
-	@lt_named_max[pid, tid, "#Adapt. lock block"] = max(arg1);
-}
-
-lockstat:::rw-block
-TRACE_FILTER
-{
-	@lt_named_count[pid, tid, "#RW. lock block"] = count();
-	@lt_named_sum[pid, tid, "#RW. lock block"] = sum(arg1);
-	@lt_named_max[pid, tid, "#RW. lock block"] = max(arg1);
-}
-
-#if defined(ENABLE_SYNCOBJ)
-/*
- * Probes to track latency caused by synchronization objects.
- */
-this int stype;
-this unsigned long long wchan;
-this unsigned long long wtime;
-
-sched:::wakeup
-/*
- * Currently we are unable to track wakeup from sched, because all its LWP IDs
- * are zero when we trace it and that makes lt_timestamps unusable.
- */
-/args[1]->pr_pid != 0 &&
-    lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/
-{
-	this->stype = args[0]->pr_stype;
-	this->wchan = args[0]->pr_wchan;
-	/*
-	 * We can use lt_timestamps[] here, because
-	 * wakeup is always fired before enqueue.
-	 * After enqueue, lt_timestamps[] will be overwritten.
-	 */
-	this->wtime = timestamp - lt_timestamps[args[1]->pr_pid,
-	    args[0]->pr_lwpid];
-
-	@lt_sync_count[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
-	    this->wchan] = count();
-	@lt_sync_sum[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
-	    this->wchan] = sum(this->wtime);
-	@lt_sync_max[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
-	    this->wchan] = max(this->wtime);
-}
-#endif /* defined(ENABLE_SYNCOBJ) */
-
-#else /* !defined(ENABLE_LOW_OVERHEAD) */
-
-/*
- * This is the low overhead mode.
- * In order to reduce the number of instructions executed during each
- * off-cpu and on-cpu event, we do the following:
- *
- *	1. Use sampling and update aggregations only roughly 1/100 times
- *		(SAMPLE_TIMES).
- *	2. Do not track anything other than what is needed for "main" window.
- *	3. Use as few thread local variables as possible.
- */
-
-#define SAMPLE_TIMES		100
-#define SAMPLE_THRESHOLD	50000000
-
-/*
- * Log timestamp when a thread is off CPU.
- */
-sched::resume:off-cpu
-TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP)
-{
-	self->lt_timestamp = timestamp;
-#if defined(ENABLE_FILTER)
-	self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE;
-#endif /* defined(ENABLE_FILTER) */
-}
-
-/*
- * Calculate latency when a thread is actually on the CPU.
- */
-this int need_skip;
-sched::resume:on-cpu
-/self->lt_timestamp != 0/
-{
-	self->lt_timestamp = timestamp - self->lt_timestamp;
-
-#if defined(ENABLE_FILTER)
-	self->lt_timestamp =
-	    (self->lt_timestamp > FILTER_THRESHOLD &&
-	    self->lt_is_block_wakeable != 0) ? 0 : self->lt_timestamp;
-	self->lt_is_block_wakeable = 0;
-#endif /* defined(ENABLE_FILTER) */
-
-	this->need_skip = (self->lt_counter < (SAMPLE_TIMES - 1) &&
-	    self->lt_timestamp <= SAMPLE_THRESHOLD) ? 1 : 0;
-	self->lt_timestamp = this->need_skip ? 0 : self->lt_timestamp;
-	self->lt_counter += this->need_skip;
-}
-
-/*
- * Track large latency first.
- */
-sched::resume:on-cpu
-/self->lt_timestamp > SAMPLE_THRESHOLD/
-{
-	this->cause = self->lt_stackp > 0 ?
-	    self->lt_cause[self->lt_stackp - 1] : "";
-	this->priority = self->lt_stackp > 0 ?
-	    self->lt_prio[self->lt_stackp - 1] : 0;
-
-	@lt_call_count[pid, tid, stack(), this->cause,
-	    this->priority] = sum(1);
-	@lt_call_sum[pid, tid, stack(), this->cause,
-	    this->priority] = sum(self->lt_timestamp);
-	@lt_call_max[pid, tid, stack(), this->cause,
-	    this->priority] = max(self->lt_timestamp);
-
-	self->lt_timestamp = 0;
-}
-
-/*
- * If we fall back to this probe, that means the latency is small and counter
- * has reached SAMPLE_TIMES.
- */
-sched::resume:on-cpu
-/self->lt_timestamp != 0/
-{
-	this->cause = self->lt_stackp > 0 ?
-	    self->lt_cause[self->lt_stackp - 1] : "";
-	this->priority = self->lt_stackp > 0 ?
-	    self->lt_prio[self->lt_stackp - 1] : 0;
-
-	/* Need +1 because lt_counter has not been updated in this cycle. */
-	@lt_call_count[pid, tid, stack(), this->cause,
-	    this->priority] = sum(self->lt_counter + 1);
-	@lt_call_sum[pid, tid, stack(), this->cause,
-	    this->priority] = sum((self->lt_counter + 1) * self->lt_timestamp);
-	@lt_call_max[pid, tid, stack(), this->cause,
-	    this->priority] = max(self->lt_timestamp);
-
-	self->lt_timestamp = 0;
-	self->lt_counter = 0;
-}
-
-#endif /* !defined(ENABLE_LOW_OVERHEAD) */
-
-#define	TRANSLATE(entryprobe, returnprobe, cause, priority)		\
-entryprobe								\
-TRACE_FILTER_COND(self->lt_stackp == 0 ||				\
-    (self->lt_stackp < MAX_TAG &&					\
-    self->lt_prio[self->lt_stackp - 1] <= priority) )			\
-{									\
-	self->lt_prio[self->lt_stackp] = priority;			\
-	self->lt_cause[self->lt_stackp] = cause;			\
-	++self->lt_stackp;						\
-}									\
-returnprobe								\
-TRACE_FILTER_COND(self->lt_stackp > 0 &&				\
-    self->lt_cause[self->lt_stackp - 1] == cause)			\
-{									\
-	--self->lt_stackp;						\
-	self->lt_cause[self->lt_stackp] = NULL;				\
-}
-
-/*
- * Syscalls have a priority of 10. This is to make sure that latency is
- * traced to one of the syscalls only if nothing else matches.
- * We put this special probe here because it uses "probefunc" variable instead
- * of a constant string.
- */
-
-TRANSLATE(syscall:::entry, syscall:::return, probefunc, 10)
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/latencytop.d	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,421 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+#define	MAX_TAG		8
+#define	MAX_STACK	64
+
+#pragma D option aggsize=8m
+#pragma D option bufsize=16m
+#pragma D option dynvarsize=16m
+#pragma D option aggrate=0
+#pragma D option stackframes=MAX_STACK
+/*
+ * Our D script needs to compile even if some of the TRANSLATE probes cannot
+ * be found. Missing probes can be caused by older kernel, different
+ * architecture, unloaded modules etc.
+ */
+#pragma D option zdefs
+
+#if defined(ENABLE_SCHED)
+#if defined(TRACE_PID)
+#define TRACE_FILTER    / pid == 0 || pid == TRACE_PID /
+#define TRACE_FILTER_COND(a)    / (pid == 0 || pid == TRACE_PID) && (a) /
+#elif defined(TRACE_PGID)
+#define TRACE_FILTER    / pid == 0 || curpsinfo->pr_pgid == TRACE_PGID /
+#define TRACE_FILTER_COND(a)
+    / (pid == 0 || curpsinfo->pr_pgid == TRACE_PGID) && (a) /
+#else
+#define TRACE_FILTER
+#define TRACE_FILTER_COND(a)	/ (a) /
+#endif
+#else	/* ENABLE_SCHED */
+#if defined(TRACE_PID)
+#define TRACE_FILTER    / pid == TRACE_PID /
+#define TRACE_FILTER_COND(a)    / (pid == TRACE_PID) && (a) /
+#elif defined(TRACE_PGID)
+#define TRACE_FILTER    / curpsinfo->pr_pgid == TRACE_PGID /
+#define TRACE_FILTER_COND(a)    / (curpsinfo->pr_pgid == TRACE_PGID) && (a) /
+#else
+#define TRACE_FILTER	/ pid != 0 /
+#define TRACE_FILTER_COND(a)    / (pid != 0) && (a) /
+#endif
+#endif /* ENABLE_SCHED */
+
+/* Threshold to filter WAKEABLE latencies. */
+#define FILTER_THRESHOLD	5000000
+/* From thread.h */
+#define T_WAKEABLE		2
+
+/*
+ * This array is used to store timestamp of when threads are enqueued
+ * to dispatch queue.
+ * self-> is not accessible when enqueue happens.
+ */
+unsigned long long lt_timestamps[int, int];
+
+self unsigned int lt_is_block_wakeable;
+self unsigned long long lt_sleep_start;
+self unsigned long long lt_sleep_duration;
+self unsigned long long lt_sch_delay;
+self unsigned int lt_counter;		/* only used in low overhead */
+self unsigned long long lt_timestamp;	/* only used in low overhead */
+self unsigned int lt_stackp;
+self unsigned int lt_prio[int];
+self string lt_cause[int];
+
+this unsigned int priority;
+this string cause;
+
+/*
+ * Clean up everything, otherwise we will run out of memory.
+ */
+proc:::lwp-exit
+{
+	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0;
+
+	self->lt_sleep_start = 0;
+	self->lt_is_block_wakeable = 0;
+	self->lt_counter = 0;
+	self->lt_timestamp = 0;
+
+	/*
+	 * Workaround: no way to clear associative array.
+	 * We have to manually clear 0 ~ (MAX_TAG-1).
+	 */
+
+	self->lt_prio[0] = 0;
+	self->lt_prio[1] = 0;
+	self->lt_prio[2] = 0;
+	self->lt_prio[3] = 0;
+	self->lt_prio[4] = 0;
+	self->lt_prio[5] = 0;
+	self->lt_prio[6] = 0;
+	self->lt_prio[7] = 0;
+
+	self->lt_cause[0] = 0;
+	self->lt_cause[1] = 0;
+	self->lt_cause[2] = 0;
+	self->lt_cause[3] = 0;
+	self->lt_cause[4] = 0;
+	self->lt_cause[5] = 0;
+	self->lt_cause[6] = 0;
+	self->lt_cause[7] = 0;
+}
+
+#if !defined(ENABLE_LOW_OVERHEAD)
+/*
+ * Log timestamp when a thread is taken off the CPU.
+ */
+sched::resume:off-cpu
+TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP)
+{
+	self->lt_sleep_start = timestamp;
+	self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE;
+
+	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] =
+	    self->lt_sleep_start;
+}
+
+/*
+ * Log timestamp when a thread is put on a dispatch queue and becomes runnable.
+ */
+sched:::enqueue
+/lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/
+{
+	lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] = timestamp;
+}
+
+/*
+ * Calculate latency when the thread is actually on the CPU.
+ * This is necessary in order to get the right stack.
+ */
+this unsigned long long end;
+this unsigned long long now;
+sched::resume:on-cpu
+/self->lt_sleep_start != 0/
+{
+	this->end = lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid];
+	this->now = timestamp;
+	lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0;
+	this->end = (this->end != 0 && this->end != self->lt_sleep_start)
+	    ? this->end : this->now;
+
+	self->lt_sch_delay = this->now - this->end;
+	self->lt_sleep_duration = this->end - self->lt_sleep_start;
+	self->lt_sleep_start = 0;
+}
+
+/*
+ * Filter: drop all "large" latency when it is interruptible, i.e., sleep()
+ * etc.
+ */
+#if defined(ENABLE_FILTER)
+sched::resume:on-cpu
+/self->lt_sleep_duration > FILTER_THRESHOLD &&
+  self->lt_is_block_wakeable != 0/
+{
+	self->lt_sch_delay = 0;
+	self->lt_sleep_duration = 0;
+	self->lt_is_block_wakeable = 0;
+}
+#endif /* defined(ENABLE_FILTER) */
+
+/*
+ * Write sleep time to the aggregation.
+ * lt_sleep_duration is the duration between the time when a thread is taken
+ * off the CPU and the time when it is enqueued again.
+ */
+sched::resume:on-cpu
+/self->lt_sleep_duration != 0/
+{
+	this->cause = self->lt_stackp > 0 ?
+	    self->lt_cause[self->lt_stackp - 1] : "";
+	this->priority = self->lt_stackp > 0 ?
+	    self->lt_prio[self->lt_stackp - 1] : 0;
+
+	@lt_call_count[pid, tid, stack(), this->cause,
+	    this->priority] = count();
+	@lt_call_sum[pid, tid, stack(), this->cause,
+	    this->priority] = sum(self->lt_sleep_duration);
+	@lt_call_max[pid, tid, stack(),  this->cause,
+	    this->priority] = max(self->lt_sleep_duration);
+
+	self->lt_is_block_wakeable = 0;	/* Clear the flag to avoid leak */
+	self->lt_sleep_duration = 0;
+}
+
+/*
+ * Write time spent in queue to the aggregation.
+ * lt_sch_delay is the interval between the time when a thread becomes
+ * runnable and the time when it is actually on the CPU.
+ */
+sched::resume:on-cpu
+/self->lt_sch_delay != 0/
+{
+	@lt_named_count[pid, tid, "Wait for available CPU"] = count();
+	@lt_named_sum[pid, tid, "Wait for available CPU"] =
+	    sum(self->lt_sch_delay);
+	@lt_named_max[pid, tid, "Wait for available CPU"] =
+	    max(self->lt_sch_delay);
+
+	self->lt_sch_delay = 0;
+}
+
+/*
+ * Probes to track latency caused by spinning on a lock.
+ */
+lockstat:::adaptive-spin
+TRACE_FILTER
+{
+	@lt_named_count[pid, tid, "Adapt. lock spin"] = count();
+	@lt_named_sum[pid, tid, "Adapt. lock spin"] = sum(arg1);
+	@lt_named_max[pid, tid, "Adapt. lock spin"] = max(arg1);
+}
+
+lockstat:::spin-spin
+TRACE_FILTER
+{
+	@lt_named_count[pid, tid, "Spinlock spin"] = count();
+	@lt_named_sum[pid, tid, "Spinlock spin"] = sum(arg1);
+	@lt_named_max[pid, tid, "Spinlock spin"] = max(arg1);
+}
+
+/*
+ * Probes to track latency caused by blocking on a lock.
+ */
+lockstat:::adaptive-block
+TRACE_FILTER
+{
+	@lt_named_count[pid, tid, "#Adapt. lock block"] = count();
+	@lt_named_sum[pid, tid, "#Adapt. lock block"] = sum(arg1);
+	@lt_named_max[pid, tid, "#Adapt. lock block"] = max(arg1);
+}
+
+lockstat:::rw-block
+TRACE_FILTER
+{
+	@lt_named_count[pid, tid, "#RW. lock block"] = count();
+	@lt_named_sum[pid, tid, "#RW. lock block"] = sum(arg1);
+	@lt_named_max[pid, tid, "#RW. lock block"] = max(arg1);
+}
+
+#if defined(ENABLE_SYNCOBJ)
+/*
+ * Probes to track latency caused by synchronization objects.
+ */
+this int stype;
+this unsigned long long wchan;
+this unsigned long long wtime;
+
+sched:::wakeup
+/*
+ * Currently we are unable to track wakeup from sched, because all its LWP IDs
+ * are zero when we trace it and that makes lt_timestamps unusable.
+ */
+/args[1]->pr_pid != 0 &&
+    lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/
+{
+	this->stype = args[0]->pr_stype;
+	this->wchan = args[0]->pr_wchan;
+	/*
+	 * We can use lt_timestamps[] here, because
+	 * wakeup is always fired before enqueue.
+	 * After enqueue, lt_timestamps[] will be overwritten.
+	 */
+	this->wtime = timestamp - lt_timestamps[args[1]->pr_pid,
+	    args[0]->pr_lwpid];
+
+	@lt_sync_count[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
+	    this->wchan] = count();
+	@lt_sync_sum[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
+	    this->wchan] = sum(this->wtime);
+	@lt_sync_max[args[1]->pr_pid, args[0]->pr_lwpid, this->stype,
+	    this->wchan] = max(this->wtime);
+}
+#endif /* defined(ENABLE_SYNCOBJ) */
+
+#else /* !defined(ENABLE_LOW_OVERHEAD) */
+
+/*
+ * This is the low overhead mode.
+ * In order to reduce the number of instructions executed during each
+ * off-cpu and on-cpu event, we do the following:
+ *
+ *	1. Use sampling and update aggregations only roughly 1/100 times
+ *		(SAMPLE_TIMES).
+ *	2. Do not track anything other than what is needed for "main" window.
+ *	3. Use as few thread local variables as possible.
+ */
+
+#define SAMPLE_TIMES		100
+#define SAMPLE_THRESHOLD	50000000
+
+/*
+ * Log timestamp when a thread is off CPU.
+ */
+sched::resume:off-cpu
+TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP)
+{
+	self->lt_timestamp = timestamp;
+#if defined(ENABLE_FILTER)
+	self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE;
+#endif /* defined(ENABLE_FILTER) */
+}
+
+/*
+ * Calculate latency when a thread is actually on the CPU.
+ */
+this int need_skip;
+sched::resume:on-cpu
+/self->lt_timestamp != 0/
+{
+	self->lt_timestamp = timestamp - self->lt_timestamp;
+
+#if defined(ENABLE_FILTER)
+	self->lt_timestamp =
+	    (self->lt_timestamp > FILTER_THRESHOLD &&
+	    self->lt_is_block_wakeable != 0) ? 0 : self->lt_timestamp;
+	self->lt_is_block_wakeable = 0;
+#endif /* defined(ENABLE_FILTER) */
+
+	this->need_skip = (self->lt_counter < (SAMPLE_TIMES - 1) &&
+	    self->lt_timestamp <= SAMPLE_THRESHOLD) ? 1 : 0;
+	self->lt_timestamp = this->need_skip ? 0 : self->lt_timestamp;
+	self->lt_counter += this->need_skip;
+}
+
+/*
+ * Track large latency first.
+ */
+sched::resume:on-cpu
+/self->lt_timestamp > SAMPLE_THRESHOLD/
+{
+	this->cause = self->lt_stackp > 0 ?
+	    self->lt_cause[self->lt_stackp - 1] : "";
+	this->priority = self->lt_stackp > 0 ?
+	    self->lt_prio[self->lt_stackp - 1] : 0;
+
+	@lt_call_count[pid, tid, stack(), this->cause,
+	    this->priority] = sum(1);
+	@lt_call_sum[pid, tid, stack(), this->cause,
+	    this->priority] = sum(self->lt_timestamp);
+	@lt_call_max[pid, tid, stack(), this->cause,
+	    this->priority] = max(self->lt_timestamp);
+
+	self->lt_timestamp = 0;
+}
+
+/*
+ * If we fall back to this probe, that means the latency is small and counter
+ * has reached SAMPLE_TIMES.
+ */
+sched::resume:on-cpu
+/self->lt_timestamp != 0/
+{
+	this->cause = self->lt_stackp > 0 ?
+	    self->lt_cause[self->lt_stackp - 1] : "";
+	this->priority = self->lt_stackp > 0 ?
+	    self->lt_prio[self->lt_stackp - 1] : 0;
+
+	/* Need +1 because lt_counter has not been updated in this cycle. */
+	@lt_call_count[pid, tid, stack(), this->cause,
+	    this->priority] = sum(self->lt_counter + 1);
+	@lt_call_sum[pid, tid, stack(), this->cause,
+	    this->priority] = sum((self->lt_counter + 1) * self->lt_timestamp);
+	@lt_call_max[pid, tid, stack(), this->cause,
+	    this->priority] = max(self->lt_timestamp);
+
+	self->lt_timestamp = 0;
+	self->lt_counter = 0;
+}
+
+#endif /* !defined(ENABLE_LOW_OVERHEAD) */
+
+#define	TRANSLATE(entryprobe, returnprobe, cause, priority)		\
+entryprobe								\
+TRACE_FILTER_COND(self->lt_stackp == 0 ||				\
+    (self->lt_stackp < MAX_TAG &&					\
+    self->lt_prio[self->lt_stackp - 1] <= priority) )			\
+{									\
+	self->lt_prio[self->lt_stackp] = priority;			\
+	self->lt_cause[self->lt_stackp] = cause;			\
+	++self->lt_stackp;						\
+}									\
+returnprobe								\
+TRACE_FILTER_COND(self->lt_stackp > 0 &&				\
+    self->lt_cause[self->lt_stackp - 1] == cause)			\
+{									\
+	--self->lt_stackp;						\
+	self->lt_cause[self->lt_stackp] = NULL;				\
+}
+
+/*
+ * Syscalls have a priority of 10. This is to make sure that latency is
+ * traced to one of the syscalls only if nothing else matches.
+ * We put this special probe here because it uses "probefunc" variable instead
+ * of a constant string.
+ */
+
+TRANSLATE(syscall:::entry, syscall:::return, probefunc, 10)
--- old/usr/src/cmd/latencytop/common/latencytop.h	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,273 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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.
- */
-
-#ifndef _LATENCYTOP_H
-#define	_LATENCYTOP_H
-
-#include <sys/types.h>
-
-#include <glib.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * Without this lint seems to be confused by glib header file.
- */
-#ifdef __lint
-#undef g_assert
-#define	g_assert(x)	((void)(x))
-#undef TRUE
-#define	TRUE		1
-#endif
-
-/*
- * We define our own conversions in order to avoid compiler warnings.
- */
-#define	LT_INT_TO_POINTER(a)	((void *)(unsigned long)(a))
-
-#define	TITLE			"LatencyTOP for OpenSolaris, version 1.0"
-#define	COPYRIGHT		"Copyright (c) 2008-2009, Intel Corporation."
-#define	DEFAULT_KLOG_FILE	"/var/log/latencytop.log"
-
-#define	INVALID_PID		(~0)
-#define	INVALID_TID		(~0)
-#define	PID_SYS_GLOBAL		INVALID_PID
-#define	INVALID_CAUSE		0
-#define	HIGHER_PRIORITY(a, b)	((a) > (b))
-
-#ifdef EMBED_CONFIGS
-/*
- * LatencyTOP configuration is embedded in the binary.
- * Array will be generated by elfwrap.
- */
-extern char latencytop_d_start;
-extern char latencytop_d_end;
-extern char latencytop_trans_start;
-extern char latencytop_trans_end;
-#else
-/*
- * LatencyTOP configuration is provided externally by user.
- */
-#define	DEFAULT_CONFIG_NAME	"./latencytop.trans"
-#define	DEFAULT_D_SCRIPT_NAME   "./latencytop.d"
-#endif
-
-typedef enum {
-	LT_STAT_COUNT,
-	LT_STAT_MAX,
-	LT_STAT_SUM,
-} lt_stat_type_t;
-
-#define	LT_KLOG_LEVEL_NONE	0	/* Log nothing */
-#define	LT_KLOG_LEVEL_UNMAPPED	1	/* Log only stacks not mapped */
-#define	LT_KLOG_LEVEL_MAPPED	2	/* Log only stacks mapped */
-#define	LT_KLOG_LEVEL_ALL	3	/* Log all stacks, mapped or not */
-
-typedef enum {
-	LT_LEVEL_GLOBAL,	/* System wide statistics */
-	LT_LEVEL_PROCESS,	/* Per-process statistics */
-	LT_LEVEL_THREAD,	/* Per-thread statistics */
-} lt_stat_level_t;
-
-typedef enum {
-	LT_SORT_TOTAL,
-	LT_SORT_MAX,
-	LT_SORT_AVG,
-	LT_SORT_COUNT,
-} lt_sort_t;
-
-typedef enum {
-	LT_FIELD_FNAME,
-	LT_FIELD_PSARGS,
-} lt_field_t;
-
-typedef enum {
-	LT_LIST_CAUSE,		/* List latency by causes (default) */
-	LT_LIST_SPECIALS,	/* List only "special" causes */
-	LT_LIST_SOBJ		/* List synchronization objects */
-} lt_list_type_t;
-
-/*
- * Data structure which contains statistics.
- */
-typedef struct {
-	uint64_t lt_s_count;
-	uint64_t lt_s_total;
-	uint64_t lt_s_max;
-} lt_stat_data_t;
-
-/*
- * Data structure that stores statistics along with the name.
- */
-typedef struct {
-	enum {
-		STAT_CAUSE,
-		STAT_SOBJ
-	} lt_se_type;
-	const char *lt_se_string;
-	lt_stat_data_t lt_se_data;
-	union {
-		struct {
-			int lt_se_c_id;
-			int lt_se_c_flags;
-		} lt_se_t_cause;
-		struct {
-			int lt_se_s_id;
-		} lt_se_t_sobj;
-	} lt_se_tsdata;	/* type specific data */
-} lt_stat_entry_t;
-
-typedef struct {
-	int lt_cfg_enable_filter;
-	int lt_cfg_trace_sched;
-	int lt_cfg_trace_syncobj;
-	int lt_cfg_low_overhead_mode;
-	int lt_cfg_snap_interval;
-	char *lt_cfg_config_name;
-	unsigned int lt_cfg_trace_pid;
-	unsigned int lt_cfg_trace_pgid;
-} lt_config_t;
-
-extern lt_config_t g_config;	/* The global settings */
-
-/*
- * Causes can be disabled through the configuration file.
- * When disabled, though D script will continue to capture causes, they will
- * not be counted by LatencyTOP.
- */
-#define	CAUSE_FLAG_DISABLED		1
-/*
- * This flag will not show and count causes as part of summary in
- * "kstack window".
- */
-#define	CAUSE_FLAG_HIDE_IN_SUMMARY	2
-/*
- * This is generated from D script (named cause), and is "special".
- */
-#define	CAUSE_FLAG_SPECIAL		4
-#define	CAUSE_ALL_FLAGS			0xffffffff
-
-extern boolean_t lt_drop_detected;
-
-/*
- * These functions collect statistics using DTrace.
- */
-extern int lt_dtrace_init(void);
-extern int lt_dtrace_work(int);
-extern int lt_dtrace_collect(void);
-extern int lt_dtrace_deinit(void);
-
-/*
- * These functions maintain configuration, e.g. symbol to cause mapping.
- */
-extern int lt_table_init(void);
-extern int lt_table_cause_from_stack(const char *, int *, int *);
-extern const char *lt_table_get_cause_name(int);
-extern int lt_table_get_cause_flag(int, int);
-extern int lt_table_cause_from_name(char *, int, int);
-extern int lt_table_append_trans(FILE *fp);
-extern void lt_table_deinit(void);
-
-/*
- * These functions update statistic of all causes of latency, collected
- * from DTrace.
- */
-extern void lt_stat_update(pid_t, id_t, char *, char *, unsigned int,
-    lt_stat_type_t, uint64_t);
-extern void lt_stat_update_cause(pid_t, id_t, int, lt_stat_type_t, uint64_t);
-extern void lt_stat_update_sobj(pid_t, id_t, int, unsigned long long,
-    lt_stat_type_t, uint64_t);
-extern void lt_stat_clear_all(void);
-extern void lt_stat_free_all(void);
-
-/*
- * These functions produce lists for display panes.
- * Note: after a call to lt_stat_update_*, the old lists will become invalid.
- */
-extern void *lt_stat_list_create(lt_list_type_t, lt_stat_level_t,
-    pid_t, id_t, int, lt_sort_t);
-extern int lt_stat_list_has_item(void *, int);
-extern const char *lt_stat_list_get_reason(void *, int);
-extern uint64_t lt_stat_list_get_max(void *, int);
-extern uint64_t lt_stat_list_get_sum(void *, int);
-extern uint64_t lt_stat_list_get_count(void *, int);
-extern uint64_t lt_stat_list_get_gtotal(void *);
-extern void lt_stat_list_free(void *);
-
-/*
- * These functions produce the process list and the thread list.
- */
-extern int lt_stat_proc_list_create(pid_t **, id_t **);
-extern void lt_stat_proc_list_free(pid_t *, id_t *);
-extern const char *lt_stat_proc_get_name(pid_t);
-extern int lt_stat_proc_get_nthreads(pid_t);
-
-/*
- * These functions use ncurses to create console-based display.
- */
-extern void lt_display_init(void);
-extern int lt_display_loop(int);
-extern void lt_display_error(const char *, ...);
-extern void lt_display_deinit(void);
-
-/*
- * Write statistics to log file - useful for debugging and offline analysis.
- */
-extern void lt_klog_init(void);
-extern void lt_klog_deinit(void);
-extern int lt_klog_set_log_file(const char *);
-extern int lt_klog_set_log_level(int);
-extern void lt_klog_write(void);
-extern void lt_klog_log(int, pid_t, char *, lt_stat_type_t,
-    uint64_t);
-
-/*
- * Utility functions.
- */
-extern uint64_t lt_millisecond(void);
-extern void *lt_malloc(size_t);
-extern void *lt_zalloc(size_t);
-extern char *lt_strdup(const char *);
-extern void lt_check_null(void *);
-extern void lt_time_str(char *, int);
-extern char *lt_get_proc_field(pid_t, lt_field_t);
-extern void lt_update_stat_value(lt_stat_data_t *, lt_stat_type_t, uint64_t);
-extern int lt_sort_by_total_desc(lt_stat_entry_t *, lt_stat_entry_t *);
-extern int lt_sort_by_max_desc(lt_stat_entry_t *, lt_stat_entry_t *);
-extern int lt_sort_by_count_desc(lt_stat_entry_t *, lt_stat_entry_t *);
-extern int lt_sort_by_avg_desc(lt_stat_entry_t *, lt_stat_entry_t *);
-extern void lt_gpipe_init(void);
-extern void lt_gpipe_deinit(void);
-extern void lt_gpipe_break(const char *);
-extern int lt_gpipe_readfd(void);
-extern int lt_file_exist(const char *);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _LATENCYTOP_H */
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/latencytop.h	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,273 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+#ifndef _LATENCYTOP_H
+#define	_LATENCYTOP_H
+
+#include <sys/types.h>
+
+#include <glib.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Without this lint seems to be confused by glib header file.
+ */
+#ifdef __lint
+#undef g_assert
+#define	g_assert(x)	((void)(x))
+#undef TRUE
+#define	TRUE		1
+#endif
+
+/*
+ * We define our own conversions in order to avoid compiler warnings.
+ */
+#define	LT_INT_TO_POINTER(a)	((void *)(unsigned long)(a))
+
+#define	TITLE			"LatencyTOP for OpenSolaris, version 1.0"
+#define	COPYRIGHT		"Copyright (c) 2008-2009, Intel Corporation."
+#define	DEFAULT_KLOG_FILE	"/var/log/latencytop.log"
+
+#define	INVALID_PID		(~0)
+#define	INVALID_TID		(~0)
+#define	PID_SYS_GLOBAL		INVALID_PID
+#define	INVALID_CAUSE		0
+#define	HIGHER_PRIORITY(a, b)	((a) > (b))
+
+#ifdef EMBED_CONFIGS
+/*
+ * LatencyTOP configuration is embedded in the binary.
+ * Array will be generated by elfwrap.
+ */
+extern char latencytop_d_start;
+extern char latencytop_d_end;
+extern char latencytop_trans_start;
+extern char latencytop_trans_end;
+#else
+/*
+ * LatencyTOP configuration is provided externally by user.
+ */
+#define	DEFAULT_CONFIG_NAME	"./latencytop.trans"
+#define	DEFAULT_D_SCRIPT_NAME   "./latencytop.d"
+#endif
+
+typedef enum {
+	LT_STAT_COUNT,
+	LT_STAT_MAX,
+	LT_STAT_SUM,
+} lt_stat_type_t;
+
+#define	LT_KLOG_LEVEL_NONE	0	/* Log nothing */
+#define	LT_KLOG_LEVEL_UNMAPPED	1	/* Log only stacks not mapped */
+#define	LT_KLOG_LEVEL_MAPPED	2	/* Log only stacks mapped */
+#define	LT_KLOG_LEVEL_ALL	3	/* Log all stacks, mapped or not */
+
+typedef enum {
+	LT_LEVEL_GLOBAL,	/* System wide statistics */
+	LT_LEVEL_PROCESS,	/* Per-process statistics */
+	LT_LEVEL_THREAD,	/* Per-thread statistics */
+} lt_stat_level_t;
+
+typedef enum {
+	LT_SORT_TOTAL,
+	LT_SORT_MAX,
+	LT_SORT_AVG,
+	LT_SORT_COUNT,
+} lt_sort_t;
+
+typedef enum {
+	LT_FIELD_FNAME,
+	LT_FIELD_PSARGS,
+} lt_field_t;
+
+typedef enum {
+	LT_LIST_CAUSE,		/* List latency by causes (default) */
+	LT_LIST_SPECIALS,	/* List only "special" causes */
+	LT_LIST_SOBJ		/* List synchronization objects */
+} lt_list_type_t;
+
+/*
+ * Data structure which contains statistics.
+ */
+typedef struct {
+	uint64_t lt_s_count;
+	uint64_t lt_s_total;
+	uint64_t lt_s_max;
+} lt_stat_data_t;
+
+/*
+ * Data structure that stores statistics along with the name.
+ */
+typedef struct {
+	enum {
+		STAT_CAUSE,
+		STAT_SOBJ
+	} lt_se_type;
+	const char *lt_se_string;
+	lt_stat_data_t lt_se_data;
+	union {
+		struct {
+			int lt_se_c_id;
+			int lt_se_c_flags;
+		} lt_se_t_cause;
+		struct {
+			int lt_se_s_id;
+		} lt_se_t_sobj;
+	} lt_se_tsdata;	/* type specific data */
+} lt_stat_entry_t;
+
+typedef struct {
+	int lt_cfg_enable_filter;
+	int lt_cfg_trace_sched;
+	int lt_cfg_trace_syncobj;
+	int lt_cfg_low_overhead_mode;
+	int lt_cfg_snap_interval;
+	char *lt_cfg_config_name;
+	unsigned int lt_cfg_trace_pid;
+	unsigned int lt_cfg_trace_pgid;
+} lt_config_t;
+
+extern lt_config_t g_config;	/* The global settings */
+
+/*
+ * Causes can be disabled through the configuration file.
+ * When disabled, though D script will continue to capture causes, they will
+ * not be counted by LatencyTOP.
+ */
+#define	CAUSE_FLAG_DISABLED		1
+/*
+ * This flag will not show and count causes as part of summary in
+ * "kstack window".
+ */
+#define	CAUSE_FLAG_HIDE_IN_SUMMARY	2
+/*
+ * This is generated from D script (named cause), and is "special".
+ */
+#define	CAUSE_FLAG_SPECIAL		4
+#define	CAUSE_ALL_FLAGS			0xffffffff
+
+extern boolean_t lt_drop_detected;
+
+/*
+ * These functions collect statistics using DTrace.
+ */
+extern int lt_dtrace_init(void);
+extern int lt_dtrace_work(int);
+extern int lt_dtrace_collect(void);
+extern int lt_dtrace_deinit(void);
+
+/*
+ * These functions maintain configuration, e.g. symbol to cause mapping.
+ */
+extern int lt_table_init(void);
+extern int lt_table_cause_from_stack(const char *, int *, int *);
+extern const char *lt_table_get_cause_name(int);
+extern int lt_table_get_cause_flag(int, int);
+extern int lt_table_cause_from_name(char *, int, int);
+extern int lt_table_append_trans(FILE *fp);
+extern void lt_table_deinit(void);
+
+/*
+ * These functions update statistic of all causes of latency, collected
+ * from DTrace.
+ */
+extern void lt_stat_update(pid_t, id_t, char *, char *, unsigned int,
+    lt_stat_type_t, uint64_t);
+extern void lt_stat_update_cause(pid_t, id_t, int, lt_stat_type_t, uint64_t);
+extern void lt_stat_update_sobj(pid_t, id_t, int, unsigned long long,
+    lt_stat_type_t, uint64_t);
+extern void lt_stat_clear_all(void);
+extern void lt_stat_free_all(void);
+
+/*
+ * These functions produce lists for display panes.
+ * Note: after a call to lt_stat_update_*, the old lists will become invalid.
+ */
+extern void *lt_stat_list_create(lt_list_type_t, lt_stat_level_t,
+    pid_t, id_t, int, lt_sort_t);
+extern int lt_stat_list_has_item(void *, int);
+extern const char *lt_stat_list_get_reason(void *, int);
+extern uint64_t lt_stat_list_get_max(void *, int);
+extern uint64_t lt_stat_list_get_sum(void *, int);
+extern uint64_t lt_stat_list_get_count(void *, int);
+extern uint64_t lt_stat_list_get_gtotal(void *);
+extern void lt_stat_list_free(void *);
+
+/*
+ * These functions produce the process list and the thread list.
+ */
+extern int lt_stat_proc_list_create(pid_t **, id_t **);
+extern void lt_stat_proc_list_free(pid_t *, id_t *);
+extern const char *lt_stat_proc_get_name(pid_t);
+extern int lt_stat_proc_get_nthreads(pid_t);
+
+/*
+ * These functions use ncurses to create console-based display.
+ */
+extern void lt_display_init(void);
+extern int lt_display_loop(int);
+extern void lt_display_error(const char *, ...);
+extern void lt_display_deinit(void);
+
+/*
+ * Write statistics to log file - useful for debugging and offline analysis.
+ */
+extern void lt_klog_init(void);
+extern void lt_klog_deinit(void);
+extern int lt_klog_set_log_file(const char *);
+extern int lt_klog_set_log_level(int);
+extern void lt_klog_write(void);
+extern void lt_klog_log(int, pid_t, char *, lt_stat_type_t,
+    uint64_t);
+
+/*
+ * Utility functions.
+ */
+extern uint64_t lt_millisecond(void);
+extern void *lt_malloc(size_t);
+extern void *lt_zalloc(size_t);
+extern char *lt_strdup(const char *);
+extern void lt_check_null(void *);
+extern void lt_time_str(char *, int);
+extern char *lt_get_proc_field(pid_t, lt_field_t);
+extern void lt_update_stat_value(lt_stat_data_t *, lt_stat_type_t, uint64_t);
+extern int lt_sort_by_total_desc(lt_stat_entry_t *, lt_stat_entry_t *);
+extern int lt_sort_by_max_desc(lt_stat_entry_t *, lt_stat_entry_t *);
+extern int lt_sort_by_count_desc(lt_stat_entry_t *, lt_stat_entry_t *);
+extern int lt_sort_by_avg_desc(lt_stat_entry_t *, lt_stat_entry_t *);
+extern void lt_gpipe_init(void);
+extern void lt_gpipe_deinit(void);
+extern void lt_gpipe_break(const char *);
+extern int lt_gpipe_readfd(void);
+extern int lt_file_exist(const char *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LATENCYTOP_H */
--- old/usr/src/cmd/latencytop/common/latencytop.trans	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,44 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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.
-#
-# LatencyTOP 1.0 configuration
-#
-
-#
-# Format:
-# D <priority>    <probe 1>     <probe 2>  ...   <probe n>     <Cause>
-# ; <special_command>  <option value>
-# # comments
-#
-# D: We use dtrace probes to tag latency to different causes. The entry probe
-# pushes the cause and the priority to a thread local stack, and the return
-# probe pops them. These probes are transformed into:
-#     TRANSLATE(entryprobe, returnprobe, cause, priority)
-# and are append to the embedded D script.
-#
-# <special_command>:
-# disable_category <category name> : do not count and display <category name>
-#
-
-# ZFS
-D 60    sdt:zfs:zil_commit_writer:zil-cw1  sdt:zfs:zil_commit_writer:zil-cw4  ZFS ZIL writer I/O
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/latencytop.trans	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,44 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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.
+#
+# LatencyTOP 1.0 configuration
+#
+
+#
+# Format:
+# D <priority>    <probe 1>     <probe 2>  ...   <probe n>     <Cause>
+# ; <special_command>  <option value>
+# # comments
+#
+# D: We use dtrace probes to tag latency to different causes. The entry probe
+# pushes the cause and the priority to a thread local stack, and the return
+# probe pops them. These probes are transformed into:
+#     TRANSLATE(entryprobe, returnprobe, cause, priority)
+# and are append to the embedded D script.
+#
+# <special_command>:
+# disable_category <category name> : do not count and display <category name>
+#
+
+# ZFS
+D 60    sdt:zfs:zil_commit_writer:zil-cw1  sdt:zfs:zil_commit_writer:zil-cw4  ZFS ZIL writer I/O
--- old/usr/src/cmd/latencytop/sparcv9/Makefile	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 ../Makefile.com
-include ../../Makefile.cmd.64
-
-WRAPOPT = -64
-
-install: all $(ROOTPROG64)
--- old/usr/src/cmd/latencytop/common/stat.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,1050 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <sys/stat.h>
-
-#include "latencytop.h"
-
-/* Statistics for each process/thread. */
-typedef struct _lt_stat_collection lt_stat_collection_t;
-typedef gboolean (*check_child_func_t) (gpointer key,
-    lt_stat_collection_t *stat, void *user);
-
-typedef struct {
-	lt_stat_entry_t lt_grp_summary;
-	/* cause_id -> stat entry */
-	GHashTable *lt_grp_cidlist;
-} lt_datagroup_t;
-
-#define	NGROUPS			2
-#define	GROUP_CAUSE		0
-#define	GROUP_SOBJ		1
-
-/*
- * 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 {
-	lt_stat_level_t lt_sc_level;
-	unsigned int lt_sc_id;
-	char *lt_sc_name;
-	lt_datagroup_t lt_sc_groups[NGROUPS];
-	/*
-	 * The following fields: lt_sc_parent, lt_sc_children and
-	 * lt_sc_check_child_func maintain the tree structure.
-	 */
-	lt_stat_collection_t *lt_sc_parent;		/* Parent node */
-	GHashTable *lt_sc_children;	/* pid/tid -> lt_stat_collection_t */
-	check_child_func_t lt_sc_check_child_func; /* Release dead children */
-};
-
-/* Internal data structure to back 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 lt_sl_entry_count;
-	lt_stat_entry_t **lt_sl_entries;
-	uint64_t lt_sl_gtotal;
-	free_list_func_t lt_sl_free_func;
-};
-
-/* Root of the collection hierarchy: system level statistics */
-static lt_stat_collection_t *stat_system = NULL;
-
-/*
- * 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 {
-	lt_sobj_id_t lt_so_oid;
-	int lt_so_cause_id;
-	char lt_so_string[32];	/* Enough to hold "%s: 0x%llX" */
-} lt_sobj_t;
-
-static GHashTable *sobj_table = NULL;
-static int sobj_table_len = 0;
-
-/*
- * Lower 32-bit of the address of synchronization objects is used to hash
- * them.
- */
-static guint
-sobj_id_hash(lt_sobj_id_t *id)
-{
-	g_assert(id != NULL);
-	return (id->lt_soi_addr & 0xFFFFFFFF);
-}
-
-/*
- * Test if two synchronization objects are the same.
- */
-static gboolean
-sobj_id_equal(lt_sobj_id_t *a, lt_sobj_id_t *b)
-{
-	g_assert(a != NULL && b != NULL);
-	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 *
-lookup_sobj(lt_sobj_id_t *id)
-{
-	const char *stype_str[] = {
-		"None",
-		"Mutex",
-		"RWLock",
-		"CV",
-		"Sema",
-		"User",
-		"User_PI",
-		"Shuttle"
-	};
-	const int stype_str_len =
-	    sizeof (stype_str) / sizeof (stype_str[0]);
-	lt_sobj_t *ret = NULL;
-	g_assert(id != NULL);
-
-	if (id->lt_soi_type < 0 || id->lt_soi_type >= stype_str_len) {
-		return (NULL);
-	}
-
-	if (sobj_table != NULL) {
-		ret = (lt_sobj_t *)g_hash_table_lookup(sobj_table, id);
-	} else {
-		sobj_table = g_hash_table_new_full(
-		    (GHashFunc)sobj_id_hash, (GEqualFunc)sobj_id_equal,
-		    NULL, (GDestroyNotify)free);
-		lt_check_null(sobj_table);
-	}
-
-	if (ret == NULL) {
-		ret = (lt_sobj_t *)lt_zalloc(sizeof (lt_sobj_t));
-		ret->lt_so_cause_id = ++sobj_table_len;
-		(void) snprintf(ret->lt_so_string, sizeof (ret->lt_so_string),
-		    "%s: 0x%llX", stype_str[id->lt_soi_type], id->lt_soi_addr);
-		ret->lt_so_oid.lt_soi_type = id->lt_soi_type;
-		ret->lt_so_oid.lt_soi_addr = id->lt_soi_addr;
-
-		g_hash_table_insert(sobj_table, &ret->lt_so_oid, ret);
-	}
-
-	return (ret);
-}
-
-/*
- * Check if a process exists by using /proc/pid
- */
-/* ARGSUSED */
-static gboolean
-check_process(gpointer key, lt_stat_collection_t *stat, void *user)
-{
-	char name[PATH_MAX];
-
-	(void) snprintf(name, PATH_MAX, "/proc/%u", stat->lt_sc_id);
-	return (lt_file_exist(name) ? FALSE : TRUE);
-}
-
-/*
- * Check if a thread exists by using /proc/pid/lwp/tid
- */
-/* ARGSUSED */
-static gboolean
-check_thread(gpointer key, lt_stat_collection_t *stat, void *user)
-{
-	char name[PATH_MAX];
-
-	g_assert(stat->lt_sc_parent != NULL);
-	g_assert(stat->lt_sc_parent->lt_sc_level == LT_LEVEL_PROCESS);
-
-	(void) snprintf(name, PATH_MAX, "/proc/%u/lwp/%u",
-	    stat->lt_sc_parent->lt_sc_id, stat->lt_sc_id);
-	return (lt_file_exist(name) ? FALSE : TRUE);
-}
-
-/*
- * Helper function to free a stat node.
- */
-static void
-free_stat(lt_stat_collection_t *stat)
-{
-	int i;
-
-	if (stat == NULL) {
-		return;
-	}
-
-	for (i = 0; i < NGROUPS; ++i) {
-		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
-			g_hash_table_destroy(stat->lt_sc_groups[i].
-			    lt_grp_cidlist);
-		}
-	}
-
-	if (stat->lt_sc_children != NULL) {
-		g_hash_table_destroy(stat->lt_sc_children);
-	}
-
-	if (stat->lt_sc_name != NULL) {
-		free(stat->lt_sc_name);
-	}
-
-	free(stat);
-}
-
-/*
- * Helper function to initialize a stat node.
- */
-/* ARGSUSED */
-static void
-clear_stat(gpointer key, lt_stat_collection_t *stat, void *user)
-{
-	int i;
-
-	g_assert(stat != NULL);
-
-	for (i = 0; i < NGROUPS; ++i) {
-		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
-			g_hash_table_destroy(stat->lt_sc_groups[i].
-			    lt_grp_cidlist);
-			stat->lt_sc_groups[i].lt_grp_cidlist = NULL;
-		}
-
-		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_count = 0;
-		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_total = 0;
-		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_max = 0;
-	}
-
-	if (stat->lt_sc_children != NULL) {
-		g_hash_table_foreach_remove(stat->lt_sc_children,
-		    (GHRFunc)stat->lt_sc_check_child_func, NULL);
-		g_hash_table_foreach(stat->lt_sc_children,
-		    (GHFunc)clear_stat, NULL);
-	}
-}
-
-/*
- * Update a collection with the given value.
- * Recursively update parents in the hierarchy  until the root is reached.
- */
-static void
-update_stat_entry(lt_stat_collection_t *stat, int cause_id,
-		lt_stat_type_t type, uint64_t value,
-		const char *string, int group_to_use)
-{
-	lt_stat_entry_t *entry = NULL;
-	lt_datagroup_t *group;
-
-	if (group_to_use < 0 || group_to_use >= NGROUPS) {
-		return;
-	}
-
-	group = &(stat->lt_sc_groups[group_to_use]);
-
-	if (group->lt_grp_cidlist != NULL) {
-		entry = (lt_stat_entry_t *)g_hash_table_lookup(
-		    group->lt_grp_cidlist, LT_INT_TO_POINTER(cause_id));
-	} else   {
-		group->lt_grp_cidlist = g_hash_table_new_full(
-		    g_direct_hash, g_direct_equal,
-		    NULL, (GDestroyNotify)free);
-		lt_check_null(group->lt_grp_cidlist);
-	}
-
-	if (entry == NULL) {
-		entry = (lt_stat_entry_t *)lt_zalloc(sizeof (lt_stat_entry_t));
-		entry->lt_se_string = string;
-
-		switch (group_to_use) {
-		case GROUP_CAUSE:
-			entry->lt_se_type = STAT_CAUSE;
-			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_id = cause_id;
-			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags =
-			    lt_table_get_cause_flag(cause_id, CAUSE_ALL_FLAGS);
-
-			/* hide the first '#' */
-			if ((entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags
-			    & CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
-				++entry->lt_se_string;
-			}
-
-			break;
-		case GROUP_SOBJ:
-			entry->lt_se_type = STAT_SOBJ;
-			entry->lt_se_tsdata.lt_se_t_sobj.lt_se_s_id = cause_id;
-			break;
-		}
-
-		g_hash_table_insert(group->lt_grp_cidlist,
-		    LT_INT_TO_POINTER(cause_id), entry);
-	}
-
-	lt_update_stat_value(&entry->lt_se_data, type, value);
-
-	if (group_to_use == GROUP_SOBJ ||
-	    (entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
-	    CAUSE_FLAG_HIDE_IN_SUMMARY) == 0) {
-		lt_update_stat_value(&group->lt_grp_summary.lt_se_data, type,
-		    value);
-	}
-
-	if (stat->lt_sc_parent != NULL) {
-		update_stat_entry(stat->lt_sc_parent, cause_id, type, value,
-		    string, group_to_use);
-	}
-}
-
-/*
- * Identify the cause of latency from the given stack trace.
- * Return cause_id.
- */
-static void
-find_cause(char *stack, int *cause_id, int *cause_priority)
-{
-	int cause_temp;
-	int prio_temp;
-	int cause = INVALID_CAUSE;
-	int priority = 0;
-	int found = 0;
-
-	g_assert(cause_id != NULL);
-	g_assert(cause_priority != NULL);
-
-	while (stack != NULL) {
-		char *sep;
-		sep = strchr(stack, ' ');
-
-		if (sep != NULL) {
-			*sep = '\0';
-		}
-
-		found = lt_table_cause_from_stack(stack, &cause_temp,
-		    &prio_temp);
-
-		if (found && (cause == INVALID_CAUSE ||
-		    HIGHER_PRIORITY(prio_temp, priority))) {
-			cause = cause_temp;
-			priority = prio_temp;
-		}
-
-		if (sep != NULL) {
-			*sep = ' ';
-			stack = sep + 1;
-		} else   {
-			stack = NULL;
-		}
-	}
-
-	*cause_id = cause;
-	*cause_priority = priority;
-}
-
-/*
- * Create a new collection and hook it to the parent.
- */
-static lt_stat_collection_t *
-new_collection(lt_stat_level_t level, unsigned int id, char *name,
-    lt_stat_collection_t *parent, check_child_func_t check_child_func)
-{
-	int i;
-	lt_stat_collection_t *ret;
-
-	ret = (lt_stat_collection_t *)
-	    lt_zalloc(sizeof (lt_stat_collection_t));
-
-	ret->lt_sc_level = level;
-	ret->lt_sc_check_child_func = check_child_func;
-	ret->lt_sc_id = id;
-	ret->lt_sc_name = name;
-
-	for (i = 0; i < NGROUPS; ++i) {
-		ret->lt_sc_groups[i].lt_grp_summary.lt_se_string =
-		    (const char *)name;
-	}
-
-	if (parent != NULL) {
-		ret->lt_sc_parent = parent;
-
-		if (parent->lt_sc_children == NULL) {
-			parent->lt_sc_children = g_hash_table_new_full(
-			    g_direct_hash, g_direct_equal,
-			    NULL, (GDestroyNotify)free_stat);
-			lt_check_null(parent->lt_sc_children);
-		}
-
-		g_hash_table_insert(parent->lt_sc_children,
-		    LT_INT_TO_POINTER((int)id), ret);
-	}
-
-	return (ret);
-}
-
-/*
- * Find the "leaf" in the collection hierarchy, using the given pid and tid.
- */
-static lt_stat_collection_t *
-get_stat_c(pid_t pid, id_t tid)
-{
-	lt_stat_collection_t *stat_p = NULL;
-	lt_stat_collection_t *stat_t = NULL;
-
-	if (stat_system == NULL) {
-		stat_system = new_collection(LT_LEVEL_GLOBAL,
-		    PID_SYS_GLOBAL, lt_strdup("SYSTEM"), NULL, check_process);
-	} else if (stat_system->lt_sc_children != NULL) {
-		stat_p = (lt_stat_collection_t *)
-		    g_hash_table_lookup(stat_system->lt_sc_children,
-		    LT_INT_TO_POINTER(pid));
-	}
-
-	if (stat_p == NULL) {
-		char *fname;
-		fname = lt_get_proc_field(pid, LT_FIELD_FNAME);
-
-		if (fname == NULL) {
-			/*
-			 * we could not get the executable name of the
-			 * process; the process is probably already dead.
-			 */
-			return (NULL);
-		}
-
-		stat_p = new_collection(LT_LEVEL_PROCESS,
-		    (unsigned int)pid, fname, stat_system, check_thread);
-	} else if (stat_p->lt_sc_children != NULL) {
-		stat_t = (lt_stat_collection_t *)
-		    g_hash_table_lookup(stat_p->lt_sc_children,
-		    LT_INT_TO_POINTER(tid));
-	}
-
-	if (stat_t == NULL) {
-		const int tname_size = 16; /* Enough for "Thread %d" */
-		char *tname;
-
-		tname = (char *)lt_zalloc(tname_size);
-		(void) snprintf(tname, tname_size, "Thread %d", tid);
-
-		stat_t = new_collection(LT_LEVEL_THREAD,
-		    (unsigned int)tid, tname, stat_p, NULL);
-	}
-
-	return (stat_t);
-}
-
-/*
- * Update statistics with the given cause_id. Values will be added to
- * internal statistics.
- */
-void
-lt_stat_update_cause(pid_t pid, id_t tid, int cause_id, lt_stat_type_t type,
-    uint64_t value)
-{
-	const char *string;
-	lt_stat_collection_t *stat_t = NULL;
-
-	if (cause_id < 0 || value == 0) {
-		return;
-	}
-
-	if (lt_table_get_cause_flag(cause_id, CAUSE_FLAG_DISABLED)) {
-		/* Ignore this cause */
-		return;
-	}
-
-	stat_t = get_stat_c(pid, tid);
-
-	if (stat_t == NULL) {
-		/* Process must be dead. */
-		return;
-	}
-
-	string = lt_table_get_cause_name(cause_id);
-
-	update_stat_entry(stat_t, cause_id, type, value, string, GROUP_CAUSE);
-}
-
-/*
- * 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
-lt_stat_update(pid_t pid, id_t tid, char *stack, char *tag,
-    unsigned int tag_priority, lt_stat_type_t type, uint64_t value)
-{
-	int tag_cause_id = INVALID_CAUSE;
-	int stack_cause_id = INVALID_CAUSE;
-	int cause_id = INVALID_CAUSE;
-	int stack_priority = 0;
-
-	if (value == 0) {
-		return;
-	}
-
-	find_cause(stack, &stack_cause_id, &stack_priority);
-
-	if (tag_priority != 0) {
-		tag_cause_id = lt_table_cause_from_name(tag, 0, 0);
-
-		if (tag_cause_id == INVALID_CAUSE) {
-			/* This must be a syscall tag */
-			char tmp[64];
-			(void) snprintf(tmp, sizeof (tmp), "Syscall: %s", tag);
-			tag_cause_id = lt_table_cause_from_name(tmp, 1, 0);
-		}
-	}
-
-	cause_id = (tag_priority > stack_priority) ? tag_cause_id :
-	    stack_cause_id;
-
-	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.
-		 */
-		cause_id = lt_table_cause_from_name(stack, 1,
-		    CAUSE_FLAG_SPECIAL);
-		lt_klog_log(LT_KLOG_LEVEL_UNMAPPED, pid, stack, type, value);
-	} else   {
-		lt_klog_log(LT_KLOG_LEVEL_MAPPED, pid, stack, type, value);
-	}
-
-	lt_stat_update_cause(pid, tid, cause_id, type, value);
-}
-
-/*
- * 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) {
-		clear_stat(NULL, stat_system, NULL);
-	}
-
-	if (sobj_table != NULL) {
-		g_hash_table_destroy(sobj_table);
-		sobj_table = NULL;
-	}
-}
-
-/*
- * Clean up function that frees all memory used for statistics.
- */
-void
-lt_stat_free_all(void)
-{
-	if (stat_system != NULL) {
-		free_stat(stat_system);
-		stat_system = NULL;
-	}
-
-	if (sobj_table != NULL) {
-		g_hash_table_destroy(sobj_table);
-		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 *
-lt_stat_list_create(lt_list_type_t list_type, lt_stat_level_t level,
-    pid_t pid, id_t tid, int count, lt_sort_t sort_by)
-{
-	GCompareFunc func;
-	GList *list, *walk;
-	lt_stat_collection_t *stat_c = NULL;
-	lt_stat_list_t *ret;
-	lt_datagroup_t *group;
-
-	if (level == LT_LEVEL_GLOBAL) {
-		/* Use global entry */
-		stat_c = stat_system;
-	} else if (stat_system != NULL && stat_system->lt_sc_children != NULL) {
-		/* Find process entry first */
-		stat_c = (lt_stat_collection_t *)g_hash_table_lookup(
-		    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
-
-		if (level == LT_LEVEL_THREAD) {
-			/*
-			 * If thread entry is requested, find it based on
-			 * process entry.
-			 */
-			if (stat_c != NULL && stat_c->lt_sc_children != NULL) {
-				stat_c = (lt_stat_collection_t *)
-				    g_hash_table_lookup(stat_c->lt_sc_children,
-				    LT_INT_TO_POINTER(tid));
-			} else {
-				/*
-				 * Thread entry was not found; set it to NULL,
-				 * so that we can return empty list later.
-				 */
-				stat_c = NULL;
-			}
-		}
-	}
-
-	ret = (lt_stat_list_t *)lt_zalloc(sizeof (lt_stat_list_t));
-	ret->lt_sl_entries = (lt_stat_entry_t **)
-	    lt_zalloc(count * sizeof (lt_stat_entry_t *));
-
-	if (stat_c == NULL) {
-		/* Empty list */
-		return (ret);
-	}
-
-	if (list_type == LT_LIST_SOBJ) {
-		group = &(stat_c->lt_sc_groups[GROUP_SOBJ]);
-	} else {
-		group = &(stat_c->lt_sc_groups[GROUP_CAUSE]);
-	}
-
-	if (group->lt_grp_cidlist == NULL) {
-		/* Empty list */
-		return (ret);
-	}
-
-	ret->lt_sl_gtotal = group->lt_grp_summary.lt_se_data.lt_s_total;
-
-	list = g_hash_table_get_values(group->lt_grp_cidlist);
-
-	switch (sort_by) {
-	case LT_SORT_TOTAL:
-		func = (GCompareFunc)lt_sort_by_total_desc;
-		break;
-	case LT_SORT_MAX:
-		func = (GCompareFunc)lt_sort_by_max_desc;
-		break;
-	case LT_SORT_AVG:
-		func = (GCompareFunc)lt_sort_by_avg_desc;
-		break;
-	case LT_SORT_COUNT:
-		func = (GCompareFunc)lt_sort_by_count_desc;
-		break;
-	}
-	list = g_list_sort(list, func);
-
-	for (walk = list;
-	    walk != NULL && count > 0;
-	    walk = g_list_next(walk), --count) {
-		lt_stat_entry_t *data = (lt_stat_entry_t *)walk->data;
-
-		if (list_type == LT_LIST_CAUSE &&
-		    data->lt_se_type == STAT_CAUSE &&
-		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
-		    CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
-			continue;
-		}
-
-		if (list_type == LT_LIST_SPECIALS &&
-		    data->lt_se_type == STAT_CAUSE &&
-		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
-		    CAUSE_FLAG_SPECIAL) == 0) {
-			continue;
-		}
-
-		if (data->lt_se_data.lt_s_count == 0) {
-			break;
-		}
-
-		ret->lt_sl_entries[ret->lt_sl_entry_count++] = data;
-	}
-
-	g_list_free(list);
-
-	return (ret);
-}
-
-/*
- * Free memory allocated by lt_stat_list_create().
- */
-void
-lt_stat_list_free(void *ptr)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL) {
-		return;
-	}
-
-	if (list->lt_sl_free_func != NULL) {
-		list->lt_sl_free_func(list);
-	}
-
-	if (list->lt_sl_entries != NULL) {
-		free(list->lt_sl_entries);
-	}
-
-	free(list);
-}
-
-/*
- * Check if the given list contains the given item.
- */
-int
-lt_stat_list_has_item(void *ptr, int i)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
-	    list->lt_sl_entries[i] == NULL) {
-		return (0);
-	}
-
-	return (1);
-}
-
-/*
- * Get display name of the given item i in the given list.
- */
-const char *
-lt_stat_list_get_reason(void *ptr, int i)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
-	    list->lt_sl_entries[i] == NULL) {
-		return (NULL);
-	}
-
-	g_assert(list->lt_sl_entries[i]->lt_se_string != NULL);
-
-	return (list->lt_sl_entries[i]->lt_se_string);
-}
-
-/*
- * Get maximum value of the given item i in the given list.
- */
-uint64_t
-lt_stat_list_get_max(void *ptr, int i)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
-	    list->lt_sl_entries[i] == NULL) {
-		return (0);
-	}
-
-	return (list->lt_sl_entries[i]->lt_se_data.lt_s_max);
-}
-
-/*
- * Get total value of the given item i in the given list.
- */
-uint64_t
-lt_stat_list_get_sum(void *ptr, int i)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
-	    list->lt_sl_entries[i] == NULL) {
-		return (0);
-	}
-
-	return (list->lt_sl_entries[i]->lt_se_data.lt_s_total);
-}
-
-/*
- * Get count value of the given item i in the given list.
- */
-uint64_t
-lt_stat_list_get_count(void *ptr, int i)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
-	    list->lt_sl_entries[i] == NULL) {
-		return (0);
-	}
-
-	return (list->lt_sl_entries[i]->lt_se_data.lt_s_count);
-}
-
-/*
- * Get grand total of all latency in the list.
- */
-uint64_t
-lt_stat_list_get_gtotal(void *ptr)
-{
-	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
-
-	if (list == NULL) {
-		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.
- */
-
-/*
- * Helper function, sort by PID/TID ascend.
- */
-static int
-sort_id(lt_stat_collection_t *a, lt_stat_collection_t *b)
-{
-	return ((int)(a->lt_sc_id - b->lt_sc_id));
-}
-
-/*
- * Get the current list of processes. Call lt_stat_proc_list_free after use
- * to clean up.
- */
-static int
-plist_create(pid_t ** list)
-{
-	GList *pid_list, *walk;
-	int ret, count;
-
-	ret = g_hash_table_size(stat_system->lt_sc_children);
-	*list = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
-
-	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
-	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
-
-	for (walk = pid_list, count = 0;
-	    walk != NULL && count < ret;
-	    walk = g_list_next(walk), ++count) {
-		(*list)[count] = (int)
-		    ((lt_stat_collection_t *)(walk->data))->lt_sc_id;
-	}
-
-	g_list_free(pid_list);
-
-	return (ret);
-}
-
-/*
- * Count the no. of threads currently present in a process.
- * Only thread that have SSLEEP are counted.
- */
-/* ARGSUSED */
-static void
-count_threads(gpointer key, lt_stat_collection_t *stat_c, int *ret)
-{
-	g_assert(ret != NULL);
-
-	if (stat_c->lt_sc_children != NULL) {
-		*ret += g_hash_table_size(stat_c->lt_sc_children);
-	}
-}
-
-/*
- * Get current list of processes and threads.
- * Call lt_stat_proc_list_free after use to clean up.
- */
-static int
-tlist_create(pid_t ** plist, id_t ** tlist)
-{
-	GList *pid_list, *walk_p;
-	GList *tid_list, *walk_t;
-	int ret = 0;
-	int count = 0;
-
-	g_hash_table_foreach(stat_system->lt_sc_children,
-	    (GHFunc)count_threads, &ret);
-
-	*plist = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
-	*tlist = (id_t *)lt_malloc(sizeof (id_t) * ret);
-
-	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
-	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
-
-	for (walk_p = pid_list; walk_p != NULL;
-	    walk_p = g_list_next(walk_p)) {
-		lt_stat_collection_t *stat_p =
-		    (lt_stat_collection_t *)walk_p->data;
-
-		if (stat_p->lt_sc_children == NULL) {
-			continue;
-		}
-
-		tid_list = g_hash_table_get_values(stat_p->lt_sc_children);
-		tid_list = g_list_sort(tid_list, (GCompareFunc)sort_id);
-
-		for (walk_t = tid_list; walk_t != NULL;
-		    walk_t = g_list_next(walk_t)) {
-			lt_stat_collection_t *stat_t =
-			    (lt_stat_collection_t *)walk_t->data;
-
-			(*plist)[count] = (int)stat_p->lt_sc_id;
-			(*tlist)[count] = (int)stat_t->lt_sc_id;
-
-			++count;
-		}
-		g_list_free(tid_list);
-	}
-
-	g_list_free(pid_list);
-	g_assert(count == ret);
-
-	return (ret);
-}
-
-/*
- * List of processes that are tracked by LatencyTOP.
- */
-int
-lt_stat_proc_list_create(pid_t ** plist, id_t ** tlist)
-{
-	if (plist == NULL) {
-		return (-1);
-	}
-
-	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
-		*plist = NULL;
-
-		if (tlist != NULL) {
-			*tlist = NULL;
-		}
-
-		return (0);
-	}
-
-	if (tlist == NULL) {
-		return (plist_create(plist));
-	} else {
-		return (tlist_create(plist, tlist));
-	}
-}
-
-/*
- * Free memory allocated by lt_stat_proc_list_create().
- */
-void
-lt_stat_proc_list_free(pid_t *plist, id_t *tlist)
-{
-	if (plist != NULL) {
-		free(plist);
-	}
-
-	if (tlist != NULL) {
-		free(tlist);
-	}
-}
-
-/*
- * Get executable name of the given process (ID).
- */
-const char *
-lt_stat_proc_get_name(pid_t pid)
-{
-	lt_stat_collection_t *stat_p = NULL;
-
-	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
-		return (NULL);
-	}
-
-	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
-	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
-
-	if (stat_p != NULL) {
-		return (stat_p->lt_sc_name);
-	} else   {
-		return (NULL);
-	}
-}
-
-/*
- * Get number of threads.
- */
-int
-lt_stat_proc_get_nthreads(pid_t pid)
-{
-	lt_stat_collection_t *stat_p = NULL;
-
-	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
-		return (0);
-	}
-
-	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
-	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
-
-	if (stat_p != NULL) {
-		return (g_hash_table_size(stat_p->lt_sc_children));
-	} else   {
-		return (0);
-	}
-}
-
-/*
- * Update statistics for synchronization objects.
- */
-void
-lt_stat_update_sobj(pid_t pid, id_t tid, int stype,
-    unsigned long long wchan,
-    lt_stat_type_t type, uint64_t value)
-{
-	lt_sobj_id_t id;
-	lt_sobj_t *sobj;
-	int cause_id;
-	lt_stat_collection_t *stat_t = NULL;
-
-	stat_t = get_stat_c(pid, tid);
-
-	if (stat_t == NULL) {
-		return;
-	}
-
-	id.lt_soi_type = stype;
-	id.lt_soi_addr = wchan;
-	sobj = lookup_sobj(&id);
-
-	if (sobj == NULL) {
-		return;
-	}
-
-	cause_id = sobj->lt_so_cause_id;
-
-	update_stat_entry(stat_t, cause_id, type, value,
-	    sobj->lt_so_string, GROUP_SOBJ);
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/stat.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,1050 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <sys/stat.h>
+
+#include "latencytop.h"
+
+/* Statistics for each process/thread. */
+typedef struct _lt_stat_collection lt_stat_collection_t;
+typedef gboolean (*check_child_func_t) (gpointer key,
+    lt_stat_collection_t *stat, void *user);
+
+typedef struct {
+	lt_stat_entry_t lt_grp_summary;
+	/* cause_id -> stat entry */
+	GHashTable *lt_grp_cidlist;
+} lt_datagroup_t;
+
+#define	NGROUPS			2
+#define	GROUP_CAUSE		0
+#define	GROUP_SOBJ		1
+
+/*
+ * 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 {
+	lt_stat_level_t lt_sc_level;
+	unsigned int lt_sc_id;
+	char *lt_sc_name;
+	lt_datagroup_t lt_sc_groups[NGROUPS];
+	/*
+	 * The following fields: lt_sc_parent, lt_sc_children and
+	 * lt_sc_check_child_func maintain the tree structure.
+	 */
+	lt_stat_collection_t *lt_sc_parent;		/* Parent node */
+	GHashTable *lt_sc_children;	/* pid/tid -> lt_stat_collection_t */
+	check_child_func_t lt_sc_check_child_func; /* Release dead children */
+};
+
+/* Internal data structure to back 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 lt_sl_entry_count;
+	lt_stat_entry_t **lt_sl_entries;
+	uint64_t lt_sl_gtotal;
+	free_list_func_t lt_sl_free_func;
+};
+
+/* Root of the collection hierarchy: system level statistics */
+static lt_stat_collection_t *stat_system = NULL;
+
+/*
+ * 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 {
+	lt_sobj_id_t lt_so_oid;
+	int lt_so_cause_id;
+	char lt_so_string[32];	/* Enough to hold "%s: 0x%llX" */
+} lt_sobj_t;
+
+static GHashTable *sobj_table = NULL;
+static int sobj_table_len = 0;
+
+/*
+ * Lower 32-bit of the address of synchronization objects is used to hash
+ * them.
+ */
+static guint
+sobj_id_hash(lt_sobj_id_t *id)
+{
+	g_assert(id != NULL);
+	return (id->lt_soi_addr & 0xFFFFFFFF);
+}
+
+/*
+ * Test if two synchronization objects are the same.
+ */
+static gboolean
+sobj_id_equal(lt_sobj_id_t *a, lt_sobj_id_t *b)
+{
+	g_assert(a != NULL && b != NULL);
+	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 *
+lookup_sobj(lt_sobj_id_t *id)
+{
+	const char *stype_str[] = {
+		"None",
+		"Mutex",
+		"RWLock",
+		"CV",
+		"Sema",
+		"User",
+		"User_PI",
+		"Shuttle"
+	};
+	const int stype_str_len =
+	    sizeof (stype_str) / sizeof (stype_str[0]);
+	lt_sobj_t *ret = NULL;
+	g_assert(id != NULL);
+
+	if (id->lt_soi_type < 0 || id->lt_soi_type >= stype_str_len) {
+		return (NULL);
+	}
+
+	if (sobj_table != NULL) {
+		ret = (lt_sobj_t *)g_hash_table_lookup(sobj_table, id);
+	} else {
+		sobj_table = g_hash_table_new_full(
+		    (GHashFunc)sobj_id_hash, (GEqualFunc)sobj_id_equal,
+		    NULL, (GDestroyNotify)free);
+		lt_check_null(sobj_table);
+	}
+
+	if (ret == NULL) {
+		ret = (lt_sobj_t *)lt_zalloc(sizeof (lt_sobj_t));
+		ret->lt_so_cause_id = ++sobj_table_len;
+		(void) snprintf(ret->lt_so_string, sizeof (ret->lt_so_string),
+		    "%s: 0x%llX", stype_str[id->lt_soi_type], id->lt_soi_addr);
+		ret->lt_so_oid.lt_soi_type = id->lt_soi_type;
+		ret->lt_so_oid.lt_soi_addr = id->lt_soi_addr;
+
+		g_hash_table_insert(sobj_table, &ret->lt_so_oid, ret);
+	}
+
+	return (ret);
+}
+
+/*
+ * Check if a process exists by using /proc/pid
+ */
+/* ARGSUSED */
+static gboolean
+check_process(gpointer key, lt_stat_collection_t *stat, void *user)
+{
+	char name[PATH_MAX];
+
+	(void) snprintf(name, PATH_MAX, "/proc/%u", stat->lt_sc_id);
+	return (lt_file_exist(name) ? FALSE : TRUE);
+}
+
+/*
+ * Check if a thread exists by using /proc/pid/lwp/tid
+ */
+/* ARGSUSED */
+static gboolean
+check_thread(gpointer key, lt_stat_collection_t *stat, void *user)
+{
+	char name[PATH_MAX];
+
+	g_assert(stat->lt_sc_parent != NULL);
+	g_assert(stat->lt_sc_parent->lt_sc_level == LT_LEVEL_PROCESS);
+
+	(void) snprintf(name, PATH_MAX, "/proc/%u/lwp/%u",
+	    stat->lt_sc_parent->lt_sc_id, stat->lt_sc_id);
+	return (lt_file_exist(name) ? FALSE : TRUE);
+}
+
+/*
+ * Helper function to free a stat node.
+ */
+static void
+free_stat(lt_stat_collection_t *stat)
+{
+	int i;
+
+	if (stat == NULL) {
+		return;
+	}
+
+	for (i = 0; i < NGROUPS; ++i) {
+		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
+			g_hash_table_destroy(stat->lt_sc_groups[i].
+			    lt_grp_cidlist);
+		}
+	}
+
+	if (stat->lt_sc_children != NULL) {
+		g_hash_table_destroy(stat->lt_sc_children);
+	}
+
+	if (stat->lt_sc_name != NULL) {
+		free(stat->lt_sc_name);
+	}
+
+	free(stat);
+}
+
+/*
+ * Helper function to initialize a stat node.
+ */
+/* ARGSUSED */
+static void
+clear_stat(gpointer key, lt_stat_collection_t *stat, void *user)
+{
+	int i;
+
+	g_assert(stat != NULL);
+
+	for (i = 0; i < NGROUPS; ++i) {
+		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
+			g_hash_table_destroy(stat->lt_sc_groups[i].
+			    lt_grp_cidlist);
+			stat->lt_sc_groups[i].lt_grp_cidlist = NULL;
+		}
+
+		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_count = 0;
+		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_total = 0;
+		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_max = 0;
+	}
+
+	if (stat->lt_sc_children != NULL) {
+		g_hash_table_foreach_remove(stat->lt_sc_children,
+		    (GHRFunc)stat->lt_sc_check_child_func, NULL);
+		g_hash_table_foreach(stat->lt_sc_children,
+		    (GHFunc)clear_stat, NULL);
+	}
+}
+
+/*
+ * Update a collection with the given value.
+ * Recursively update parents in the hierarchy  until the root is reached.
+ */
+static void
+update_stat_entry(lt_stat_collection_t *stat, int cause_id,
+    lt_stat_type_t type, uint64_t value,
+    const char *string, int group_to_use)
+{
+	lt_stat_entry_t *entry = NULL;
+	lt_datagroup_t *group;
+
+	if (group_to_use < 0 || group_to_use >= NGROUPS) {
+		return;
+	}
+
+	group = &(stat->lt_sc_groups[group_to_use]);
+
+	if (group->lt_grp_cidlist != NULL) {
+		entry = (lt_stat_entry_t *)g_hash_table_lookup(
+		    group->lt_grp_cidlist, LT_INT_TO_POINTER(cause_id));
+	} else   {
+		group->lt_grp_cidlist = g_hash_table_new_full(
+		    g_direct_hash, g_direct_equal,
+		    NULL, (GDestroyNotify)free);
+		lt_check_null(group->lt_grp_cidlist);
+	}
+
+	if (entry == NULL) {
+		entry = (lt_stat_entry_t *)lt_zalloc(sizeof (lt_stat_entry_t));
+		entry->lt_se_string = string;
+
+		switch (group_to_use) {
+		case GROUP_CAUSE:
+			entry->lt_se_type = STAT_CAUSE;
+			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_id = cause_id;
+			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags =
+			    lt_table_get_cause_flag(cause_id, CAUSE_ALL_FLAGS);
+
+			/* hide the first '#' */
+			if ((entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags
+			    & CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
+				++entry->lt_se_string;
+			}
+
+			break;
+		case GROUP_SOBJ:
+			entry->lt_se_type = STAT_SOBJ;
+			entry->lt_se_tsdata.lt_se_t_sobj.lt_se_s_id = cause_id;
+			break;
+		}
+
+		g_hash_table_insert(group->lt_grp_cidlist,
+		    LT_INT_TO_POINTER(cause_id), entry);
+	}
+
+	lt_update_stat_value(&entry->lt_se_data, type, value);
+
+	if (group_to_use == GROUP_SOBJ ||
+	    (entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
+	    CAUSE_FLAG_HIDE_IN_SUMMARY) == 0) {
+		lt_update_stat_value(&group->lt_grp_summary.lt_se_data, type,
+		    value);
+	}
+
+	if (stat->lt_sc_parent != NULL) {
+		update_stat_entry(stat->lt_sc_parent, cause_id, type, value,
+		    string, group_to_use);
+	}
+}
+
+/*
+ * Identify the cause of latency from the given stack trace.
+ * Return cause_id.
+ */
+static void
+find_cause(char *stack, int *cause_id, int *cause_priority)
+{
+	int cause_temp;
+	int prio_temp;
+	int cause = INVALID_CAUSE;
+	int priority = 0;
+	int found = 0;
+
+	g_assert(cause_id != NULL);
+	g_assert(cause_priority != NULL);
+
+	while (stack != NULL) {
+		char *sep;
+		sep = strchr(stack, ' ');
+
+		if (sep != NULL) {
+			*sep = '\0';
+		}
+
+		found = lt_table_cause_from_stack(stack, &cause_temp,
+		    &prio_temp);
+
+		if (found && (cause == INVALID_CAUSE ||
+		    HIGHER_PRIORITY(prio_temp, priority))) {
+			cause = cause_temp;
+			priority = prio_temp;
+		}
+
+		if (sep != NULL) {
+			*sep = ' ';
+			stack = sep + 1;
+		} else   {
+			stack = NULL;
+		}
+	}
+
+	*cause_id = cause;
+	*cause_priority = priority;
+}
+
+/*
+ * Create a new collection and hook it to the parent.
+ */
+static lt_stat_collection_t *
+new_collection(lt_stat_level_t level, unsigned int id, char *name,
+    lt_stat_collection_t *parent, check_child_func_t check_child_func)
+{
+	int i;
+	lt_stat_collection_t *ret;
+
+	ret = (lt_stat_collection_t *)
+	    lt_zalloc(sizeof (lt_stat_collection_t));
+
+	ret->lt_sc_level = level;
+	ret->lt_sc_check_child_func = check_child_func;
+	ret->lt_sc_id = id;
+	ret->lt_sc_name = name;
+
+	for (i = 0; i < NGROUPS; ++i) {
+		ret->lt_sc_groups[i].lt_grp_summary.lt_se_string =
+		    (const char *)name;
+	}
+
+	if (parent != NULL) {
+		ret->lt_sc_parent = parent;
+
+		if (parent->lt_sc_children == NULL) {
+			parent->lt_sc_children = g_hash_table_new_full(
+			    g_direct_hash, g_direct_equal,
+			    NULL, (GDestroyNotify)free_stat);
+			lt_check_null(parent->lt_sc_children);
+		}
+
+		g_hash_table_insert(parent->lt_sc_children,
+		    LT_INT_TO_POINTER((int)id), ret);
+	}
+
+	return (ret);
+}
+
+/*
+ * Find the "leaf" in the collection hierarchy, using the given pid and tid.
+ */
+static lt_stat_collection_t *
+get_stat_c(pid_t pid, id_t tid)
+{
+	lt_stat_collection_t *stat_p = NULL;
+	lt_stat_collection_t *stat_t = NULL;
+
+	if (stat_system == NULL) {
+		stat_system = new_collection(LT_LEVEL_GLOBAL,
+		    PID_SYS_GLOBAL, lt_strdup("SYSTEM"), NULL, check_process);
+	} else if (stat_system->lt_sc_children != NULL) {
+		stat_p = (lt_stat_collection_t *)
+		    g_hash_table_lookup(stat_system->lt_sc_children,
+		    LT_INT_TO_POINTER(pid));
+	}
+
+	if (stat_p == NULL) {
+		char *fname;
+		fname = lt_get_proc_field(pid, LT_FIELD_FNAME);
+
+		if (fname == NULL) {
+			/*
+			 * we could not get the executable name of the
+			 * process; the process is probably already dead.
+			 */
+			return (NULL);
+		}
+
+		stat_p = new_collection(LT_LEVEL_PROCESS,
+		    (unsigned int)pid, fname, stat_system, check_thread);
+	} else if (stat_p->lt_sc_children != NULL) {
+		stat_t = (lt_stat_collection_t *)
+		    g_hash_table_lookup(stat_p->lt_sc_children,
+		    LT_INT_TO_POINTER(tid));
+	}
+
+	if (stat_t == NULL) {
+		const int tname_size = 16; /* Enough for "Thread %d" */
+		char *tname;
+
+		tname = (char *)lt_zalloc(tname_size);
+		(void) snprintf(tname, tname_size, "Thread %d", tid);
+
+		stat_t = new_collection(LT_LEVEL_THREAD,
+		    (unsigned int)tid, tname, stat_p, NULL);
+	}
+
+	return (stat_t);
+}
+
+/*
+ * Update statistics with the given cause_id. Values will be added to
+ * internal statistics.
+ */
+void
+lt_stat_update_cause(pid_t pid, id_t tid, int cause_id, lt_stat_type_t type,
+    uint64_t value)
+{
+	const char *string;
+	lt_stat_collection_t *stat_t = NULL;
+
+	if (cause_id < 0 || value == 0) {
+		return;
+	}
+
+	if (lt_table_get_cause_flag(cause_id, CAUSE_FLAG_DISABLED)) {
+		/* Ignore this cause */
+		return;
+	}
+
+	stat_t = get_stat_c(pid, tid);
+
+	if (stat_t == NULL) {
+		/* Process must be dead. */
+		return;
+	}
+
+	string = lt_table_get_cause_name(cause_id);
+
+	update_stat_entry(stat_t, cause_id, type, value, string, GROUP_CAUSE);
+}
+
+/*
+ * 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
+lt_stat_update(pid_t pid, id_t tid, char *stack, char *tag,
+    unsigned int tag_priority, lt_stat_type_t type, uint64_t value)
+{
+	int tag_cause_id = INVALID_CAUSE;
+	int stack_cause_id = INVALID_CAUSE;
+	int cause_id = INVALID_CAUSE;
+	int stack_priority = 0;
+
+	if (value == 0) {
+		return;
+	}
+
+	find_cause(stack, &stack_cause_id, &stack_priority);
+
+	if (tag_priority != 0) {
+		tag_cause_id = lt_table_cause_from_name(tag, 0, 0);
+
+		if (tag_cause_id == INVALID_CAUSE) {
+			/* This must be a syscall tag */
+			char tmp[64];
+			(void) snprintf(tmp, sizeof (tmp), "Syscall: %s", tag);
+			tag_cause_id = lt_table_cause_from_name(tmp, 1, 0);
+		}
+	}
+
+	cause_id = (tag_priority > stack_priority) ? tag_cause_id :
+	    stack_cause_id;
+
+	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.
+		 */
+		cause_id = lt_table_cause_from_name(stack, 1,
+		    CAUSE_FLAG_SPECIAL);
+		lt_klog_log(LT_KLOG_LEVEL_UNMAPPED, pid, stack, type, value);
+	} else   {
+		lt_klog_log(LT_KLOG_LEVEL_MAPPED, pid, stack, type, value);
+	}
+
+	lt_stat_update_cause(pid, tid, cause_id, type, value);
+}
+
+/*
+ * 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) {
+		clear_stat(NULL, stat_system, NULL);
+	}
+
+	if (sobj_table != NULL) {
+		g_hash_table_destroy(sobj_table);
+		sobj_table = NULL;
+	}
+}
+
+/*
+ * Clean up function that frees all memory used for statistics.
+ */
+void
+lt_stat_free_all(void)
+{
+	if (stat_system != NULL) {
+		free_stat(stat_system);
+		stat_system = NULL;
+	}
+
+	if (sobj_table != NULL) {
+		g_hash_table_destroy(sobj_table);
+		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 *
+lt_stat_list_create(lt_list_type_t list_type, lt_stat_level_t level,
+    pid_t pid, id_t tid, int count, lt_sort_t sort_by)
+{
+	GCompareFunc func;
+	GList *list, *walk;
+	lt_stat_collection_t *stat_c = NULL;
+	lt_stat_list_t *ret;
+	lt_datagroup_t *group;
+
+	if (level == LT_LEVEL_GLOBAL) {
+		/* Use global entry */
+		stat_c = stat_system;
+	} else if (stat_system != NULL && stat_system->lt_sc_children != NULL) {
+		/* Find process entry first */
+		stat_c = (lt_stat_collection_t *)g_hash_table_lookup(
+		    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
+
+		if (level == LT_LEVEL_THREAD) {
+			/*
+			 * If thread entry is requested, find it based on
+			 * process entry.
+			 */
+			if (stat_c != NULL && stat_c->lt_sc_children != NULL) {
+				stat_c = (lt_stat_collection_t *)
+				    g_hash_table_lookup(stat_c->lt_sc_children,
+				    LT_INT_TO_POINTER(tid));
+			} else {
+				/*
+				 * Thread entry was not found; set it to NULL,
+				 * so that we can return empty list later.
+				 */
+				stat_c = NULL;
+			}
+		}
+	}
+
+	ret = (lt_stat_list_t *)lt_zalloc(sizeof (lt_stat_list_t));
+	ret->lt_sl_entries = (lt_stat_entry_t **)
+	    lt_zalloc(count * sizeof (lt_stat_entry_t *));
+
+	if (stat_c == NULL) {
+		/* Empty list */
+		return (ret);
+	}
+
+	if (list_type == LT_LIST_SOBJ) {
+		group = &(stat_c->lt_sc_groups[GROUP_SOBJ]);
+	} else {
+		group = &(stat_c->lt_sc_groups[GROUP_CAUSE]);
+	}
+
+	if (group->lt_grp_cidlist == NULL) {
+		/* Empty list */
+		return (ret);
+	}
+
+	ret->lt_sl_gtotal = group->lt_grp_summary.lt_se_data.lt_s_total;
+
+	list = g_hash_table_get_values(group->lt_grp_cidlist);
+
+	switch (sort_by) {
+	case LT_SORT_TOTAL:
+		func = (GCompareFunc)lt_sort_by_total_desc;
+		break;
+	case LT_SORT_MAX:
+		func = (GCompareFunc)lt_sort_by_max_desc;
+		break;
+	case LT_SORT_AVG:
+		func = (GCompareFunc)lt_sort_by_avg_desc;
+		break;
+	case LT_SORT_COUNT:
+		func = (GCompareFunc)lt_sort_by_count_desc;
+		break;
+	}
+	list = g_list_sort(list, func);
+
+	for (walk = list;
+	    walk != NULL && count > 0;
+	    walk = g_list_next(walk), --count) {
+		lt_stat_entry_t *data = (lt_stat_entry_t *)walk->data;
+
+		if (list_type == LT_LIST_CAUSE &&
+		    data->lt_se_type == STAT_CAUSE &&
+		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
+		    CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
+			continue;
+		}
+
+		if (list_type == LT_LIST_SPECIALS &&
+		    data->lt_se_type == STAT_CAUSE &&
+		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
+		    CAUSE_FLAG_SPECIAL) == 0) {
+			continue;
+		}
+
+		if (data->lt_se_data.lt_s_count == 0) {
+			break;
+		}
+
+		ret->lt_sl_entries[ret->lt_sl_entry_count++] = data;
+	}
+
+	g_list_free(list);
+
+	return (ret);
+}
+
+/*
+ * Free memory allocated by lt_stat_list_create().
+ */
+void
+lt_stat_list_free(void *ptr)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL) {
+		return;
+	}
+
+	if (list->lt_sl_free_func != NULL) {
+		list->lt_sl_free_func(list);
+	}
+
+	if (list->lt_sl_entries != NULL) {
+		free(list->lt_sl_entries);
+	}
+
+	free(list);
+}
+
+/*
+ * Check if the given list contains the given item.
+ */
+int
+lt_stat_list_has_item(void *ptr, int i)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
+	    list->lt_sl_entries[i] == NULL) {
+		return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * Get display name of the given item i in the given list.
+ */
+const char *
+lt_stat_list_get_reason(void *ptr, int i)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
+	    list->lt_sl_entries[i] == NULL) {
+		return (NULL);
+	}
+
+	g_assert(list->lt_sl_entries[i]->lt_se_string != NULL);
+
+	return (list->lt_sl_entries[i]->lt_se_string);
+}
+
+/*
+ * Get maximum value of the given item i in the given list.
+ */
+uint64_t
+lt_stat_list_get_max(void *ptr, int i)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
+	    list->lt_sl_entries[i] == NULL) {
+		return (0);
+	}
+
+	return (list->lt_sl_entries[i]->lt_se_data.lt_s_max);
+}
+
+/*
+ * Get total value of the given item i in the given list.
+ */
+uint64_t
+lt_stat_list_get_sum(void *ptr, int i)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
+	    list->lt_sl_entries[i] == NULL) {
+		return (0);
+	}
+
+	return (list->lt_sl_entries[i]->lt_se_data.lt_s_total);
+}
+
+/*
+ * Get count value of the given item i in the given list.
+ */
+uint64_t
+lt_stat_list_get_count(void *ptr, int i)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
+	    list->lt_sl_entries[i] == NULL) {
+		return (0);
+	}
+
+	return (list->lt_sl_entries[i]->lt_se_data.lt_s_count);
+}
+
+/*
+ * Get grand total of all latency in the list.
+ */
+uint64_t
+lt_stat_list_get_gtotal(void *ptr)
+{
+	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
+
+	if (list == NULL) {
+		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.
+ */
+
+/*
+ * Helper function, sort by PID/TID ascend.
+ */
+static int
+sort_id(lt_stat_collection_t *a, lt_stat_collection_t *b)
+{
+	return ((int)(a->lt_sc_id - b->lt_sc_id));
+}
+
+/*
+ * Get the current list of processes. Call lt_stat_proc_list_free after use
+ * to clean up.
+ */
+static int
+plist_create(pid_t ** list)
+{
+	GList *pid_list, *walk;
+	int ret, count;
+
+	ret = g_hash_table_size(stat_system->lt_sc_children);
+	*list = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
+
+	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
+	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
+
+	for (walk = pid_list, count = 0;
+	    walk != NULL && count < ret;
+	    walk = g_list_next(walk), ++count) {
+		(*list)[count] = (int)
+		    ((lt_stat_collection_t *)(walk->data))->lt_sc_id;
+	}
+
+	g_list_free(pid_list);
+
+	return (ret);
+}
+
+/*
+ * Count the no. of threads currently present in a process.
+ * Only thread that have SSLEEP are counted.
+ */
+/* ARGSUSED */
+static void
+count_threads(gpointer key, lt_stat_collection_t *stat_c, int *ret)
+{
+	g_assert(ret != NULL);
+
+	if (stat_c->lt_sc_children != NULL) {
+		*ret += g_hash_table_size(stat_c->lt_sc_children);
+	}
+}
+
+/*
+ * Get current list of processes and threads.
+ * Call lt_stat_proc_list_free after use to clean up.
+ */
+static int
+tlist_create(pid_t ** plist, id_t ** tlist)
+{
+	GList *pid_list, *walk_p;
+	GList *tid_list, *walk_t;
+	int ret = 0;
+	int count = 0;
+
+	g_hash_table_foreach(stat_system->lt_sc_children,
+	    (GHFunc)count_threads, &ret);
+
+	*plist = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
+	*tlist = (id_t *)lt_malloc(sizeof (id_t) * ret);
+
+	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
+	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
+
+	for (walk_p = pid_list; walk_p != NULL;
+	    walk_p = g_list_next(walk_p)) {
+		lt_stat_collection_t *stat_p =
+		    (lt_stat_collection_t *)walk_p->data;
+
+		if (stat_p->lt_sc_children == NULL) {
+			continue;
+		}
+
+		tid_list = g_hash_table_get_values(stat_p->lt_sc_children);
+		tid_list = g_list_sort(tid_list, (GCompareFunc)sort_id);
+
+		for (walk_t = tid_list; walk_t != NULL;
+		    walk_t = g_list_next(walk_t)) {
+			lt_stat_collection_t *stat_t =
+			    (lt_stat_collection_t *)walk_t->data;
+
+			(*plist)[count] = (int)stat_p->lt_sc_id;
+			(*tlist)[count] = (int)stat_t->lt_sc_id;
+
+			++count;
+		}
+		g_list_free(tid_list);
+	}
+
+	g_list_free(pid_list);
+	g_assert(count == ret);
+
+	return (ret);
+}
+
+/*
+ * List of processes that are tracked by LatencyTOP.
+ */
+int
+lt_stat_proc_list_create(pid_t ** plist, id_t ** tlist)
+{
+	if (plist == NULL) {
+		return (-1);
+	}
+
+	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
+		*plist = NULL;
+
+		if (tlist != NULL) {
+			*tlist = NULL;
+		}
+
+		return (0);
+	}
+
+	if (tlist == NULL) {
+		return (plist_create(plist));
+	} else {
+		return (tlist_create(plist, tlist));
+	}
+}
+
+/*
+ * Free memory allocated by lt_stat_proc_list_create().
+ */
+void
+lt_stat_proc_list_free(pid_t *plist, id_t *tlist)
+{
+	if (plist != NULL) {
+		free(plist);
+	}
+
+	if (tlist != NULL) {
+		free(tlist);
+	}
+}
+
+/*
+ * Get executable name of the given process (ID).
+ */
+const char *
+lt_stat_proc_get_name(pid_t pid)
+{
+	lt_stat_collection_t *stat_p = NULL;
+
+	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
+		return (NULL);
+	}
+
+	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
+	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
+
+	if (stat_p != NULL) {
+		return (stat_p->lt_sc_name);
+	} else   {
+		return (NULL);
+	}
+}
+
+/*
+ * Get number of threads.
+ */
+int
+lt_stat_proc_get_nthreads(pid_t pid)
+{
+	lt_stat_collection_t *stat_p = NULL;
+
+	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
+		return (0);
+	}
+
+	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
+	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
+
+	if (stat_p != NULL) {
+		return (g_hash_table_size(stat_p->lt_sc_children));
+	} else   {
+		return (0);
+	}
+}
+
+/*
+ * Update statistics for synchronization objects.
+ */
+void
+lt_stat_update_sobj(pid_t pid, id_t tid, int stype,
+    unsigned long long wchan,
+    lt_stat_type_t type, uint64_t value)
+{
+	lt_sobj_id_t id;
+	lt_sobj_t *sobj;
+	int cause_id;
+	lt_stat_collection_t *stat_t = NULL;
+
+	stat_t = get_stat_c(pid, tid);
+
+	if (stat_t == NULL) {
+		return;
+	}
+
+	id.lt_soi_type = stype;
+	id.lt_soi_addr = wchan;
+	sobj = lookup_sobj(&id);
+
+	if (sobj == NULL) {
+		return;
+	}
+
+	cause_id = sobj->lt_so_cause_id;
+
+	update_stat_entry(stat_t, cause_id, type, value,
+	    sobj->lt_so_string, GROUP_SOBJ);
+}
--- old/usr/src/cmd/latencytop/common/table.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,840 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <string.h>
-#include <memory.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#include "latencytop.h"
-
-/*
- * Structure that holds detail of a cause.
- */
-typedef struct {
-	int lt_c_cause_id;
-	int lt_c_flags;
-	char *lt_c_name;
-} lt_cause_t;
-
-/*
- * Structure that represents a matched cause.
- */
-typedef struct  {
-	int lt_mt_priority;
-	int lt_mt_cause_id;
-} lt_match_t;
-
-/* All lt_cause_t that are created. */
-static GHashTable *cause_lookup = NULL;
-static GPtrArray *causes_array = NULL;
-static int causes_array_len = 0;
-
-/*
- * This hash table maps a symbol to a cause.
- * key is of type "char *" and value is of type "lt_match_t *".
- */
-static GHashTable *symbol_lookup_table = NULL;
-
-/*
- * The dtrace translation rules we get from the script
- */
-char *dtrans = NULL;
-
-/*
- * These structures are only used inside .trans parser.
- */
-typedef struct {
-	int lt_dm_priority;
-	char *lt_dm_macro;
-} lt_dmacro_t;
-
-typedef struct {
-	GSequence *lt_pr_cmd_disable;
-	GHashTable *lt_pr_dmacro;
-} lt_parser_t;
-
-/* ARGSUSED */
-static void
-free_cause(lt_cause_t *cause, void *user)
-{
-	g_assert(cause != NULL && cause->lt_c_name != NULL);
-
-	free(cause->lt_c_name);
-	free(cause);
-}
-
-static void
-free_dmacro(lt_dmacro_t *d)
-{
-	g_assert(d->lt_dm_macro != NULL);
-	free(d->lt_dm_macro);
-	free(d);
-}
-
-/*
- * Add a cause.
- */
-static lt_cause_t *
-new_cause(char *name, int flags)
-{
-	lt_cause_t *entry;
-
-	g_assert(name != NULL);
-
-	entry = (lt_cause_t *)lt_malloc(sizeof (lt_cause_t));
-	entry->lt_c_flags = flags;
-	entry->lt_c_name = name;
-	entry->lt_c_cause_id = causes_array_len;
-
-	g_ptr_array_add(causes_array, entry);
-	++causes_array_len;
-
-	return (entry);
-}
-
-/*
- * Set a cause to "disabled" state.
- */
-static void
-disable_cause(char *cause_str, GHashTable *cause_table)
-{
-	lt_cause_t *cause;
-
-	cause = (lt_cause_t *)g_hash_table_lookup(cause_table, cause_str);
-
-	if (cause != NULL) {
-		cause->lt_c_flags |= CAUSE_FLAG_DISABLED;
-	}
-}
-
-/*
- * Helper functions that reads a line from a character array.
- */
-static int
-read_line_from_mem(const char *mem, int mem_len, char *line, int line_len,
-    int *index)
-{
-	g_assert(mem != NULL && line != NULL && index != NULL);
-
-	if (line_len <= 0 || mem_len <= 0) {
-		return (0);
-	}
-
-	if (*index >= mem_len) {
-		return (0);
-	}
-
-	while (line_len > 1 && *index < mem_len) {
-		*line = mem[(*index)++];
-		--line_len;
-		++line;
-
-		if (*(line-1) == '\r' || *(line-1) == '\n') {
-			break;
-		}
-	}
-	*line = '\0';
-
-	return (1);
-}
-
-/*
- * Parse special command from configuration file. Special command
- * has the following format :
-
- *	disable_cause <cause name>
- */
-static int
-parse_config_cmd(char *begin, lt_parser_t *parser)
-{
-	char *tmp;
-	char old_chr = 0;
-
-	/*
-	 * disable_cause  FSFlush Daemon
-	 * ^
-	 */
-	if (*begin == '\0') {
-		return (0);
-	}
-
-	for (tmp = begin;
-	    *tmp != '\0' && !isspace(*tmp);
-	    ++tmp) {
-	}
-	old_chr = *tmp;
-	*tmp = '\0';
-
-	if (strcmp("disable_cause", begin) == 0) {
-		if (old_chr == '\0') {
-			/* Must have an argument */
-			lt_display_error(
-			    "Invalid command format: %s\n",
-			    begin);
-			return (-1);
-		}
-
-		begin = tmp+1;
-		while (isspace(*begin)) {
-			++begin;
-		}
-
-		g_sequence_append(parser->lt_pr_cmd_disable,
-		    lt_strdup(begin));
-	} else   {
-		*tmp = old_chr;
-		lt_display_error(
-		    "Unknown command: %s\n", begin);
-		return (-1);
-	}
-
-	return (0);
-}
-
-/*
- * Parse symbol translation from configuration file. Symbol translation
- * has the following format :
- *
- *	<priority> <symbol name> <cause>
- *
- * Finally check if that cause has already been mapped.
- */
-static int
-parse_sym_trans(char *begin)
-{
-	int priority = 0;
-	char *match;
-	char *match_dup;
-	char *cause_str;
-	lt_cause_t *cause;
-	lt_match_t *match_entry;
-	char *tmp;
-
-	/*
-	 * 10	genunix`pread			Syscall pread
-	 * ^
-	 */
-	priority = strtol(begin, &tmp, 10);
-
-	if (tmp == begin || priority == 0) {
-		return (-1);
-	}
-
-	begin = tmp;
-
-	/*
-	 * 10	genunix`pread			Syscall pread
-	 * --^
-	 */
-
-	if (!isspace(*begin)) {
-		/* At least one space char after <priority> */
-		return (-1);
-	}
-
-	while (isspace(*begin)) {
-		++begin;
-	}
-
-	if (*begin == 0) {
-		return (-1);
-	}
-
-	/*
-	 * 10	genunix`pread			Syscall pread
-	 * -----^
-	 */
-	for (tmp = begin;
-	    *tmp != '\0' && !isspace(*tmp);
-	    ++tmp) {
-	}
-
-	if (*tmp == '\0') {
-		return (-1);
-	}
-
-	*tmp = '\0';
-	match = begin;
-
-	/* Check if we have mapped this function before. */
-	match_entry = (lt_match_t *)
-	    g_hash_table_lookup(symbol_lookup_table, match);
-
-	if (match_entry != NULL &&
-	    HIGHER_PRIORITY(match_entry->lt_mt_priority, priority)) {
-		/* We already have a higher entry. Ignore this. */
-		return (0);
-	}
-
-	begin = tmp + 1;
-
-	/*
-	 * 10	genunix`pread			Syscall pread
-	 * -------------------------------------^
-	 */
-	while (isspace(*begin)) {
-		++begin;
-	}
-
-	if (*begin == 0) {
-		return (-1);
-	}
-
-	cause_str = begin;
-
-	/* Check if we have mapped this cause before. */
-	cause = (lt_cause_t *)
-	    g_hash_table_lookup(cause_lookup, cause_str);
-
-	if (cause == NULL) {
-		char *cause_dup = lt_strdup(cause_str);
-		cause = new_cause(cause_dup, 0);
-		g_hash_table_insert(cause_lookup, cause_dup, cause);
-	}
-
-	match_entry = (lt_match_t *)lt_malloc(sizeof (lt_match_t));
-	match_entry->lt_mt_priority = priority;
-	match_entry->lt_mt_cause_id = cause->lt_c_cause_id;
-	match_dup = lt_strdup(match);
-
-	g_hash_table_insert(symbol_lookup_table, match_dup,
-	    match_entry);
-
-	return (0);
-}
-
-/*
- * Parse D macro. D macros have the following format :
- *
- *	<priority> <entry probe> <return probe> <cause>
- *
- * Finally check if that cause has already been mapped.
- */
-static int
-parse_dmacro(char *begin, lt_parser_t *parser)
-{
-	int priority = 0;
-	char *entryprobe;
-	char *returnprobe;
-	char *cause_str;
-	char buf[512];
-	char probepair[512];
-	char *tmp = NULL;
-	lt_cause_t *cause;
-	lt_dmacro_t *dmacro;
-
-	/*
-	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
-	 * ^
-	 */
-	priority = strtol(begin, &tmp, 10);
-
-	if (tmp == begin || priority == 0) {
-		return (-1);
-	}
-
-	begin = tmp;
-
-	/*
-	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
-	 * --^
-	 */
-	while (isspace(*begin)) {
-		++begin;
-	}
-
-	if (*begin == 0) {
-		return (-1);
-	}
-
-	/*
-	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
-	 * -----^
-	 */
-	for (tmp = begin;
-	    *tmp != '\0' && !isspace(*tmp);
-	    ++tmp) {
-	}
-
-	if (*tmp == '\0') {
-		return (-1);
-	}
-
-	*tmp = '\0';
-	entryprobe = begin;
-	begin = tmp + 1;
-
-	while (isspace(*begin)) {
-		++begin;
-	}
-
-	/*
-	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
-	 * -----------------------------^
-	 */
-	for (tmp = begin;
-	    *tmp != '\0' && !isspace(*tmp);
-	    ++tmp) {
-	}
-
-	if (*tmp == '\0') {
-		return (-1);
-	}
-
-	*tmp = '\0';
-	returnprobe = begin;
-	begin = tmp + 1;
-
-	while (isspace(*begin)) {
-		++begin;
-	}
-
-	/*
-	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
-	 * -----------------------------------------------------^
-	 */
-	if (*begin == 0) {
-		return (-1);
-	}
-
-	cause_str = begin;
-
-	dmacro = NULL;
-
-	/* Check if we have mapped this cause before. */
-	cause = (lt_cause_t *)
-	    g_hash_table_lookup(cause_lookup, cause_str);
-
-	if (cause == NULL) {
-		char *cause_dup = lt_strdup(cause_str);
-		cause = new_cause(cause_dup, 0);
-		g_hash_table_insert(cause_lookup, cause_dup, cause);
-	}
-
-	(void) snprintf(buf, sizeof (buf), "\nTRANSLATE(%s, %s, \"%s\", %d)\n",
-	    entryprobe, returnprobe, cause_str, priority);
-
-	(void) snprintf(probepair, sizeof (probepair), "%s %s", entryprobe,
-	    returnprobe);
-
-	g_assert(cause != NULL);
-	g_assert(parser->lt_pr_dmacro != NULL);
-
-	dmacro = g_hash_table_lookup(parser->lt_pr_dmacro, probepair);
-
-	if (dmacro == NULL) {
-		dmacro = (lt_dmacro_t *)lt_malloc(sizeof (lt_dmacro_t));
-		dmacro->lt_dm_priority = priority;
-		dmacro->lt_dm_macro = lt_strdup(buf);
-		g_hash_table_insert(parser->lt_pr_dmacro, lt_strdup(probepair),
-		    dmacro);
-	} else if (dmacro->lt_dm_priority < priority) {
-		free(dmacro->lt_dm_macro);
-		dmacro->lt_dm_priority = priority;
-		dmacro->lt_dm_macro = lt_strdup(buf);
-	}
-
-	return (0);
-}
-
-/*
- * Helper function to collect TRANSLATE() macros.
- */
-/* ARGSUSED */
-static void
-genscript(void *key, lt_dmacro_t *dmacro, GString *str)
-{
-	g_string_append(str, dmacro->lt_dm_macro);
-}
-
-/*
- * Main logic that parses translation rules one line at a time,
- * and creates a lookup table from it. The syntax for the translation
- * is as follows :
- *
- *	#				<--- comment
- *	D <D macro rule>		<--- D macro
- *	S <Symbol translation>		<--- Symbols
- *	disable_cause <cause>		<--- special command
- */
-static int
-parse_config(const char *work, int work_len)
-{
-	char line[256];
-	int len;
-	char *begin, *end;
-	int current = 0;
-	lt_parser_t parser;
-	int ret = 0;
-	char flag;
-	GString *script;
-
-	cause_lookup = g_hash_table_new(g_str_hash, g_str_equal);
-	lt_check_null(cause_lookup);
-
-	parser.lt_pr_cmd_disable = g_sequence_new((GDestroyNotify)free);
-	lt_check_null(parser.lt_pr_cmd_disable);
-
-	parser.lt_pr_dmacro = g_hash_table_new_full(g_str_hash,
-	    g_str_equal, (GDestroyNotify)free, (GDestroyNotify)free_dmacro);
-	lt_check_null(parser.lt_pr_dmacro);
-
-	while (read_line_from_mem(work, work_len, line, sizeof (line),
-	    &current)) {
-		len = strlen(line);
-
-		if (line[len-1] != '\n' && line[len-1] != '\r' &&
-		    current < work_len) {
-			lt_display_error("Configuration line too long.\n");
-			goto err;
-		}
-
-		begin = line;
-
-		while (isspace(*begin)) {
-			++begin;
-		}
-
-		if (*begin == '\0') {
-			/* Ignore empty line */
-			continue;
-		}
-
-		/* Delete trailing spaces. */
-		end = begin + strlen(begin) - 1;
-
-		while (isspace(*end)) {
-			--end;
-		}
-
-		end[1] = '\0';
-
-		flag = *begin;
-		++begin;
-
-		switch (flag) {
-		case '#':
-			ret = 0;
-			break;
-		case ';':
-			ret = parse_config_cmd(begin, &parser);
-			break;
-		case 'D':
-		case 'd':
-			if (!isspace(*begin)) {
-				lt_display_error(
-				    "No space after flag char: %s\n", line);
-			}
-			while (isspace(*begin)) {
-				++begin;
-			}
-			ret = parse_dmacro(begin, &parser);
-			break;
-		case 'S':
-		case 's':
-			if (!isspace(*begin)) {
-				lt_display_error(
-				    "No space after flag char: %s\n", line);
-			}
-			while (isspace(*begin)) {
-				++begin;
-			}
-			ret = parse_sym_trans(begin);
-			break;
-		default:
-			ret = -1;
-			break;
-		}
-
-		if (ret != 0) {
-			lt_display_error(
-			    "Invalid configuration line: %s\n", line);
-			goto err;
-		}
-	}
-
-	script = g_string_new(NULL);
-	g_hash_table_foreach(parser.lt_pr_dmacro, (GHFunc)genscript, script);
-	dtrans = g_string_free(script, FALSE);
-
-	if (dtrans != NULL && strlen(dtrans) == 0) {
-		free(dtrans);
-		dtrans = NULL;
-	}
-
-	g_sequence_foreach(parser.lt_pr_cmd_disable, (GFunc)disable_cause,
-	    cause_lookup);
-	g_sequence_free(parser.lt_pr_cmd_disable);
-
-	return (0);
-
-err:
-	g_sequence_free(parser.lt_pr_cmd_disable);
-	g_hash_table_destroy(parser.lt_pr_dmacro);
-	return (-1);
-
-}
-
-/*
- * Init function, called when latencytop starts.
- * It loads translation rules from the configuration file. The configuration
- * file defines some causes and symbols that match those causes.
- */
-int
-lt_table_init(void)
-{
-	char *config_loaded = NULL;
-	int config_loaded_len = 0;
-	const char *work = NULL;
-	int work_len = 0;
-	lt_cause_t *cause;
-
-#ifdef EMBED_CONFIGS
-	work = &latencytop_trans_start;
-	work_len = (int)(&latencytop_trans_end - &latencytop_trans_start);
-#endif
-
-	if (g_config.lt_cfg_config_name != NULL) {
-		FILE *fp;
-		fp = fopen(g_config.lt_cfg_config_name, "r");
-
-		if (NULL == fp) {
-			lt_display_error(
-			    "Unable to open configuration file.\n");
-			return (-1);
-		}
-
-		(void) fseek(fp, 0, SEEK_END);
-		config_loaded_len = (int)ftell(fp);
-		config_loaded = (char *)lt_malloc(config_loaded_len);
-		(void) fseek(fp, 0, SEEK_SET);
-
-		/* A zero-byte translation is valid */
-		if (config_loaded_len != 0 &&
-		    fread(config_loaded, config_loaded_len, 1, fp) == 0) {
-			lt_display_error(
-			    "Unable to read configuration file.\n");
-			(void) fclose(fp);
-			free(config_loaded);
-			return (-1);
-		}
-
-		(void) fclose(fp);
-		(void) printf("Loaded configuration from %s\n",
-		    g_config.lt_cfg_config_name);
-
-		work = config_loaded;
-		work_len = config_loaded_len;
-	}
-
-	lt_table_deinit();
-	causes_array = g_ptr_array_new();
-	lt_check_null(causes_array);
-
-	/* 0 is not used, but it is kept as a place for bugs etc. */
-	cause = new_cause(lt_strdup("Nothing"), CAUSE_FLAG_DISABLED);
-	g_assert(cause->lt_c_cause_id == INVALID_CAUSE);
-
-	symbol_lookup_table = g_hash_table_new_full(
-	    g_str_hash, g_str_equal,
-	    (GDestroyNotify)free, (GDestroyNotify)free);
-	lt_check_null(symbol_lookup_table);
-
-	if (work_len != 0 && parse_config(work, work_len) != 0) {
-		return (-1);
-	}
-
-	if (config_loaded != NULL) {
-		free(config_loaded);
-	}
-
-	return (0);
-}
-
-/*
- * Some causes, such as "lock spinning", do not have stack trace. Names
- * of such causes are explicitly specified in the D script.
- * This function resolves such causes and dynamically adds them
- * to the global tables when they are found first. If auto_create is set
- * to TRUE, the entry will be created if it is not found.
- * Return cause_id of the cause.
- */
-int
-lt_table_cause_from_name(char *name, int auto_create, int flags)
-{
-	lt_cause_t *cause = NULL;
-
-	if (cause_lookup == NULL) {
-		cause_lookup = g_hash_table_new(g_str_hash, g_str_equal);
-		lt_check_null(cause_lookup);
-	} else   {
-		cause = (lt_cause_t *)
-		    g_hash_table_lookup(cause_lookup, name);
-	}
-
-	if (cause == NULL && auto_create) {
-		char *cause_dup;
-
-		if (name[0] == '#') {
-			flags |= CAUSE_FLAG_HIDE_IN_SUMMARY;
-		}
-
-		cause_dup = lt_strdup(name);
-		cause = new_cause(cause_dup, flags);
-		g_hash_table_insert(cause_lookup, cause_dup, cause);
-	}
-
-	return (cause == NULL ? INVALID_CAUSE : cause->lt_c_cause_id);
-}
-
-/*
- * Try to map a symbol on stack to a known cause.
- * module_func has the format "module_name`function_name".
- * cause_id and priority will be set if a cause is found.
- * If cause is found return 1, otherwise return 0.
- */
-int
-lt_table_cause_from_stack(const char *module_func, int *cause_id, int *priority)
-{
-	lt_match_t *match;
-
-	g_assert(module_func != NULL && cause_id != NULL && priority != NULL);
-
-	if (symbol_lookup_table == NULL) {
-		return (0);
-	}
-
-	match = (lt_match_t *)
-	    g_hash_table_lookup(symbol_lookup_table, module_func);
-
-	if (match == NULL) {
-		char *func = strchr(module_func, '`');
-
-		if (func != NULL) {
-			match = (lt_match_t *)
-			    g_hash_table_lookup(symbol_lookup_table, func);
-		}
-	}
-
-	if (match == NULL) {
-		return (0);
-	} else   {
-		*cause_id = match->lt_mt_cause_id;
-		*priority = match->lt_mt_priority;
-		return (1);
-	}
-}
-
-/*
- * Get the display name of a cause. cause_id must be valid,
- * it is usually returned from lt_table_cause_from_stack() or
- * lt_table_cause_from_name().
- */
-const char *
-lt_table_get_cause_name(int cause_id)
-{
-	lt_cause_t *cause;
-
-	if (cause_id < 0 || cause_id >= causes_array_len) {
-		return (NULL);
-	}
-
-	cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id);
-
-	if (cause == NULL) {
-		return (NULL);
-	} else {
-		return (cause->lt_c_name);
-	}
-}
-
-/*
- * Check cause flag.
- * If CAUSE_ALL_FLAGS is passed in, all flags are returned.
- */
-int
-lt_table_get_cause_flag(int cause_id, int flag)
-{
-	lt_cause_t *cause;
-
-	if (cause_id < 0 || cause_id >= causes_array_len) {
-		return (0);
-	}
-
-	cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id);
-
-	if (cause == NULL) {
-		return (0);
-	} else {
-		return (cause->lt_c_flags & flag);
-	}
-}
-
-/*
- * Append macros to D script, if any.
- */
-int
-lt_table_append_trans(FILE *fp)
-{
-	if (dtrans != NULL) {
-		if (fwrite(dtrans, strlen(dtrans), 1, fp) != 1) {
-			return (-1);
-		}
-	}
-
-	return (0);
-}
-
-/*
- * Clean up function.
- * Free the resources used for symbol table (symbols, causes etc.).
- */
-void
-lt_table_deinit(void)
-{
-	if (symbol_lookup_table != NULL) {
-		g_hash_table_destroy(symbol_lookup_table);
-		symbol_lookup_table = NULL;
-	}
-
-	if (cause_lookup != NULL) {
-		g_hash_table_destroy(cause_lookup);
-		cause_lookup = NULL;
-	}
-
-	if (causes_array != NULL) {
-		g_ptr_array_foreach(causes_array, (GFunc)free_cause, NULL);
-		g_ptr_array_free(causes_array, TRUE);
-		causes_array = NULL;
-		causes_array_len = 0;
-	}
-
-	if (dtrans != NULL) {
-		g_free(dtrans);
-		dtrans = NULL;
-	}
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/table.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,840 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "latencytop.h"
+
+/*
+ * Structure that holds detail of a cause.
+ */
+typedef struct {
+	int lt_c_cause_id;
+	int lt_c_flags;
+	char *lt_c_name;
+} lt_cause_t;
+
+/*
+ * Structure that represents a matched cause.
+ */
+typedef struct  {
+	int lt_mt_priority;
+	int lt_mt_cause_id;
+} lt_match_t;
+
+/* All lt_cause_t that are created. */
+static GHashTable *cause_lookup = NULL;
+static GPtrArray *causes_array = NULL;
+static int causes_array_len = 0;
+
+/*
+ * This hash table maps a symbol to a cause.
+ * key is of type "char *" and value is of type "lt_match_t *".
+ */
+static GHashTable *symbol_lookup_table = NULL;
+
+/*
+ * The dtrace translation rules we get from the script
+ */
+char *dtrans = NULL;
+
+/*
+ * These structures are only used inside .trans parser.
+ */
+typedef struct {
+	int lt_dm_priority;
+	char *lt_dm_macro;
+} lt_dmacro_t;
+
+typedef struct {
+	GSequence *lt_pr_cmd_disable;
+	GHashTable *lt_pr_dmacro;
+} lt_parser_t;
+
+/* ARGSUSED */
+static void
+free_cause(lt_cause_t *cause, void *user)
+{
+	g_assert(cause != NULL && cause->lt_c_name != NULL);
+
+	free(cause->lt_c_name);
+	free(cause);
+}
+
+static void
+free_dmacro(lt_dmacro_t *d)
+{
+	g_assert(d->lt_dm_macro != NULL);
+	free(d->lt_dm_macro);
+	free(d);
+}
+
+/*
+ * Add a cause.
+ */
+static lt_cause_t *
+new_cause(char *name, int flags)
+{
+	lt_cause_t *entry;
+
+	g_assert(name != NULL);
+
+	entry = (lt_cause_t *)lt_malloc(sizeof (lt_cause_t));
+	entry->lt_c_flags = flags;
+	entry->lt_c_name = name;
+	entry->lt_c_cause_id = causes_array_len;
+
+	g_ptr_array_add(causes_array, entry);
+	++causes_array_len;
+
+	return (entry);
+}
+
+/*
+ * Set a cause to "disabled" state.
+ */
+static void
+disable_cause(char *cause_str, GHashTable *cause_table)
+{
+	lt_cause_t *cause;
+
+	cause = (lt_cause_t *)g_hash_table_lookup(cause_table, cause_str);
+
+	if (cause != NULL) {
+		cause->lt_c_flags |= CAUSE_FLAG_DISABLED;
+	}
+}
+
+/*
+ * Helper functions that reads a line from a character array.
+ */
+static int
+read_line_from_mem(const char *mem, int mem_len, char *line, int line_len,
+    int *index)
+{
+	g_assert(mem != NULL && line != NULL && index != NULL);
+
+	if (line_len <= 0 || mem_len <= 0) {
+		return (0);
+	}
+
+	if (*index >= mem_len) {
+		return (0);
+	}
+
+	while (line_len > 1 && *index < mem_len) {
+		*line = mem[(*index)++];
+		--line_len;
+		++line;
+
+		if (*(line-1) == '\r' || *(line-1) == '\n') {
+			break;
+		}
+	}
+	*line = '\0';
+
+	return (1);
+}
+
+/*
+ * Parse special command from configuration file. Special command
+ * has the following format :
+ *
+ *	disable_cause <cause name>
+ */
+static int
+parse_config_cmd(char *begin, lt_parser_t *parser)
+{
+	char *tmp;
+	char old_chr = 0;
+
+	/*
+	 * disable_cause  FSFlush Daemon
+	 * ^
+	 */
+	if (*begin == '\0') {
+		return (0);
+	}
+
+	for (tmp = begin;
+	    *tmp != '\0' && !isspace(*tmp);
+	    ++tmp) {
+	}
+	old_chr = *tmp;
+	*tmp = '\0';
+
+	if (strcmp("disable_cause", begin) == 0) {
+		if (old_chr == '\0') {
+			/* Must have an argument */
+			lt_display_error(
+			    "Invalid command format: %s\n",
+			    begin);
+			return (-1);
+		}
+
+		begin = tmp+1;
+		while (isspace(*begin)) {
+			++begin;
+		}
+
+		g_sequence_append(parser->lt_pr_cmd_disable,
+		    lt_strdup(begin));
+	} else   {
+		*tmp = old_chr;
+		lt_display_error(
+		    "Unknown command: %s\n", begin);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Parse symbol translation from configuration file. Symbol translation
+ * has the following format :
+ *
+ *	<priority> <symbol name> <cause>
+ *
+ * Finally check if that cause has already been mapped.
+ */
+static int
+parse_sym_trans(char *begin)
+{
+	int priority = 0;
+	char *match;
+	char *match_dup;
+	char *cause_str;
+	lt_cause_t *cause;
+	lt_match_t *match_entry;
+	char *tmp;
+
+	/*
+	 * 10	genunix`pread			Syscall pread
+	 * ^
+	 */
+	priority = strtol(begin, &tmp, 10);
+
+	if (tmp == begin || priority == 0) {
+		return (-1);
+	}
+
+	begin = tmp;
+
+	/*
+	 * 10	genunix`pread			Syscall pread
+	 * --^
+	 */
+
+	if (!isspace(*begin)) {
+		/* At least one space char after <priority> */
+		return (-1);
+	}
+
+	while (isspace(*begin)) {
+		++begin;
+	}
+
+	if (*begin == 0) {
+		return (-1);
+	}
+
+	/*
+	 * 10	genunix`pread			Syscall pread
+	 * -----^
+	 */
+	for (tmp = begin;
+	    *tmp != '\0' && !isspace(*tmp);
+	    ++tmp) {
+	}
+
+	if (*tmp == '\0') {
+		return (-1);
+	}
+
+	*tmp = '\0';
+	match = begin;
+
+	/* Check if we have mapped this function before. */
+	match_entry = (lt_match_t *)
+	    g_hash_table_lookup(symbol_lookup_table, match);
+
+	if (match_entry != NULL &&
+	    HIGHER_PRIORITY(match_entry->lt_mt_priority, priority)) {
+		/* We already have a higher entry. Ignore this. */
+		return (0);
+	}
+
+	begin = tmp + 1;
+
+	/*
+	 * 10	genunix`pread			Syscall pread
+	 * -------------------------------------^
+	 */
+	while (isspace(*begin)) {
+		++begin;
+	}
+
+	if (*begin == 0) {
+		return (-1);
+	}
+
+	cause_str = begin;
+
+	/* Check if we have mapped this cause before. */
+	cause = (lt_cause_t *)
+	    g_hash_table_lookup(cause_lookup, cause_str);
+
+	if (cause == NULL) {
+		char *cause_dup = lt_strdup(cause_str);
+		cause = new_cause(cause_dup, 0);
+		g_hash_table_insert(cause_lookup, cause_dup, cause);
+	}
+
+	match_entry = (lt_match_t *)lt_malloc(sizeof (lt_match_t));
+	match_entry->lt_mt_priority = priority;
+	match_entry->lt_mt_cause_id = cause->lt_c_cause_id;
+	match_dup = lt_strdup(match);
+
+	g_hash_table_insert(symbol_lookup_table, match_dup,
+	    match_entry);
+
+	return (0);
+}
+
+/*
+ * Parse D macro. D macros have the following format :
+ *
+ *	<priority> <entry probe> <return probe> <cause>
+ *
+ * Finally check if that cause has already been mapped.
+ */
+static int
+parse_dmacro(char *begin, lt_parser_t *parser)
+{
+	int priority = 0;
+	char *entryprobe;
+	char *returnprobe;
+	char *cause_str;
+	char buf[512];
+	char probepair[512];
+	char *tmp = NULL;
+	lt_cause_t *cause;
+	lt_dmacro_t *dmacro;
+
+	/*
+	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
+	 * ^
+	 */
+	priority = strtol(begin, &tmp, 10);
+
+	if (tmp == begin || priority == 0) {
+		return (-1);
+	}
+
+	begin = tmp;
+
+	/*
+	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
+	 * --^
+	 */
+	while (isspace(*begin)) {
+		++begin;
+	}
+
+	if (*begin == 0) {
+		return (-1);
+	}
+
+	/*
+	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
+	 * -----^
+	 */
+	for (tmp = begin;
+	    *tmp != '\0' && !isspace(*tmp);
+	    ++tmp) {
+	}
+
+	if (*tmp == '\0') {
+		return (-1);
+	}
+
+	*tmp = '\0';
+	entryprobe = begin;
+	begin = tmp + 1;
+
+	while (isspace(*begin)) {
+		++begin;
+	}
+
+	/*
+	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
+	 * -----------------------------^
+	 */
+	for (tmp = begin;
+	    *tmp != '\0' && !isspace(*tmp);
+	    ++tmp) {
+	}
+
+	if (*tmp == '\0') {
+		return (-1);
+	}
+
+	*tmp = '\0';
+	returnprobe = begin;
+	begin = tmp + 1;
+
+	while (isspace(*begin)) {
+		++begin;
+	}
+
+	/*
+	 * 10	syscall::pread:entry	syscall::pread:return	Syscall pread
+	 * -----------------------------------------------------^
+	 */
+	if (*begin == 0) {
+		return (-1);
+	}
+
+	cause_str = begin;
+
+	dmacro = NULL;
+
+	/* Check if we have mapped this cause before. */
+	cause = (lt_cause_t *)
+	    g_hash_table_lookup(cause_lookup, cause_str);
+
+	if (cause == NULL) {
+		char *cause_dup = lt_strdup(cause_str);
+		cause = new_cause(cause_dup, 0);
+		g_hash_table_insert(cause_lookup, cause_dup, cause);
+	}
+
+	(void) snprintf(buf, sizeof (buf), "\nTRANSLATE(%s, %s, \"%s\", %d)\n",
+	    entryprobe, returnprobe, cause_str, priority);
+
+	(void) snprintf(probepair, sizeof (probepair), "%s %s", entryprobe,
+	    returnprobe);
+
+	g_assert(cause != NULL);
+	g_assert(parser->lt_pr_dmacro != NULL);
+
+	dmacro = g_hash_table_lookup(parser->lt_pr_dmacro, probepair);
+
+	if (dmacro == NULL) {
+		dmacro = (lt_dmacro_t *)lt_malloc(sizeof (lt_dmacro_t));
+		dmacro->lt_dm_priority = priority;
+		dmacro->lt_dm_macro = lt_strdup(buf);
+		g_hash_table_insert(parser->lt_pr_dmacro, lt_strdup(probepair),
+		    dmacro);
+	} else if (dmacro->lt_dm_priority < priority) {
+		free(dmacro->lt_dm_macro);
+		dmacro->lt_dm_priority = priority;
+		dmacro->lt_dm_macro = lt_strdup(buf);
+	}
+
+	return (0);
+}
+
+/*
+ * Helper function to collect TRANSLATE() macros.
+ */
+/* ARGSUSED */
+static void
+genscript(void *key, lt_dmacro_t *dmacro, GString *str)
+{
+	g_string_append(str, dmacro->lt_dm_macro);
+}
+
+/*
+ * Main logic that parses translation rules one line at a time,
+ * and creates a lookup table from it. The syntax for the translation
+ * is as follows :
+ *
+ *	#				<--- comment
+ *	D <D macro rule>		<--- D macro
+ *	S <Symbol translation>		<--- Symbols
+ *	disable_cause <cause>		<--- special command
+ */
+static int
+parse_config(const char *work, int work_len)
+{
+	char line[256];
+	int len;
+	char *begin, *end;
+	int current = 0;
+	lt_parser_t parser;
+	int ret = 0;
+	char flag;
+	GString *script;
+
+	cause_lookup = g_hash_table_new(g_str_hash, g_str_equal);
+	lt_check_null(cause_lookup);
+
+	parser.lt_pr_cmd_disable = g_sequence_new((GDestroyNotify)free);
+	lt_check_null(parser.lt_pr_cmd_disable);
+
+	parser.lt_pr_dmacro = g_hash_table_new_full(g_str_hash,
+	    g_str_equal, (GDestroyNotify)free, (GDestroyNotify)free_dmacro);
+	lt_check_null(parser.lt_pr_dmacro);
+
+	while (read_line_from_mem(work, work_len, line, sizeof (line),
+	    &current)) {
+		len = strlen(line);
+
+		if (line[len-1] != '\n' && line[len-1] != '\r' &&
+		    current < work_len) {
+			lt_display_error("Configuration line too long.\n");
+			goto err;
+		}
+
+		begin = line;
+
+		while (isspace(*begin)) {
+			++begin;
+		}
+
+		if (*begin == '\0') {
+			/* Ignore empty line */
+			continue;
+		}
+
+		/* Delete trailing spaces. */
+		end = begin + strlen(begin) - 1;
+
+		while (isspace(*end)) {
+			--end;
+		}
+
+		end[1] = '\0';
+
+		flag = *begin;
+		++begin;
+
+		switch (flag) {
+		case '#':
+			ret = 0;
+			break;
+		case ';':
+			ret = parse_config_cmd(begin, &parser);
+			break;
+		case 'D':
+		case 'd':
+			if (!isspace(*begin)) {
+				lt_display_error(
+				    "No space after flag char: %s\n", line);
+			}
+			while (isspace(*begin)) {
+				++begin;
+			}
+			ret = parse_dmacro(begin, &parser);
+			break;
+		case 'S':
+		case 's':
+			if (!isspace(*begin)) {
+				lt_display_error(
+				    "No space after flag char: %s\n", line);
+			}
+			while (isspace(*begin)) {
+				++begin;
+			}
+			ret = parse_sym_trans(begin);
+			break;
+		default:
+			ret = -1;
+			break;
+		}
+
+		if (ret != 0) {
+			lt_display_error(
+			    "Invalid configuration line: %s\n", line);
+			goto err;
+		}
+	}
+
+	script = g_string_new(NULL);
+	g_hash_table_foreach(parser.lt_pr_dmacro, (GHFunc)genscript, script);
+	dtrans = g_string_free(script, FALSE);
+
+	if (dtrans != NULL && strlen(dtrans) == 0) {
+		free(dtrans);
+		dtrans = NULL;
+	}
+
+	g_sequence_foreach(parser.lt_pr_cmd_disable, (GFunc)disable_cause,
+	    cause_lookup);
+	g_sequence_free(parser.lt_pr_cmd_disable);
+
+	return (0);
+
+err:
+	g_sequence_free(parser.lt_pr_cmd_disable);
+	g_hash_table_destroy(parser.lt_pr_dmacro);
+	return (-1);
+
+}
+
+/*
+ * Init function, called when latencytop starts.
+ * It loads translation rules from the configuration file. The configuration
+ * file defines some causes and symbols that match those causes.
+ */
+int
+lt_table_init(void)
+{
+	char *config_loaded = NULL;
+	int config_loaded_len = 0;
+	const char *work = NULL;
+	int work_len = 0;
+	lt_cause_t *cause;
+
+#ifdef EMBED_CONFIGS
+	work = &latencytop_trans_start;
+	work_len = (int)(&latencytop_trans_end - &latencytop_trans_start);
+#endif
+
+	if (g_config.lt_cfg_config_name != NULL) {
+		FILE *fp;
+		fp = fopen(g_config.lt_cfg_config_name, "r");
+
+		if (NULL == fp) {
+			lt_display_error(
+			    "Unable to open configuration file.\n");
+			return (-1);
+		}
+
+		(void) fseek(fp, 0, SEEK_END);
+		config_loaded_len = (int)ftell(fp);
+		config_loaded = (char *)lt_malloc(config_loaded_len);
+		(void) fseek(fp, 0, SEEK_SET);
+
+		/* A zero-byte translation is valid */
+		if (config_loaded_len != 0 &&
+		    fread(config_loaded, config_loaded_len, 1, fp) == 0) {
+			lt_display_error(
+			    "Unable to read configuration file.\n");
+			(void) fclose(fp);
+			free(config_loaded);
+			return (-1);
+		}
+
+		(void) fclose(fp);
+		(void) printf("Loaded configuration from %s\n",
+		    g_config.lt_cfg_config_name);
+
+		work = config_loaded;
+		work_len = config_loaded_len;
+	}
+
+	lt_table_deinit();
+	causes_array = g_ptr_array_new();
+	lt_check_null(causes_array);
+
+	/* 0 is not used, but it is kept as a place for bugs etc. */
+	cause = new_cause(lt_strdup("Nothing"), CAUSE_FLAG_DISABLED);
+	g_assert(cause->lt_c_cause_id == INVALID_CAUSE);
+
+	symbol_lookup_table = g_hash_table_new_full(
+	    g_str_hash, g_str_equal,
+	    (GDestroyNotify)free, (GDestroyNotify)free);
+	lt_check_null(symbol_lookup_table);
+
+	if (work_len != 0 && parse_config(work, work_len) != 0) {
+		return (-1);
+	}
+
+	if (config_loaded != NULL) {
+		free(config_loaded);
+	}
+
+	return (0);
+}
+
+/*
+ * Some causes, such as "lock spinning", do not have stack trace. Names
+ * of such causes are explicitly specified in the D script.
+ * This function resolves such causes and dynamically adds them
+ * to the global tables when they are found first. If auto_create is set
+ * to TRUE, the entry will be created if it is not found.
+ * Return cause_id of the cause.
+ */
+int
+lt_table_cause_from_name(char *name, int auto_create, int flags)
+{
+	lt_cause_t *cause = NULL;
+
+	if (cause_lookup == NULL) {
+		cause_lookup = g_hash_table_new(g_str_hash, g_str_equal);
+		lt_check_null(cause_lookup);
+	} else   {
+		cause = (lt_cause_t *)
+		    g_hash_table_lookup(cause_lookup, name);
+	}
+
+	if (cause == NULL && auto_create) {
+		char *cause_dup;
+
+		if (name[0] == '#') {
+			flags |= CAUSE_FLAG_HIDE_IN_SUMMARY;
+		}
+
+		cause_dup = lt_strdup(name);
+		cause = new_cause(cause_dup, flags);
+		g_hash_table_insert(cause_lookup, cause_dup, cause);
+	}
+
+	return (cause == NULL ? INVALID_CAUSE : cause->lt_c_cause_id);
+}
+
+/*
+ * Try to map a symbol on stack to a known cause.
+ * module_func has the format "module_name`function_name".
+ * cause_id and priority will be set if a cause is found.
+ * If cause is found return 1, otherwise return 0.
+ */
+int
+lt_table_cause_from_stack(const char *module_func, int *cause_id, int *priority)
+{
+	lt_match_t *match;
+
+	g_assert(module_func != NULL && cause_id != NULL && priority != NULL);
+
+	if (symbol_lookup_table == NULL) {
+		return (0);
+	}
+
+	match = (lt_match_t *)
+	    g_hash_table_lookup(symbol_lookup_table, module_func);
+
+	if (match == NULL) {
+		char *func = strchr(module_func, '`');
+
+		if (func != NULL) {
+			match = (lt_match_t *)
+			    g_hash_table_lookup(symbol_lookup_table, func);
+		}
+	}
+
+	if (match == NULL) {
+		return (0);
+	} else   {
+		*cause_id = match->lt_mt_cause_id;
+		*priority = match->lt_mt_priority;
+		return (1);
+	}
+}
+
+/*
+ * Get the display name of a cause. cause_id must be valid,
+ * it is usually returned from lt_table_cause_from_stack() or
+ * lt_table_cause_from_name().
+ */
+const char *
+lt_table_get_cause_name(int cause_id)
+{
+	lt_cause_t *cause;
+
+	if (cause_id < 0 || cause_id >= causes_array_len) {
+		return (NULL);
+	}
+
+	cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id);
+
+	if (cause == NULL) {
+		return (NULL);
+	} else {
+		return (cause->lt_c_name);
+	}
+}
+
+/*
+ * Check cause flag.
+ * If CAUSE_ALL_FLAGS is passed in, all flags are returned.
+ */
+int
+lt_table_get_cause_flag(int cause_id, int flag)
+{
+	lt_cause_t *cause;
+
+	if (cause_id < 0 || cause_id >= causes_array_len) {
+		return (0);
+	}
+
+	cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id);
+
+	if (cause == NULL) {
+		return (0);
+	} else {
+		return (cause->lt_c_flags & flag);
+	}
+}
+
+/*
+ * Append macros to D script, if any.
+ */
+int
+lt_table_append_trans(FILE *fp)
+{
+	if (dtrans != NULL) {
+		if (fwrite(dtrans, strlen(dtrans), 1, fp) != 1) {
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Clean up function.
+ * Free the resources used for symbol table (symbols, causes etc.).
+ */
+void
+lt_table_deinit(void)
+{
+	if (symbol_lookup_table != NULL) {
+		g_hash_table_destroy(symbol_lookup_table);
+		symbol_lookup_table = NULL;
+	}
+
+	if (cause_lookup != NULL) {
+		g_hash_table_destroy(cause_lookup);
+		cause_lookup = NULL;
+	}
+
+	if (causes_array != NULL) {
+		g_ptr_array_foreach(causes_array, (GFunc)free_cause, NULL);
+		g_ptr_array_free(causes_array, TRUE);
+		causes_array = NULL;
+		causes_array_len = 0;
+	}
+
+	if (dtrans != NULL) {
+		g_free(dtrans);
+		dtrans = NULL;
+	}
+}
--- old/usr/src/cmd/latencytop/common/util.c	Thu Apr 11 14:30:36 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,312 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 <unistd.h>
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <procfs.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "latencytop.h"
-
-/* Pipe that breaks the event loop (and exits early) */
-static int signal_pipe[2];
-
-/*
- * Get current system time in milliseconds (1e-3).
- */
-uint64_t
-lt_millisecond(void)
-{
-	struct timeval p;
-	(void) gettimeofday(&p, NULL);
-	return ((uint64_t)p.tv_sec * 1000 + p.tv_usec / 1000);
-}
-
-/*
- * Check if we are out of memory.
- */
-void
-lt_check_null(void *p)
-{
-	if (p == NULL) {
-		(void) fprintf(stderr, "Out of memory!\n");
-		g_assert(0);
-		exit(2);
-	}
-}
-
-/*
- * Safe malloc.
- */
-void *
-lt_malloc(size_t size)
-{
-	void *ret = malloc(size);
-
-	lt_check_null(ret);
-
-	return (ret);
-}
-
-/*
- * Safe alloc with memory cleared.
- * It is named "zalloc" because its signature is different from
- * calloc() in stdlib.
- */
-void *
-lt_zalloc(size_t size)
-{
-	void *ret = calloc(size, 1);
-
-	lt_check_null(ret);
-
-	return (ret);
-}
-
-/*
- * Safe strdup.
- */
-char *
-lt_strdup(const char *str)
-{
-	char *ret = strdup(str);
-
-	lt_check_null(ret);
-
-	return (ret);
-}
-
-/*
- * Get string for current time, e.g. YYYY-MM-DD
- */
-void
-lt_time_str(char *buffer, int len)
-{
-	struct tm tms;
-	time_t t;
-	int i;
-
-	(void) time(&t);
-	(void) gmtime_r(&t, &tms);
-	(void) asctime_r(&tms, buffer, len);
-
-	for (i = strlen(buffer)-1; i > 0; --i) {
-
-		if (isspace(buffer[i])) {
-			buffer[i] = '\0';
-		} else {
-			break;
-		}
-	}
-}
-
-/*
- * Retrieves the process's executable name and arguments from /proc.
- */
-char *
-lt_get_proc_field(pid_t pid, lt_field_t field)
-{
-	char name[PATH_MAX];
-	int fd;
-	int ret;
-	psinfo_t psinfo;
-
-	(void) snprintf(name, PATH_MAX, "/proc/%d/psinfo", (int)pid);
-	fd = open(name, O_RDONLY);
-
-	if (fd == -1) {
-		return (NULL);
-	}
-
-	ret = read(fd, (char *)&psinfo, sizeof (psinfo_t));
-	(void) close(fd);
-
-	if (ret < 0) {
-		return (NULL);
-	}
-
-	switch (field) {
-	case LT_FIELD_FNAME:
-		return (lt_strdup(psinfo.pr_fname));
-	case LT_FIELD_PSARGS:
-		return (lt_strdup(psinfo.pr_psargs));
-	}
-	return (NULL);
-}
-
-/*
- * Helper function to update the data structure.
- */
-void
-lt_update_stat_value(lt_stat_data_t *entry,
-    lt_stat_type_t type, uint64_t value)
-{
-	switch (type) {
-	case LT_STAT_COUNT:
-		entry->lt_s_count += value;
-		break;
-	case LT_STAT_SUM:
-		entry->lt_s_total += value;
-		break;
-	case LT_STAT_MAX:
-		if (value > entry->lt_s_max) {
-			entry->lt_s_max = value;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-/*
- * Helper function to sort on total.
- */
-int
-lt_sort_by_total_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
-{
-	g_assert(a != NULL && b != NULL);
-	/*
-	 * lt_s_total is of type int64_t, so we can't simply return
-	 * (b->lt_se_data.lt_s_total - a->lt_se_data.lt_s_total).
-	 */
-	if (b->lt_se_data.lt_s_total > a->lt_se_data.lt_s_total) {
-		return (1);
-	} else if (b->lt_se_data.lt_s_total < a->lt_se_data.lt_s_total) {
-		return (-1);
-	} else {
-		return (0);
-	}
-}
-
-/*
- * Helper function to sort on max.
- */
-int
-lt_sort_by_max_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
-{
-	g_assert(a != NULL && b != NULL);
-
-	if (b->lt_se_data.lt_s_max > a->lt_se_data.lt_s_max) {
-		return (1);
-	} else if (b->lt_se_data.lt_s_max < a->lt_se_data.lt_s_max) {
-		return (-1);
-	} else {
-		return (0);
-	}
-}
-
-/*
- * Helper function to sort on count.
- */
-int
-lt_sort_by_count_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
-{
-	g_assert(a != NULL && b != NULL);
-
-	if (b->lt_se_data.lt_s_count > a->lt_se_data.lt_s_count) {
-		return (1);
-	} else if (b->lt_se_data.lt_s_count < a->lt_se_data.lt_s_count) {
-		return (-1);
-	} else {
-		return (0);
-	}
-}
-
-/*
- * Helper function to sort on average.
- */
-int
-lt_sort_by_avg_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
-{
-	double avg_a, avg_b;
-
-	g_assert(a != NULL && b != NULL);
-
-	avg_a = (double)a->lt_se_data.lt_s_total / a->lt_se_data.lt_s_count;
-	avg_b = (double)b->lt_se_data.lt_s_total / b->lt_se_data.lt_s_count;
-
-	if (avg_b > avg_a) {
-		return (1);
-	} else if (avg_b < avg_a) {
-		return (-1);
-	} else {
-		return (0);
-	}
-}
-
-/*
- * Create pipe for signal handler and wakeup.
- */
-void
-lt_gpipe_init(void)
-{
-	(void) pipe(signal_pipe);
-}
-
-/*
- * Close the pipe used in signal handler.
- */
-void
-lt_gpipe_deinit(void)
-{
-	(void) close(signal_pipe[0]);
-	(void) close(signal_pipe[1]);
-}
-
-/*
- * Break early from the main loop.
- */
-void
-lt_gpipe_break(const char *ch)
-{
-	(void) write(signal_pipe[1], ch, 1);
-}
-
-int
-lt_gpipe_readfd(void)
-{
-	return (signal_pipe[0]);
-}
-
-/*
- * Check if the given file exists.
- */
-int
-lt_file_exist(const char *name)
-{
-	struct stat64 st;
-
-	if (stat64(name, &st) == 0) {
-		return (1);
-	} else {
-		return (0);
-	}
-}
--- /dev/null	Thu Apr 11 08:00:00 2024
+++ new/usr/src/cmd/latencytop/util.c	Thu Apr 11 14:30:36 2024
@@ -0,0 +1,312 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <unistd.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <procfs.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "latencytop.h"
+
+/* Pipe that breaks the event loop (and exits early) */
+static int signal_pipe[2];
+
+/*
+ * Get current system time in milliseconds (1e-3).
+ */
+uint64_t
+lt_millisecond(void)
+{
+	struct timeval p;
+	(void) gettimeofday(&p, NULL);
+	return ((uint64_t)p.tv_sec * 1000 + p.tv_usec / 1000);
+}
+
+/*
+ * Check if we are out of memory.
+ */
+void
+lt_check_null(void *p)
+{
+	if (p == NULL) {
+		(void) fprintf(stderr, "Out of memory!\n");
+		g_assert(0);
+		exit(2);
+	}
+}
+
+/*
+ * Safe malloc.
+ */
+void *
+lt_malloc(size_t size)
+{
+	void *ret = malloc(size);
+
+	lt_check_null(ret);
+
+	return (ret);
+}
+
+/*
+ * Safe alloc with memory cleared.
+ * It is named "zalloc" because its signature is different from
+ * calloc() in stdlib.
+ */
+void *
+lt_zalloc(size_t size)
+{
+	void *ret = calloc(size, 1);
+
+	lt_check_null(ret);
+
+	return (ret);
+}
+
+/*
+ * Safe strdup.
+ */
+char *
+lt_strdup(const char *str)
+{
+	char *ret = strdup(str);
+
+	lt_check_null(ret);
+
+	return (ret);
+}
+
+/*
+ * Get string for current time, e.g. YYYY-MM-DD
+ */
+void
+lt_time_str(char *buffer, int len)
+{
+	struct tm tms;
+	time_t t;
+	int i;
+
+	(void) time(&t);
+	(void) gmtime_r(&t, &tms);
+	(void) asctime_r(&tms, buffer, len);
+
+	for (i = strlen(buffer)-1; i > 0; --i) {
+
+		if (isspace(buffer[i])) {
+			buffer[i] = '\0';
+		} else {
+			break;
+		}
+	}
+}
+
+/*
+ * Retrieves the process's executable name and arguments from /proc.
+ */
+char *
+lt_get_proc_field(pid_t pid, lt_field_t field)
+{
+	char name[PATH_MAX];
+	int fd;
+	int ret;
+	psinfo_t psinfo;
+
+	(void) snprintf(name, PATH_MAX, "/proc/%d/psinfo", (int)pid);
+	fd = open(name, O_RDONLY);
+
+	if (fd == -1) {
+		return (NULL);
+	}
+
+	ret = read(fd, (char *)&psinfo, sizeof (psinfo_t));
+	(void) close(fd);
+
+	if (ret < 0) {
+		return (NULL);
+	}
+
+	switch (field) {
+	case LT_FIELD_FNAME:
+		return (lt_strdup(psinfo.pr_fname));
+	case LT_FIELD_PSARGS:
+		return (lt_strdup(psinfo.pr_psargs));
+	}
+	return (NULL);
+}
+
+/*
+ * Helper function to update the data structure.
+ */
+void
+lt_update_stat_value(lt_stat_data_t *entry,
+    lt_stat_type_t type, uint64_t value)
+{
+	switch (type) {
+	case LT_STAT_COUNT:
+		entry->lt_s_count += value;
+		break;
+	case LT_STAT_SUM:
+		entry->lt_s_total += value;
+		break;
+	case LT_STAT_MAX:
+		if (value > entry->lt_s_max) {
+			entry->lt_s_max = value;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Helper function to sort on total.
+ */
+int
+lt_sort_by_total_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
+{
+	g_assert(a != NULL && b != NULL);
+	/*
+	 * lt_s_total is of type int64_t, so we can't simply return
+	 * (b->lt_se_data.lt_s_total - a->lt_se_data.lt_s_total).
+	 */
+	if (b->lt_se_data.lt_s_total > a->lt_se_data.lt_s_total) {
+		return (1);
+	} else if (b->lt_se_data.lt_s_total < a->lt_se_data.lt_s_total) {
+		return (-1);
+	} else {
+		return (0);
+	}
+}
+
+/*
+ * Helper function to sort on max.
+ */
+int
+lt_sort_by_max_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
+{
+	g_assert(a != NULL && b != NULL);
+
+	if (b->lt_se_data.lt_s_max > a->lt_se_data.lt_s_max) {
+		return (1);
+	} else if (b->lt_se_data.lt_s_max < a->lt_se_data.lt_s_max) {
+		return (-1);
+	} else {
+		return (0);
+	}
+}
+
+/*
+ * Helper function to sort on count.
+ */
+int
+lt_sort_by_count_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
+{
+	g_assert(a != NULL && b != NULL);
+
+	if (b->lt_se_data.lt_s_count > a->lt_se_data.lt_s_count) {
+		return (1);
+	} else if (b->lt_se_data.lt_s_count < a->lt_se_data.lt_s_count) {
+		return (-1);
+	} else {
+		return (0);
+	}
+}
+
+/*
+ * Helper function to sort on average.
+ */
+int
+lt_sort_by_avg_desc(lt_stat_entry_t *a, lt_stat_entry_t *b)
+{
+	double avg_a, avg_b;
+
+	g_assert(a != NULL && b != NULL);
+
+	avg_a = (double)a->lt_se_data.lt_s_total / a->lt_se_data.lt_s_count;
+	avg_b = (double)b->lt_se_data.lt_s_total / b->lt_se_data.lt_s_count;
+
+	if (avg_b > avg_a) {
+		return (1);
+	} else if (avg_b < avg_a) {
+		return (-1);
+	} else {
+		return (0);
+	}
+}
+
+/*
+ * Create pipe for signal handler and wakeup.
+ */
+void
+lt_gpipe_init(void)
+{
+	(void) pipe(signal_pipe);
+}
+
+/*
+ * Close the pipe used in signal handler.
+ */
+void
+lt_gpipe_deinit(void)
+{
+	(void) close(signal_pipe[0]);
+	(void) close(signal_pipe[1]);
+}
+
+/*
+ * Break early from the main loop.
+ */
+void
+lt_gpipe_break(const char *ch)
+{
+	(void) write(signal_pipe[1], ch, 1);
+}
+
+int
+lt_gpipe_readfd(void)
+{
+	return (signal_pipe[0]);
+}
+
+/*
+ * Check if the given file exists.
+ */
+int
+lt_file_exist(const char *name)
+{
+	struct stat64 st;
+
+	if (stat64(name, &st) == 0) {
+		return (1);
+	} else {
+		return (0);
+	}
+}
--- old/usr/src/cmd/lockstat/Makefile	Thu Apr 11 14:30:37 2024
+++ new/usr/src/cmd/lockstat/Makefile	Thu Apr 11 14:30:37 2024
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# 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
 # or http://www.opensolaris.org/os/licensing.
@@ -20,38 +19,48 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
+# Copyright (c) 2018, Joyent, Inc.
 
 PROG= lockstat
+OBJS= lockstat.o sym.o
 
 include ../Makefile.cmd
+include ../Makefile.cmd.64
 
-$(64ONLY)SUBDIRS= $(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
+LDLIBS += -lelf -lkstat -ldtrace
+CPPFLAGS += -D_ELF64
+CFLAGS += $(CCVERBOSE)
+CFLAGS64 += $(CCVERBOSE)
+CERRWARN += $(CNOWARN_UNINIT)
 
-all	:=	TARGET = all
-install	:=	TARGET = install
-clean	:=	TARGET = clean
-clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
+SMOFF += index_overflow
 
+FILEMODE= 0555
+
+CLEANFILES += $(OBJS)
+
+ROOTLINK = $(PROG:%=$(ROOTUSRSBIN64)/%)
+
 .KEEP_STATE:
 
-all:	$(SUBDIRS)
+all: $(PROG)
 
-clean clobber lint:	$(SUBDIRS)
+install: all $(ROOTUSRSBINPROG) $(ROOTLINK)
 
-install:	$(SUBDIRS)
-	-$(RM) $(ROOTUSRSBINPROG)
-	-$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG)
+$(ROOTLINK):
+	$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@
 
-$(SUBDIRS):	FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
+$(PROG):	$(OBJS)
+	$(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS)
+	$(POST_PROCESS)
 
-FRC:
+clean:
+	-$(RM) $(CLEANFILES)
 
+%.o:    %.c
+	$(COMPILE.c) $<
+
 include ../Makefile.targ
--- old/usr/src/cmd/lockstat/Makefile.com	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,63 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright (c) 2018, Joyent, Inc.
-
-PROG= lockstat
-OBJS= lockstat.o sym.o
-SRCS= $(OBJS:%.o=../%.c)
-
-include ../../Makefile.cmd
-
-LDLIBS += -lelf -lkstat -ldtrace
-CFLAGS += $(CCVERBOSE)
-CFLAGS64 += $(CCVERBOSE)
-CERRWARN += $(CNOWARN_UNINIT)
-
-SMOFF += index_overflow
-
-LINTFLAGS += -xerroff=E_SEC_SPRINTF_UNBOUNDED_COPY
-LINTFLAGS64 += -xerroff=E_SEC_SPRINTF_UNBOUNDED_COPY
-
-FILEMODE= 0555
-
-CLEANFILES += $(OBJS)
-
-.KEEP_STATE:
-
-all: $(PROG)
-
-$(PROG):	$(OBJS)
-	$(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS)
-	$(POST_PROCESS)
-
-clean:
-	-$(RM) $(CLEANFILES)
-
-lint:	lint_SRCS
-
-%.o:    ../%.c
-	$(COMPILE.c) $<
-
-include ../../Makefile.targ
--- old/usr/src/cmd/lockstat/amd64/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,34 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-CFLAGS64 += -D_ELF64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/lockstat/i386/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,31 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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) 1997 by Sun Microsystems, Inc.
-# All rights reserved.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-
-include ../Makefile.com
-
-install: all $(ROOTUSRSBINPROG32)
--- old/usr/src/cmd/lockstat/sparcv9/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,34 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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) 1997 by Sun Microsystems, Inc.
-# All rights reserved.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-CFLAGS64 += -D_ELF64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/plockstat/Makefile	Thu Apr 11 14:30:37 2024
+++ new/usr/src/cmd/plockstat/Makefile	Thu Apr 11 14:30:37 2024
@@ -23,32 +23,33 @@
 # Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 
 PROG = plockstat
+OBJS = plockstat.o
 
 include ../Makefile.cmd
+include ../Makefile.cmd.64
 
-$(64ONLY)SUBDIRS = $(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
+LDLIBS += -ldtrace -lproc
 
-all	:=	TARGET = all
-install	:=	TARGET = install
-clean	:=	TARGET = clean
-clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
+CLEANFILES += $(OBJS)
 
+ROOTLINK = $(PROG:%=$(ROOTUSRSBIN64)/%)
+
 .KEEP_STATE:
 
-all: $(SUBDIRS)
+all: $(PROG)
 
-clean clobber lint: $(SUBDIRS)
+install: all $(ROOTUSRSBINPROG) $(ROOTLINK)
 
-install: $(SUBDIRS)
-	-$(RM) $(ROOTUSRSBINPROG)
-	-$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG)
+$(ROOTLINK):
+	$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@
 
-$(SUBDIRS): FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
+$(PROG): $(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+	$(POST_PROCESS) ; $(STRIP_STABS)
 
-FRC:
+clean:
+	-$(RM) $(CLEANFILES)
+
+include ../Makefile.targ
--- old/usr/src/cmd/plockstat/Makefile.com	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,52 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-PROG = plockstat
-OBJS = plockstat.o
-SRCS = $(OBJS:%.o=../%.c)
-
-include ../../Makefile.cmd
-
-LDLIBS += -ldtrace -lproc
-
-CLEANFILES += $(OBJS)
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
-	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
-	$(POST_PROCESS) ; $(STRIP_STABS)
-
-clean:
-	-$(RM) $(CLEANFILES)
-
-lint: lint_SRCS
-
-%.o: ../%.c
-	$(COMPILE.c) $<
-
-include ../../Makefile.targ
--- old/usr/src/cmd/plockstat/amd64/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,31 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/plockstat/i386/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,30 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-
-install: all $(ROOTUSRSBINPROG32)
--- old/usr/src/cmd/plockstat/sparcv9/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,31 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-install: all $(ROOTUSRSBINPROG64)
--- old/usr/src/cmd/powertop/Makefile	Thu Apr 11 14:30:37 2024
+++ new/usr/src/cmd/powertop/Makefile	Thu Apr 11 14:30:37 2024
@@ -28,22 +28,18 @@
 
 include ../Makefile.cmd
 
-$(64ONLY)SUBDIRS	= $(MACH)
-$(BUILD64)SUBDIRS	+= $(MACH64)
+SUBDIRS	+= $(MACH64)
 
 all	:=	TARGET = all
 install	:=	TARGET = install
 clean	:=	TARGET = clean
 clobber	:=	TARGET = clobber
-lint	:=	TARGET = lint
 
 .KEEP_STATE:
 
-all clean clobber lint:	$(SUBDIRS)
+all clean clobber install:	$(SUBDIRS)
 
 install:	$(SUBDIRS)
-	-$(RM) $(ROOTPROG)
-	-$(LN) $(ISAEXEC) $(ROOTPROG)
 
 $(SUBDIRS):	FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
--- old/usr/src/cmd/powertop/amd64/Makefile	Thu Apr 11 14:30:37 2024
+++ new/usr/src/cmd/powertop/amd64/Makefile	Thu Apr 11 14:30:37 2024
@@ -41,4 +41,4 @@
 %.o: ../common/%.c
 	$(COMPILE.c) -o $@ $<
 
-install: all $(ROOTPROG64)
+install: all $(ROOTPROG)
--- old/usr/src/cmd/powertop/i386/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,43 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-
-MACH_OBJS	= pt_i386.o
-SRCS		+= $(MACH_OBJS:%.o=%.c)
-
-.KEEP_STATE:
-
-CLEANFILES	+= $(MACH_OBJS)
-
-all: $(PROG)
-
-$(PROG): $(MACH_OBJS) $(COMMON_OBJS)
-	$(LINK.c) -o $@ $(MACH_OBJS) $(COMMON_OBJS) $(LDLIBS)
-	$(POST_PROCESS)
-
-%.o: ../common/%.c
-	$(COMPILE.c) -o $@ $<
-
-install: all $(ROOTPROG32)
--- old/usr/src/cmd/powertop/i386/pt_i386.c	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,220 +0,0 @@
-/*
- * Copyright 2009, Intel Corporation
- * Copyright 2009, Sun Microsystems, Inc
- *
- * This file is part of PowerTOP
- *
- * This program file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program in a file named COPYING; if not, write to the
- * Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- *
- * Authors:
- *	Arjan van de Ven <arjan@linux.intel.com>
- *	Eric C Saxe <eric.saxe@sun.com>
- *	Aubrey Li <aubrey.li@intel.com>
- */
-
-/*
- * GPL Disclaimer
- *
- * For the avoidance of doubt, except that if any license choice other
- * than GPL or LGPL is available it will apply instead, Sun elects to
- * use only the General Public License version 2 (GPLv2) at this time
- * for any software where a choice of GPL license versions is made
- * available with the language indicating that GPLv2 or any later
- * version may be used, or where a choice of which version of the GPL
- * is applied is otherwise unspecified.
- */
-
-/*
- * DTrace scripts for observing interrupts, callouts and cyclic events
- * that cause CPU activity. Such activity prevents the processor from
- * entering lower power states and reducing power consumption.
- *
- * g_dtp_events is the default script
- */
-const char *g_dtp_events =
-"interrupt-complete"
-"/arg0 != NULL && arg3 !=0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/(caddr_t)((cyclic_t *)arg0)->cy_handler == (caddr_t)&`clock/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-"fbt::xc_common:entry"
-"{"
-"	self->xc_func = arg0;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid/"
-"{"
-"       @events_x[execname, self->xc_func] = sum(arg0);"
-"}"
-""
-"fbt::xc_common:return"
-"/self->xc_func/"
-"{"
-"	self->xc_func = 0;"
-"}";
-
-/*
- * g_dtp_events_v is enabled through the -v option, it includes cyclic events
- * in the report, allowing a complete view of system activity
- */
-const char *g_dtp_events_v =
-"interrupt-complete"
-"/arg0 != NULL && arg3 !=0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/(caddr_t)((cyclic_t *)arg0)->cy_handler != (caddr_t)&`dtrace_state_deadman &&"
-" (caddr_t)((cyclic_t *)arg0)->cy_handler != (caddr_t)&`dtrace_state_clean/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-"fbt::xc_common:entry"
-"{"
-"	self->xc_func = arg0;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid/"
-"{"
-"       @events_x[execname, self->xc_func] = sum(arg0);"
-"}"
-""
-"fbt::xc_common:return"
-"/self->xc_func/"
-"{"
-"	self->xc_func = 0;"
-"}";
-
-/*
- * This script is selected through the -c option, it takes the CPU id as
- * argument and observes activity generated by that CPU
- */
-const char *g_dtp_events_c =
-"interrupt-complete"
-"/cpu == $0 &&"
-" arg0 != NULL && arg3 != 0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/cpu == $0 &&"
-" (caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/cpu == $0 &&"
-" (caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/cpu == $0 &&"
-" (caddr_t)((cyclic_t *)arg0)->cy_handler == (caddr_t)&`clock/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-"fbt::xc_common:entry"
-"/cpu == $0/"
-"{"
-"	self->xc_func = arg0;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid &&"
-" cpu == $0/"
-"{"
-"       @events_x[execname, self->xc_func] = count();"
-"}"
-""
-"fbt::xc_common:return"
-"/cpu == $0 &&"
-" self->xc_func/"
-"{"
-"	self->xc_func = 0;"
-"}"
-""
-"fbt::xc_common:entry"
-"/cpu != $0/"
-"{"
-"	self->xc_func = arg0;"
-"	self->xc_cpu = cpu;"
-"}"
-""
-"fbt::send_dirint:entry"
-"/pid != $pid &&"
-" self->xc_func &&"
-" arg0 == $0/"
-"{"
-"       @events_xc[execname, self->xc_func, self->xc_cpu] = count();"
-"	self->xc_func = 0;"
-"	self->xc_cpu = 0;"
-"}";
-
-/*
- * i386 platform specific display messages
- */
-const char *g_msg_idle_state = "C-states (idle power)";
-const char *g_msg_freq_state = "P-states (frequencies)";
-const char *g_msg_freq_enable = "P - Enable P-states";
--- old/usr/src/cmd/powertop/sparcv9/Makefile	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,44 +0,0 @@
-#
-# 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
-# or http://www.opensolaris.org/os/licensing.
-# 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 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-MACH_OBJS	= pt_sparcv9.o
-SRCS		+= $(MACH_OBJS:%.o=%.c)
-
-.KEEP_STATE:
-
-CLEANFILES	+= $(MACH_OBJS)
-
-all: $(PROG)
-
-$(PROG): $(MACH_OBJS) $(COMMON_OBJS)
-	$(LINK.c) -o $@ $(MACH_OBJS) $(COMMON_OBJS) $(LDLIBS)
-	$(POST_PROCESS)
-
-%.o: ../common/%.c
-	$(COMPILE.c) -o $@ $<
-
-install: all $(ROOTPROG64)
--- old/usr/src/cmd/powertop/sparcv9/pt_sparcv9.c	Thu Apr 11 14:30:37 2024
+++ /dev/null	Thu Apr 11 08:00:00 2024
@@ -1,250 +0,0 @@
-/*
- * Copyright 2009, Intel Corporation
- * Copyright 2009, Sun Microsystems, Inc
- *
- * This file is part of PowerTOP
- *
- * This program file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program in a file named COPYING; if not, write to the
- * Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- *
- * Authors:
- *	Arjan van de Ven <arjan@linux.intel.com>
- *	Eric C Saxe <eric.saxe@sun.com>
- *	Aubrey Li <aubrey.li@intel.com>
- */
-
-/*
- * GPL Disclaimer
- *
- * For the avoidance of doubt, except that if any license choice other
- * than GPL or LGPL is available it will apply instead, Sun elects to
- * use only the General Public License version 2 (GPLv2) at this time
- * for any software where a choice of GPL license versions is made
- * available with the language indicating that GPLv2 or any later
- * version may be used, or where a choice of which version of the GPL
- * is applied is otherwise unspecified.
- */
-
-/*
- * DTrace scripts for observing interrupts, callouts and cyclic events
- * that cause CPU activity. Such activity prevents the processor from
- * entering lower power states and reducing power consumption.
- *
- * g_dtp_events is the default script
- */
-const char *g_dtp_events =
-"interrupt-complete"
-"/arg0 != NULL && arg3 !=0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/(caddr_t)((cyclic_t *)arg0)->cy_handler == (caddr_t)&`clock/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-"fbt::xt_all:entry,"
-"fbt::xc_all:entry"
-"{"
-"	self->xc_func = arg0;"
-"}"
-""
-"fbt::xt_one_unchecked:entry,"
-"fbt::xt_some:entry,"
-"fbt::xc_one:entry,"
-"fbt::xc_some:entry"
-"{"
-"	self->xc_func = arg1;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid/"
-"{"
-"       @events_x[execname, self->xc_func] = sum(arg0);"
-"	self->xc_func = 0;"
-"}";
-
-/*
- * g_dtp_events_v is enabled through the -v option, it includes cyclic events
- * in the report, allowing a complete view of system activity
- */
-const char *g_dtp_events_v =
-"interrupt-complete"
-"/arg0 != NULL && arg3 !=0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/(caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/(caddr_t)((cyclic_t *)arg0)->cy_handler != (caddr_t)&`dtrace_state_deadman &&"
-" (caddr_t)((cyclic_t *)arg0)->cy_handler != (caddr_t)&`dtrace_state_clean/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-"fbt::xt_all:entry,"
-"fbt::xc_all:entry"
-"{"
-"	self->xc_func = arg0;"
-"}"
-""
-"fbt::xt_one_unchecked:entry,"
-"fbt::xt_some:entry,"
-"fbt::xc_one:entry,"
-"fbt::xc_some:entry"
-"{"
-"	self->xc_func = arg1;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid/"
-"{"
-"       @events_x[execname, self->xc_func] = sum(arg0);"
-"	self->xc_func = 0;"
-"}";
-
-/*
- * This script is selected through the -c option, it takes the CPU id as
- * argument and observes activity generated by that CPU
- */
-const char *g_dtp_events_c =
-"interrupt-complete"
-"/cpu == $0 &&"
-" arg0 != NULL && arg3 != 0/"
-"{"
-"	this->devi = (struct dev_info *)arg0;"
-"	@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
-"	     this->devi->devi_instance] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/cpu == $0 &&"
-" (caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun/"
-"{"
-"       this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);"
-"       @events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();"
-"}"
-""
-"sdt:::callout-start"
-"/cpu == $0 &&"
-" (caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun/"
-"{"
-"       @events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();"
-"}"
-""
-"sdt:::cyclic-start"
-"/cpu == $0 &&"
-" (caddr_t)((cyclic_t *)arg0)->cy_handler == (caddr_t)&`clock/"
-"{"
-"	@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();"
-"}"
-""
-/*
- * xcalls to all CPUs. We're only interested in firings from other CPUs since
- * the system doesn't xcall itself
- */
-"fbt::xt_all:entry,"
-"fbt::xc_all:entry"
-"/pid != $pid &&"
-" cpu != $0/"
-"{"
-"	self->xc_func = arg0;"
-"	self->xc_cpu = cpu;"
-"	self->cpu_known = 1;"
-"}"
-""
-/*
- * xcalls to a subset of CPUs. No way of knowing if the observed CPU is in
- * it, so account it in the generic @events_x aggregation. Again, we don't
- * xcall the current CPU.
- */
-"fbt::xt_some:entry,"
-"fbt::xc_some:entry"
-"/pid != $pid &&"
-" cpu != $0/"
-"{"
-"	self->xc_func = arg1;"
-"}"
-""
-/*
- * xcalls to a specific CPU, with all the necessary information
- */
-"fbt::xt_one_unchecked:entry,"
-"fbt::xc_one:entry"
-"/arg0 == $0/"
-"{"
-"	self->xc_func = arg1;"
-"	self->xc_cpu = arg0;"
-"	self->cpu_known = 1;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid &&"
-" self->xc_func &&"
-" !self->cpu_known/"
-"{"
-"       @events_x[execname, self->xc_func] = sum(arg0);"
-"	self->xc_func = 0;"
-"}"
-""
-"sysinfo:::xcalls"
-"/pid != $pid &&"
-" self->xc_func &&"
-" self->cpu_known/"
-"{"
-"       @events_xc[execname, self->xc_func, self->xc_cpu] = sum(arg0);"
-"	self->xc_func = 0;"
-"	self->xc_cpu = 0;"
-"	self->cpu_known = 0;"
-"}";
-
-/*
- * sparcv9 platform specific display messages
- */
-const char *g_msg_idle_state = "Idle Power States";
-const char *g_msg_freq_state = "Frequency Levels";
-const char *g_msg_freq_enable = "P - Enable CPU PM";
--- old/usr/src/pkg/manifests/developer-dtrace.p5m	Thu Apr 11 14:30:37 2024
+++ new/usr/src/pkg/manifests/developer-dtrace.p5m	Thu Apr 11 14:30:37 2024
@@ -193,20 +193,15 @@
 file path=usr/lib/mdb/raw/$(ARCH64)/dof.so group=sys mode=0555
 file path=usr/lib/mdb/raw/dof.so group=sys mode=0555
 dir  path=usr/sbin
-dir  path=usr/sbin/$(ARCH32)
-file path=usr/sbin/$(ARCH32)/dtrace mode=0555
-$(i386_ONLY)file path=usr/sbin/$(ARCH32)/intrstat mode=0555
-$(i386_ONLY)file path=usr/sbin/$(ARCH32)/lockstat mode=0555
-$(i386_ONLY)file path=usr/sbin/$(ARCH32)/plockstat mode=0555
 dir  path=usr/sbin/$(ARCH64)
-file path=usr/sbin/$(ARCH64)/dtrace mode=0555
-file path=usr/sbin/$(ARCH64)/intrstat mode=0555
-file path=usr/sbin/$(ARCH64)/lockstat mode=0555
-file path=usr/sbin/$(ARCH64)/plockstat mode=0555
-hardlink path=usr/sbin/dtrace target=../../usr/lib/isaexec
-hardlink path=usr/sbin/intrstat target=../../usr/lib/isaexec
-hardlink path=usr/sbin/lockstat target=../../usr/lib/isaexec
-hardlink path=usr/sbin/plockstat target=../../usr/lib/isaexec
+link path=usr/sbin/$(ARCH64)/dtrace target=../../sbin/dtrace
+link path=usr/sbin/$(ARCH64)/intrstat target=../../sbin/intrstat
+link path=usr/sbin/$(ARCH64)/lockstat target=../../sbin/lockstat
+link path=usr/sbin/$(ARCH64)/plockstat target=../../sbin/plockstat
+file path=usr/sbin/dtrace mode=0555
+file path=usr/sbin/intrstat mode=0555
+file path=usr/sbin/lockstat mode=0555
+file path=usr/sbin/plockstat mode=0555
 dir  path=usr/share
 dir  path=usr/share/lib
 dir  path=usr/share/lib/java group=sys
--- old/usr/src/pkg/manifests/diagnostic-latencytop.p5m	Thu Apr 11 14:30:37 2024
+++ new/usr/src/pkg/manifests/diagnostic-latencytop.p5m	Thu Apr 11 14:30:37 2024
@@ -31,11 +31,7 @@
 set name=variant.arch value=$(ARCH)
 dir  path=usr group=sys
 dir  path=usr/bin
-$(i386_ONLY)dir path=usr/bin/$(ARCH32)
-$(i386_ONLY)file path=usr/bin/$(ARCH32)/latencytop mode=0555
-dir  path=usr/bin/$(ARCH64)
-file path=usr/bin/$(ARCH64)/latencytop mode=0555
-hardlink path=usr/bin/latencytop target=../../usr/lib/isaexec
+file path=usr/bin/latencytop mode=0555
 dir  path=usr/share/man/man8
 file path=usr/share/man/man8/latencytop.8
 legacy pkg=SUNWlatencytop desc="LatencyTOP tool" name="LatencyTOP tool"
--- old/usr/src/pkg/manifests/diagnostic-powertop.p5m	Thu Apr 11 14:30:37 2024
+++ new/usr/src/pkg/manifests/diagnostic-powertop.p5m	Thu Apr 11 14:30:37 2024
@@ -31,11 +31,7 @@
 set name=variant.arch value=$(ARCH)
 dir  path=usr group=sys
 dir  path=usr/bin
-$(i386_ONLY)dir path=usr/bin/$(ARCH32)
-$(i386_ONLY)file path=usr/bin/$(ARCH32)/powertop mode=0555
-dir  path=usr/bin/$(ARCH64)
-file path=usr/bin/$(ARCH64)/powertop mode=0555
-hardlink path=usr/bin/powertop target=../../usr/lib/isaexec
+file path=usr/bin/powertop mode=0555
 dir  path=usr/share/man/man8
 file path=usr/share/man/man8/powertop.8
 legacy pkg=SUNWpowertop desc="PowerTOP tool" name="PowerTOP tool"
