Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorporate PerfAnalyzer #111

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
6a3cde8
Add cloverleaf test run parser
Jul 3, 2024
24ebe6b
Add git info in clover parse
Jul 3, 2024
1580cfa
Clover run commit history parsed and visualized in jupyter
sayefsakin Jul 5, 2024
2d82182
Updted clover perf history chart
sayefsakin Jul 8, 2024
4bce3ef
Added clover profiler graph directory through DSI SQLite
sayefsakin Jul 9, 2024
4d2d6ca
added code sensing for pragma and define
sayefsakin Jul 16, 2024
b0219ad
Perf check Workflow with action files
sayefsakin Jul 19, 2024
953b0fd
Conda fix in perf_check workflow
sayefsakin Jul 19, 2024
6b97957
Conda fix for workflow
sayefsakin Jul 19, 2024
096737c
Again Conda testing
sayefsakin Jul 19, 2024
00b3601
Removed miniconda
sayefsakin Jul 19, 2024
3f48de3
Testing on mac image
sayefsakin Jul 19, 2024
cf797a0
Trying miniconda on mac
sayefsakin Jul 19, 2024
2e7e5ce
Trying setup conda v3
sayefsakin Jul 19, 2024
a3636f4
Test clover repo on action
sayefsakin Jul 19, 2024
d00e03d
Action multi checkout check
sayefsakin Jul 19, 2024
74ec7f6
Testing multi checkout workflow
sayefsakin Jul 19, 2024
d955e7a
add linux fortran
sayefsakin Jul 19, 2024
b9f0eef
Testing cloverleaf workflow
sayefsakin Jul 19, 2024
0ce020f
Testing cloverleaf
sayefsakin Jul 19, 2024
c2f6744
Install openmpi in workflow
sayefsakin Jul 19, 2024
b06baf6
Two nodes test
sayefsakin Jul 19, 2024
e1d41da
Test artifact sharing
sayefsakin Jul 19, 2024
7e163eb
Test artifact output
sayefsakin Jul 19, 2024
2043486
Test artifact duplicates
sayefsakin Jul 19, 2024
c3bad13
Test artifact content
sayefsakin Jul 19, 2024
ca82e15
Test artifact fix
sayefsakin Jul 19, 2024
96bd3b6
fly server added for perf analyzer
sayefsakin Jul 23, 2024
2902a6b
Moving to the gate
sayefsakin Jul 25, 2024
264f518
First rebasing
sayefsakin Jul 25, 2024
d34fdf4
all untrakced changes added
sayefsakin Jul 25, 2024
db0e13c
Commit table added inside perf analyzer
sayefsakin Aug 1, 2024
9030740
fly server fix
sayefsakin Aug 1, 2024
fd683ee
commit sleection table with button
sayefsakin Aug 1, 2024
5471bf6
git runner script with clover example
sayefsakin Aug 2, 2024
0bf8cd1
perf interactions
sayefsakin Aug 5, 2024
3572b22
Auto perf chart update from selected commits
sayefsakin Aug 6, 2024
b42c4a6
perf analyzer source code viewer added
sayefsakin Aug 9, 2024
3b07fbd
perf analyzer diff added
sayefsakin Aug 13, 2024
d0403b1
perf analyzer multi var diff
sayefsakin Aug 13, 2024
77bb7a6
perf analyzer metric filter added
sayefsakin Aug 13, 2024
a3b1f47
perf analyzer mpi parsing added
sayefsakin Aug 14, 2024
ed02a75
perf_analyzer moved to a new folder
sayefsakin Aug 14, 2024
83cce21
perf analyzer custom input in runner script
sayefsakin Aug 14, 2024
78c92ed
perf analyzer unused file removed
sayefsakin Aug 14, 2024
9dcd90f
perf analyzer moved to tools folder
sayefsakin Aug 14, 2024
dc41423
highligh js file removed
sayefsakin Aug 16, 2024
32e3411
readme file added for perf analyzer
sayefsakin Aug 16, 2024
2e60dda
Added readme description for perf analyzer
sayefsakin Aug 16, 2024
1b84f2a
requirement file added for perf analyzer
sayefsakin Aug 16, 2024
8ead224
updated perf analyzer jupyter file
sayefsakin Sep 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions .github/workflows/perf_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# This is a basic workflow to help you get started with Actions

name: Code Performance Analyzer

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
# push:
# branches: [ "main" ]
# pull_request:
# branches: [ "main" ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# inputs:
# hashes:
# required: true
# type: choice
# description: Make a choice
# options:
# - foo
# - bar
# - baz

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
define-matrix:
runs-on: ubuntu-latest

outputs:
hashes: ${{ steps.hashes.outputs.hashes }}

steps:
- name: Define Hashes
id: hashes
run: |
echo 'hashes=["158e23d08f73d36f71e144851451955b3ae02dff", "89cc919b28f687a25d30b44ddf547201da930c14"]' >> "$GITHUB_OUTPUT"

