Skip to content

Commit

Permalink
Initial public commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Chadderz121 committed Nov 24, 2023
0 parents commit d63ff5b
Show file tree
Hide file tree
Showing 35 changed files with 6,486 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build*/
install_dir*/
DynamoRIO-*/
optiwise_result/
tests/bin*/
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Yuxin Guo, Alex W. Chadwick

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
116 changes: 116 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
###############################################################################
# Variables (Can be overriden on command line)

# Note: to cross-compile you need to specify the standard tools (CC, CXX, etc)
# on the command line e.g. 'make CXX=aarch64-linux-gnu-g++ ...'

ARCH ?= $(shell $(CXX) -dumpmachine | sed -e 's/^\([^-]*\).*/\1/')
BUILD_DIR ?= build.$(ARCH)
INSTALL_DIR ?= install_dir.$(ARCH)
DYNAMORIO_VERSION ?= 10.0.0

ifeq ($(ARCH),aarch64)
DYNAMORIO_PREFIX ?= AArch64-Linux
else ifeq ($(ARCH),x86_64)
DYNAMORIO_PREFIX ?= Linux
else ifndef DYNAMORIO_URL
$(error Machine '$(ARCH)' not recognised. Expected 'aarch64' or 'x86_64')
else ifndef DYNAMORIO_DIRNAME
$(error Machine '$(ARCH)' not recognised. Expected 'aarch64' or 'x86_64')
endif

# Name for the directory (not a path)
DYNAMORIO_DIRNAME ?= DynamoRIO-$(DYNAMORIO_PREFIX)-$(DYNAMORIO_VERSION)
DYNAMORIO_URL ?= https://github.com/DynamoRIO/dynamorio/releases/download/release_$(DYNAMORIO_VERSION)/$(DYNAMORIO_DIRNAME).tar.gz

###############################################################################
# Meta rules

