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

RFC: added performance tests for sparse getindex + a README file #7177

Merged
merged 1 commit into from
Jun 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions test/perf/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
JULIAHOME = $(abspath ../..)
include ../../Make.inc

all: micro kernel cat shootout blas lapack sort spell
all: micro kernel cat shootout blas lapack sort spell sparse

micro kernel cat shootout blas lapack sort spell:
micro kernel cat shootout blas lapack sort spell sparse:
@$(MAKE) $(QUIET_MAKE) -C shootout
ifneq ($(OS),WINNT)
@$(call spawn,$(JULIA_EXECUTABLE)) $@/perf.jl | perl -nle '@_=split/,/; printf "%-18s %8.3f %8.3f %8.3f %8.3f\n", $$_[1], $$_[2], $$_[3], $$_[4], $$_[5]'
Expand All @@ -21,6 +21,7 @@ codespeed:
# @$(call spawn,$(JULIA_EXECUTABLE)) lapack/perf.jl codespeed
# @$(call spawn,$(JULIA_EXECUTABLE)) sort/perf.jl codespeed
@$(call spawn,$(JULIA_EXECUTABLE)) spell/perf.jl codespeed
@$(call spawn,$(JULIA_EXECUTABLE)) sparse/perf.jl codespeed
@$(call spawn,$(JULIA_EXECUTABLE)) report.jl


Expand All @@ -29,4 +30,4 @@ clean:
$(MAKE) -C micro $@
$(MAKE) -C shootout $@

.PHONY: micro kernel cat shootout blas lapack sort spell clean
.PHONY: micro kernel cat shootout blas lapack sort spell sparse clean
73 changes: 73 additions & 0 deletions test/perf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
Julia performance monitoring
============================