produce-performance-artifacts:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -el {0}
needs: define-matrix
strategy:
matrix:
hashes: ${{ fromJSON(needs.define-matrix.outputs.hashes) }}

steps:
- uses: actions/checkout@v4
with:
repository: UK-MAC/CloverLeaf_ref
ref: ${{ matrix.hashes }}

- uses: fortran-lang/[email protected]

- name: Install OpenMPI
run: sudo apt install -y openmpi-bin libopenmpi-dev

# check all the requirements and their versions
- name: Check installed dependencies
run: |
gcc --version
gfortran --version
mpirun --version
lscpu | grep -E '^Thread|^Core|^Socket|^CPU\('

- name: Compile cloverleaf
run: |
make COMPILER=GNU

- name: Run cloverleaf
run: |
mpirun -np 2 clover_leaf
mv clover.out clover_output_${{ matrix.hashes }}.out

- name: Produce Artifact
uses: actions/upload-artifact@v4
with:
name: clover_artifact_${{ matrix.hashes }}
path: clover_output_${{ matrix.hashes }}.out

consume-artifacts:
runs-on: macos-latest
needs:
- produce-performance-artifacts

steps:
- name: Download all workflow run artifacts
uses: actions/download-artifact@v4
with:
path: clover_artifact
pattern: clover_artifact_*
merge-multiple: true

- name: Check artifact files
run: |
ls -R clover_artifact
cd clover_artifact
tail -n 10 clover_output_*
# # This workflow contains a single job called "build"
# build:
# # The type of runner that the job will run on
# runs-on: macos-latest

# defaults:
# run:
# shell: bash -el {0}

# # Steps represent a sequence of tasks that will be executed as part of the job
# steps:
# # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
# - uses: actions/checkout@v4
# # with:
# # repository: UK-MAC/CloverLeaf_ref
# # ref: 0ddf495cf21cc59f84e274617522a1383e2c328c

# # - uses: actions/setup-python@v5
# # with:
# # python-version: '3.10'

# # - name: Add conda to system path
# # run: |
# # # $CONDA is an environment variable pointing to the root of the miniconda directory
# # echo $CONDA/bin >> $GITHUB_PATH



# - uses: conda-incubator/setup-miniconda@v3
# with:
# channels: defaults,conda-forge,spyder-ide
# activate-environment: cdsi
# environment-file: examples/cloverleaf/environment.yml
# auto-activate-base: false

# # - uses: s-weigand/[email protected]

# # - name: Install dependencies
# # run: |
# # cd examples/cloverleaf
# # conda env create --file environment.yml --name cdsi
# # conda activate cdsi

# # check all the requirements and their versions
# - name: Check installed dependencies
# run: |
# python3 --version
# gcc --version
# conda --version
# gfortran --version
# conda info
# conda list

# # Runs a set of commands using the runners shell
# - name: Run a multi-line script
# run: |
# echo Add other actions to build,
# echo test, and deploy your project.
# ls .
32 changes: 32 additions & 0 deletions tools/perf_analyzer/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## PerfAnalyzer

A tool to analze software performance along with code history. This is built on top of DSI SQLite plugin.

Run `fly_server.py` file. Then the dashboard can be accessed through `http://127.0.0.1:8050/`.

##### TODO: add a requirement file

Update the `runner_script.sh` to compile, copy input file, and run the program.

Update the `parse_clover_output.py` file and update `parse_clover_output_file` function to parse specific output file. Return a dictionary containing the contents of the parsed output file.

#### The features available in the dashboard

PerfAnalyzer is a dashboard based visualizer to analyze performance using git commit history and different performance metric. This has the following features

- Git History Graph
- Ordered by commit dates
- Filter Git Branch
- Select a subset of git commits
- Show Commit details like message, committer name, date, and hash.
- Performance metric line chart
- Filter by different metric
- Show details on hover
- Commit table
- Search and filter by date, hash, and message.
- Execute the `runner_script` on selected commit.
- Show difference between two commits (using git diff)
- Variable Search
- Use any regex or string to search
- Show table of found variable and file
- Show file content
64 changes: 64 additions & 0 deletions tools/perf_analyzer/auto_perf_check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#! /bin/bash

# make sure that cdsi environment is activated
if [[ $CONDA_DEFAULT_ENV != 'cdsi' ]]; then
echo "activate conda cdsi environment."
exit 0
fi
if [ -z ${SOURCE_BASE_DIRECTORY+x} ]; then
echo "SOURCE_BASE_DIRECTORY is unset"
exit 0;
else
echo "SOURCE_BASE_DIRECTORY is set to '$SOURCE_BASE_DIRECTORY'";
fi

# SOURCE_BASE_DIRECTORY="/Users/ssakin/projects/CloverLeaf/CloverLeaf_ref"
MPI_THREADS=4
export CHECK_PREV_COMMITS=15
export OMP_NUM_THREADS=4
base_directory=$(pwd)