SRC_SCRIPTS := scripts/bin/optiwise $(wildcard scripts/share/optiwise/bin/*)
INSTALL_SCRIPTS := $(patsubst scripts%,$(INSTALL_DIR)%,$(SRC_SCRIPTS))
INSTALL_LIBS := $(addprefix $(INSTALL_DIR)/share/optiwise/lib/,liboptiwise.so libexit0.so)

all: $(INSTALL_SCRIPTS) $(INSTALL_LIBS) $(INSTALL_DIR)/share/optiwise/dynamorio \
$(INSTALL_DIR)/share/optiwise/bin/analyzer \
$(INSTALL_DIR)/share/optiwise/bin/analyzer-serial
.PHONY: all

clean:
rm -rf $(INSTALL_DIR)/bin/optiwise $(INSTALL_DIR)/share/optiwise $(BUILD_DIR)
.PHONY: clean

install:
$(MAKE) all INSTALL_DIR=/usr
uninstall:
$(MAKE) clean INSTALL_DIR=/usr
.PHONY: install uninstall

###############################################################################
# DynamoRIO download & build & copy

# Rule to download DynamoRIO
$(DYNAMORIO_DIRNAME)/bin64/drrun:
wget -qO- $(DYNAMORIO_URL) | tar xvz

# Rule to minify DynamoRIO
$(INSTALL_DIR)/share/optiwise/$(DYNAMORIO_DIRNAME): scripts/minify_dynamorio.sh | $(DYNAMORIO_DIRNAME)/bin64/drrun $(INSTALL_DIR)/share/optiwise
$< $(DYNAMORIO_DIRNAME) $@

# Rule to make DynamoRIO symlink
$(INSTALL_DIR)/share/optiwise/dynamorio: | $(INSTALL_DIR)/share/optiwise/$(DYNAMORIO_DIRNAME) $(INSTALL_DIR)/share/optiwise
ln -s -f -T $(DYNAMORIO_DIRNAME) $@

###############################################################################
# Scripts build & copy

# Rules to copy scripts directly
$(INSTALL_DIR)/bin/%: scripts/bin/% | $(INSTALL_DIR)/bin
if version=$$(git describe --dirty); then \
sed -e "s/^version=.*/version=$$version/" $< > $@; \
else \
cp $< $@; \
fi
$(INSTALL_DIR)/share/optiwise/bin/%: scripts/share/optiwise/bin/% | $(INSTALL_DIR)/share/optiwise/bin
cp $< $@

###############################################################################
# DynamoRIO client build & copy

$(BUILD_DIR)/dyclient/Makefile: src/dyclient/CMakeLists.txt | $(BUILD_DIR)/dyclient $(DYNAMORIO_DIRNAME)/bin64/drrun
cd $(BUILD_DIR)/dyclient; cmake -DDynamoRIO_DIR=../../$(DYNAMORIO_DIRNAME)/cmake ../../src/dyclient
$(BUILD_DIR)/dyclient/bin/liboptiwise.so $(BUILD_DIR)/dyclient/bin/libexit0.so: $(BUILD_DIR)/dyclient/Makefile src/dyclient/*.cpp
$(MAKE) -C $(BUILD_DIR)/dyclient
$(INSTALL_DIR)/share/optiwise/lib/%.so: $(BUILD_DIR)/dyclient/bin/%.so | $(INSTALL_DIR)/share/optiwise/lib
cp $< $@

###############################################################################
# analyzer build & copy
$(BUILD_DIR)/analyzer: src/analyzer/Makefile $(wildcard src/analyzer/*) | $(BUILD_DIR)
$(MAKE) -C src/analyzer EXE=$$(realpath $@)
$(BUILD_DIR)/analyzer-serial: src/analyzer/Makefile $(wildcard src/analyzer/*) | $(BUILD_DIR)
$(MAKE) -C src/analyzer EXE=$$(realpath $@) SERIAL=1
$(INSTALL_DIR)/share/optiwise/bin/analyzer: $(BUILD_DIR)/analyzer | $(INSTALL_DIR)/share/optiwise/bin
cp $< $@
$(INSTALL_DIR)/share/optiwise/bin/analyzer-serial: $(BUILD_DIR)/analyzer-serial | $(INSTALL_DIR)/share/optiwise/bin
cp $< $@

###############################################################################
# Directory structure rules

# Rules to make target directory structure
$(BUILD_DIR):
[ -d "$@" ] || mkdir "$@"
$(BUILD_DIR)/dyclient: | $(BUILD_DIR)
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR):
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR)/bin: | $(INSTALL_DIR)
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR)/share: | $(INSTALL_DIR)
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR)/share/optiwise: | $(INSTALL_DIR)/share
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR)/share/optiwise/bin: | $(INSTALL_DIR)/share/optiwise
[ -d "$@" ] || mkdir "$@"
$(INSTALL_DIR)/share/optiwise/lib: | $(INSTALL_DIR)/share/optiwise
[ -d "$@" ] || mkdir "$@"
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# OptiWISE
OptiWISE is a profiling tool providing granular CPI and IPC analysis of
programs. It combines the information from two runs of the program: one using
low-overhead sampling, and the other using high-overhead dynamic
instrumentation. The results of these two runs are then combined to give per
instruction, per basic block, per loop, and per function overheads.

# Building

Running `make` will generate `install\_dir.ARCH` where `ARCH` is the ISA for
example `x86_64`. The `optiwise` command is available in the `bin`
subdirectory of this. Consequently running:

```sh
export PATH=$(pwd)/install_dir.x86_64/bin:$PATH
```

Will temporarily add `optiwise` to your command line.

Running `sudo make install` will install to `/usr/bin/optiwise` and
`/usr/share/optiwise` instead, meaning `optiwise` will be available on the
command line by default.

# Usage

A simple example would be:

```sh
optiwise run -- /usr/bin/echo hello
```

would cause OptiWISE to profile the program `/usr/bin/echo` with the argument
`hello`. Note that this will run that program twice. Results will be placed in
the `optiwise_result/analyze/run` directory.

For more fine grain control, see `optiwise help`. The subcommands of OptiWISE
will allow you to configure the individual jobs in OptiWISE and configure
various additional options.
128 changes: 128 additions & 0 deletions scripts/bin/optiwise
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/bin/sh -u
#
# This is the root 'optiwise' command, that will be invoked with subcommands
# e.g. 'optiwise sample <arguments>'. This script invokes an appopriate
# subcommand script e.g. 'optiwise-sample <arguments>' which handles the
# specific verb used.

script_name=$(basename $0)
# This is automatically replaced with the git tag version in installations.
# Hence, this default version will only display if that fails.
version=v0.9.0-unamed-development-version

# Directory of this script.
bin_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
share_bin_dir=$(realpath "$bin_dir/../share/optiwise/bin")
result_dir=optiwise_result

if [ $# -lt 1 ]; then
# We ran with no arguments.
do_cmd=help
else
# Parse arguments
while :; do
case "${1-}" in
-h|--help)
do_cmd=help
flag_help=$1
;;
-v|--version) do_cmd=version;;
-d|--result-dir)
shift
result_dir=$1
;;
--result-dir=*)
result_dir=${1#--*=}
;;
-?*)
cat >&2 <<EOF
Unrecognized option '$1'
Did you put an argument before the command?
Try '$script_name help'
EOF
exit 1
;;
*) break;;
esac

shift
done
fi

# Try to invoke the actual command.
case "${1-}" in
help)
if [ "${2-}" ]; then
if [ -f "$share_bin_dir/optiwise-$2" ]; then
exec "$share_bin_dir/optiwise-$2" --help
else
cat >&2 <<EOF
Unrecognized command '$2'
Did you put an argument before the command?
Try '$script_name help'
EOF
exit 1
fi
fi
do_cmd=help
;;
version) do_cmd=version;;
"") if ! [ "${do_cmd-}" ]; then do_cmd=help; fi;;
*)
if [ -f "$share_bin_dir/optiwise-$1" ]; then
if [ "${flag_help-}" ]; then
exec "$share_bin_dir/optiwise-$1" --help
else
program="$1"
shift
exec "$share_bin_dir/optiwise-$program" "--result-dir=$result_dir" "$@"
fi
else
cat >&2 <<EOF
Unrecognized command '$1'
Did you put an argument before the command?
Try '$script_name help'
EOF
exit 1
fi
;;
esac

# If we get here, it's a command that this script should handle natively.
case "$do_cmd" in
version) printf "$script_name version $version\n" ;;
help|*)
cat <<EOF
Usage: $script_name [<options>] <command> [<arguments>]
Profiling tool combining execution counts and sampling.
Supported commands:
help Displays help on a command.
run All-in-one profiling command. Roughly equivalent to 'check' then
'sample' then 'disassemble' then 'count' then 'analyze'.
A good starting point for beginners.
check Checks for many possible problems with profiling.
version Displays version number.
sample Sample a program's execution.
disassemble Disassemble a program and all dependencies.
count Obtain execution count for program's execution.
analyze Analyze and combine output of 'sample', 'disassemble', and
'count'.
By default results and temporary files will go in the 'optiwise_result'
directory within the working directory. The output of each subcommand generally
goes in a subfolder of the same name (e.g. 'optiwise_result/sample'). All
commands which generate or take results have a '--name' option which allows
naming of the output within this subfolder, and thus preserving multiple runs,
or parallelising the process.
Options:
-h, --help Display this help.
-v, --version Display version and exit.
-d, --result-dir=<directory>
Override the result directory.
EOF
;;
esac

exit 0
75 changes: 75 additions & 0 deletions scripts/minify_dynamorio.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/sh -e

# Creates a minimised install of dynamorio (no duplicated files).

src="$1"
dst=$(realpath "$2")

if [ $# -ne 2 ]; then
echo "Usage: ./minify_dyanmorio src dst" 1>&2
exit 1
fi

if [ ! -d "$src" ]; then
echo "Directory not found: $src" 1>&2
exit 1
fi
if [ ! -d "$dst" ]; then
mkdir "$dst"
fi
if [ -n "$(ls -A "$dst")" ]; then
echo "Destination directory not empty: $dst" 1>&2
exit 1
fi

subdirs="lib* bin* ext/lib* ext/bin*"
cd "$src"

# Create all subdirectories of lib{32,64}; bin{32,64} and the ext versions of
# these in the destination.
find $subdirs -type d \
| sort | sed -ne "s^mkdir -p $dst/p" \
| sh -xe 2>&1

# Copy one copy of each file in those directories (identified uniquely by the
# sha1sum).
find $subdirs -type f ! -name '*.debug' -exec sha1sum '{}' + \
| sort | uniq -w 40 | sed -ne "s[0-9a-f]\\{40\\} \(.*\)cp \1 $dst/\1p" \
| sh -xe 2>&1

# Determine the 'strip' program
strip=$(${CXX:-c++} -dumpmachine)-strip
if ! which "$strip" > /dev/null 2> /dev/null; then
strip=strip
fi

# Strip any executable files.
find "$dst" -type f -name '*.a' -perm /u+w -exec "$strip" '{}' + -printf "+ $strip"' %P\n'
find "$dst" -type f -name '*.so' -perm /u+w -exec "$strip" '{}' + -printf "+ $strip"' %P\n'
find "$dst" -type f -perm /u+w -perm /u+x -exec "$strip" '{}' + -printf "+ $strip"' %P\n'

# Copy all symbolic links.
find $subdirs -type l ! -name '*.debug' \
| sed -ne "s\(.*\)cp \1 $dst/\1p" \
| sh -xe 2>&1

# For each non-unique file, create a symlink
find $subdirs -type f ! -name '*.debug' -exec sha1sum '{}' + \
| sort | uniq -D -w 40 \
| awk '
BEGIN { FIELDWIDTHS="40 2:*" }
{
if (hash == $1) {
print "ln -s -T $(realpath --relative-to=$(dirname \"'"$dst"'/"$2"\") \"'"$dst"'/"file"\") '"$dst"'/"$2
}
else {
hash=$1
file=$2
}
}' \
| sh -xe 2>&1

cat > "$dst"/README <<EOF
This is a stripped version of $(basename "$src"). It has had unnecessary files
and debugging information removed to save space.
EOF
Loading

0 comments on commit d63ff5b

Please sign in to comment.