This directory contains tests and related utilities to monitor Julia's
performance over time. The results are presented on
[http://speed.julialang.org/](http://speed.julialang.org/).

Running the performance tests
-----------------------------

In `test/perf` run `make`. It will run the `perf.jl` script in all
the sub-directories and display the test name with the minimum,
maximum, mean and standard deviation of the wall-time of five repeated
test runs in micro seconds.

Calling `make codespeed` is for generating the results displayed on
[http://speed.julialang.org/](http://speed.julialang.org/), probably
not what you want.

There is also a `perfcomp.jl` script but it may not be working with
the rest at the moment.

Adding tests
------------
First decide whether the new tests should go into one of the existing
suites:
- `micro`: A set of micro-benchmarks commonly used to compare
programming languages; these results are shown on
[http://julialang.org/](http://julialang.org/).
- `blas`, `lapack`: Performance tests for linear algebra tasks from
low-level operations such as matrix multiplies to higher-level
operations like eigenvalue problems.
- `cat`: Performance tests for concatenation of vectors and matrices.
- `kernel`: Performance tests used to track real-world code examples
that previously ran slowly.
- `shootout` Tracks the performance of tests taken from the
[Debian shootout](http://shootout.alioth.debian.org/) performance
tests.
- `sort`: Performance tests of sorting algorithms.
- `spell` Performance tests of
[Peter Norvig's spelling corrector](http://norvig.com/spell-correct.html).
- `sparse`: Performance tests of sparse matrix operations.

Otherwise add a subdirectory containing the file `perf.jl` and
update the `Makefile` as well.

In `perf.jl`, `include("../perfutil.jl")` and then run the
performance test functions with the `@timeit` macro. For example:
```julia
@timeit(spelltest(tests1), "spell", "Peter Norvig's spell corrector")
```
with arguments: test function call, name of the test, description,
and, optionally, a group (only used for codespeed). `@timeit` will do
a warm-up and then 5 timings. Alternatively `@timeit1` does one
warm-up and one test run.

If possible aim for the tests to take about 10-100 microseconds.

Using the framework for your own tests
--------------------------------------

Just include `perfutil.jl`, use `@timeit` on the functions to be
benchmarked. Alternatively have a look at the
[Benchmark package](https://github.com/johnmyleswhite/Benchmark.jl).


Package dependencies
--------------------
- HTTPClient
- JSON
- DataStructures
- SortingAlgorithms

201 changes: 201 additions & 0 deletions test/perf/sparse/perf.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
## Sparse matrix performance
include("../perfutil.jl")

## create some sparse matrices (need to be square):
seed = 1
srand(seed)

small = 10^3
med = 10^4
large = 10^5
huge = 10^6
# # 1 entry per line
# ss = {}
# push!(ss, sprand(small, small, 1e-3))
# #push!(ss, sprand(med, med, 1e-4))
# push!(ss, sprand(large, large, 1e-5))

# 10 entries per line
ts = {}
push!(ts, sprand(small, small, 1e-2))
#push!(ts, sprand(med, med, 1e-3))
push!(ts, sprand(large, large, 1e-4))

# 100 entries per line
us = {}
push!(us, sprand(small, small, 1e-1))
#push!(us, sprand(med, med, 1e-2))
push!(us, sprand(large, large, 1e-3))
#push!(us, sprand(huge, huge, 1e-4))

# # 1000 entries per line
# vs = {}
# push!(vs, sprand(small, small, 1.0))
# #push!(vs, sprand(med, med, 1e-1))
# push!(vs, sprand(large, large, 1e-2))
# #push!(vs, sprand(huge, huge, 1e-3))

## using uint32 (works up to 10^9)
uus = {}
for u in us
push!(uus, SparseMatrixCSC(u.m, u.n, uint32(u.colptr), uint32(u.rowval), u.nzval))
end

## getindex
rep = 20
reps = rep^2
function integer_indexing(A)
# index with two random integers
nI, nJ = size(A)
rI = 1:nI
rJ = 1:nJ
tmp = zero(eltype(A))
for i in rand(rI, reps)
for j in rand(rJ, rep)
tmp += A[i,j]
end
end
tmp
end

function row_indexing(A, rowinds)
# index rows with rowinds and columns with a random integer
nI, nJ = size(A)
rI = 1:nI
rJ = 1:nJ
tmp = zero(eltype(A))
for j in rand(rJ, reps)
tmp += sum(A[rowinds,j])
end
tmp
end

function col_indexing(A, colinds)
# index rows with a random integer and columns with colinds
nI, nJ = size(A)
rI = 1:nI
rJ = 1:nJ
tmp = zero(eltype(A))
for i in rand(rI, div(reps,10) )
tmp += sum(A[i,colinds])
end
tmp
end

function row_col_indexing(A, rowinds, colinds)
# index rows with rowinds and columns with colinds
# we need:
(maximum(rowinds)+rep < size(A,1) && maximum(colinds)+rep < size(A, 2)) || error("bad rowinds or colinds")
nI, nJ = size(A)
rI = 1:nI
rJ = 1:nJ
for i in 1:10
for j in 1:10
tmp2 = A[rowinds.+i, colinds.+j]
end
end
end

function one_arg_indexing(A, lininds)
# This is for 1d-indexing and indexing with one array of logicals.
# Both return a nx1 sparse matrix.
tmp = zero(eltype(A))
if isa(eltype(A), Bool)
tmp = sum(A[lininds])
else
for i in 1:rep
tmp += sum(A[lininds])
end
end
tmp
end

# test performance with matrices in us, uus and ts for
# - integer indexing
# - range indexing
# - ordered array indexing
# - disordered array indexing
# - 1d indexing with integers and booleans

# setup:
# - indices
intinds = nothing
logicalinds = nothing # needs to be generated for a specific matrix size.
rangeinds = 121:237
orderedinds = [rangeinds]
disorderedinds = orderedinds[randperm(length(orderedinds))]

inds = [(intinds, "integers"), (logicalinds, "logical array"), (rangeinds, "a range"),
(orderedinds, "a ordered array"), (disorderedinds, "a disordered array")]

# - matrix sizes
sizes = [(1, "small", "Small sparse matrix"), (2, "medium", "Medium sparse matrix")]

# - matrix types
mattyp = [(ts, "10 entries/column"), (us, "100 entries/column")]
# change to following line, after regression is fixed: https://github.com/JuliaLang/julia/pull/7162#issuecomment-45400517
#mattyp = [(ts, "10 entries/column"), (us, "100 entries/column"), (uus, "100 entries/column uint32")]

# - functions
funs = [(integer_indexing, 1, "indexing"), (one_arg_indexing, 1, "1d indexing"),
(row_indexing, 2, "indexing rows"), (col_indexing, 2, "indexing rows"),
(row_col_indexing, 3, "indexing rows & columns")]

# performance tests:
counters = [1,1] # for small and medium matrix
# integer indexing
for (sz,s1,s2) in sizes # size of the matrix
for (mt, ms) in mattyp # type of the matrix
m = mt[sz]
c = counters[sz]
@timeit integer_indexing(m) "sparse_getindex_$s1$c" "$s2 with $ms, indexing with integers"
counters[sz] += 1
end
end

# range & array indexing
for (sz,s1,s2) in sizes # size of the matrix
for (mt, ms) in mattyp # type of the matrix
m = mt[sz]
for (fun, nargs, funstr) in funs[3:5] # indexing test function
for (ind,indstr) in inds[3:5] # type of indices
c = counters[sz]
if indstr=="logical array"
# make a logical array of the right size
ind = sprandbool(size(m,1)..., 1e-5)
end
if nargs==2
@timeit fun(m, ind) "sparse_getindex_$s1$c" "Sparse matrix with $ms, $funstr with $indstr"
elseif nargs==3
@timeit fun(m, ind, ind) "sparse_getindex_$s1$c" "Sparse matrix with $ms, $funstr with $indstr"
else
error("Something is amiss here.")
end
counters[sz] += 1
end
end
end
end

# linear indexing
for (sz,s1,s2) in sizes # size of the matrix
for (mt, ms) in mattyp # type of the matrix
m = mt[sz]
for (ind,indstr) in inds[2:5] # type of indices
if indstr=="logical array"
if sz==2
continue # logical indexing with medium size sparse matrix takes too long
end
# make a logical array of the right size
ind = sprandbool(size(m)..., 1e-5)
c = counters[sz]
@timeit1 one_arg_indexing(m, ind) "sparse_getindex_$s1$c" "$s2 with $ms, linear indexing with $indstr"
counters[sz] += 1
else
c = counters[sz]
@timeit one_arg_indexing(m, ind) "sparse_getindex_$s1$c" "$s2 with $ms, linear indexing with $indstr"
counters[sz] += 1
end
end
end
end