run_and_check_commit() {
echo "current commit hash $1"

cd $SOURCE_BASE_DIRECTORY
git checkout $1
make clean
make COMPILER=GNU
echo "================================ Compile Done ================================ "

echo "============================= Running CloverLeaf ============================= "
mpirun -np $MPI_THREADS clover_leaf
cp clover.out $base_directory"/clover_output/clover_$1.out"
echo "======================= CloverLeaf Executed for has $1 ======================= "

echo "=========================== Running output parser ============================ "
cd $base_directory
python3 parse_clover_output.py --testname random_test --gitdir $SOURCE_BASE_DIRECTORY
echo "============================ Output CSV updated ============================== "
}

track_variables() {
echo "current commit hash $1"

cd $SOURCE_BASE_DIRECTORY
git checkout $1

echo "=========================== Running code sensing ============================ "
cd $base_directory
python3 code_sensing.py --testname random_test --gitdir $SOURCE_BASE_DIRECTORY
echo "============================ Output CSV updated ============================== "
}

cd $SOURCE_BASE_DIRECTORY
prev_hash=( $(git log master -n "$CHECK_PREV_COMMITS" --format=format:%h) )

for c_hash in "${prev_hash[@]}"
do
# run_and_check_commit $c_hash
track_variables $c_hash
done

cd $SOURCE_BASE_DIRECTORY
git checkout master
echo "=========================== Auto Perf Script Completed ============================ "
90 changes: 90 additions & 0 deletions tools/perf_analyzer/code_sensing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env python3

import argparse
import pickle
import sys
import glob
import re
import git

def recursive_c_directive_match(re_list, search_file_list, cur_dir):
""" The data is parsed from all of the files in the current directory """
occurance = dict()
for code_files in glob.iglob('**', root_dir=cur_dir, recursive=True):
for f_type in search_file_list:
if re.search(f_type + '$', code_files):
with open(cur_dir + "/" + code_files, 'r') as cf:
line_number = 1
for line in cf:
for each_re in re_list:
line_match = re.compile(r"\s*[#]" + each_re + r"\s+(\w+)[\t\s]+(.*)\s*(\r\n|\r|\n)").match(line)
if line_match is not None:
c_line = "#" + each_re + " " + line_match.group(1)
second_part = line_match.group(2)
if second_part is not None and len(second_part) > 0:
c_line = c_line + " " + line_match.group(2)
c_line = c_line.rstrip()
occurance[c_line] = occurance.get(c_line, dict())
# occurance[line]["first"] = line_match.group(1)
# occurance[line]["second"] = line_match.group(2)
occurance[c_line][code_files] = occurance[c_line].get(code_files, list())
occurance[c_line][code_files].append(line_number)
line_number = line_number + 1
print("matching done")
return occurance

def recursive_customized_match(re_list, search_file_list, cur_dir):
""" The data is parsed from all of the files in the current directory """
occurance = dict()
for code_files in glob.iglob('**', root_dir=cur_dir, recursive=True):
for f_type in search_file_list:
if re.search(f_type + '$', code_files):
with open(cur_dir + "/" + code_files, 'r') as cf:
line_number = 1
for line in cf:
for each_re in re_list:
line_match = re.compile(r".*(" + each_re + r").*").match(line)
if line_match is not None:
# c_line = line_match.group(1)
c_line = line.rstrip()
occurance[c_line] = occurance.get(c_line, dict())
# occurance[line]["first"] = line_match.group(1)
# occurance[line]["second"] = line_match.group(2)
occurance[c_line][code_files] = occurance[c_line].get(code_files, list())
occurance[c_line][code_files].append(line_number)
line_number = line_number + 1
print("matching done")
return occurance

def main():
""" A testname argument is required """
parser = argparse.ArgumentParser()
parser.add_argument('--testname', help='the test name')
parser.add_argument('--gitdir', help='the git directory')
args = parser.parse_args()
# testname = "temp_test"
testname = args.testname
git_repo = args.gitdir
if testname is None or git_repo is None:
parser.print_help()
sys.exit(0)

git_hash = git.Repo(git_repo).head.object.hexsha
re_list = ["pragma", "define"]
search_file_list = [r"\.c", r"\.cc"]
# occ = recursive_c_directive_match(re_list, search_file_list, git_repo)

# with open(git_hash + '.pickle', 'wb') as handle:
# pickle.dump(occ, handle, protocol=pickle.HIGHEST_PROTOCOL)

# re_list = [r"OMP PARALLEL", r"vol=0\.0", r"\w+=\d+\.\d+"]
search_file_list = [r"\.c", r"\.cc", r"\.f90"]
recursive_customized_match(re_list, search_file_list, git_repo)

# with open(git_hash + '.pickle', 'rb') as handle:
# b = pickle.load(handle)
# print(b)

if __name__ == '__main__':
main()

Loading