Making the change length(nzrange(P.A,u)) for du and dv
fixes the issue. (Of course.) Is there any way to disable non-const global variables within a function? (Or warn when they are used?) David On Saturday, April 4, 2015 at 4:08:38 AM UTC-4, Tony Kelman wrote: > > This is an excellent use case for the @code_warntype macro. You can > quickly see that rowval, n, x, r, pushval, nzi, v, rvold, rvnew, and > several temporary variables are ending up as Any or underspecified Array > type. A few things you can do to help: > > - give the A field of the PageRankProblem type more specific type > parameters, A::SparseMatrixCSC{Float64, Int64} so the type of rowval can be > inferred > - change n = size(A,1) to n = size(P.A, 1); otherwise you're referring to > the global variable A > - use the colptr version instead of length(nzrange(A,u)) for du, and > similarly for dv - for some reason the length of the output of nzrange > can't be inferred as an Int, this might be a bug worth reporting > > Those 3 changes get it to within a factor of 2 of C++ on my machine. > > -Tony > > > On Friday, April 3, 2015 at 6:22:43 PM UTC-7, David Gleich wrote: >> >> I'm trying to figure out why the following algorithm is so slow in Julia. >> >> $ julia pprpush_perf4.jl >> elapsed time: 0.754419672 seconds # first run, no compiled >> elapsed time: 0.627998826 seconds # second run, compiled >> elapsed time: 0.616043857 seconds (292 MB allocated, 1.52% gc time in 14 >> pauses with 0 full sweep) # third run, with @time >> True = 0.026124014066724 # make sure the result is correct >> x[0] = 0.026124014066724 >> >> $ rm a.out; g++ -O2 pprpush_perf.cpp; ./a.out >> >> Elapsed 0.010623 seconds. # second run of the algorithm in C++ >> >> True = 0.026124014066724 # make sure the result is correct >> x[0] = 0.026124014066724 >> y[0] = 0.026124014066724 >> >> So Julia is ~60x slower than the equivalent C++ code. >> >> I've attached the code for both procedures for the complete code, but >> here's the key algorithm. This is the PageRank "push" procedure due to >> Andersen, Chung, and Lang (FOCS 2006). >> >> Basically, it does random access to the rows or columns of a sparse >> matrix (whichever is faster, because it assumes the sparse matrix is the >> adjacency matrix of an undirected graph). >> >> I tried a few different things to speed it up in Julia, but nothing >> seemed to work. Any thoughts? >> >> function ppr_push(P::PageRankProblem, eps::Float64) >> # extract the sparse data structure >> #colptr = P.A.colptr >> rowval = rowvals(P.A) # P.A is just a julia sparse matrix >> n = size(A,1) >> >> # create the initial solution and residual >> x = zeros(n,1) >> r = zeros(n,1) >> >> r[P.seed] = 1. >> >> q = [P.seed] >> >> pushcount = 0 >> pushvol = 0 >> maxpush = 1./(eps*(1.-P.alpha)) >> >> while length(q) > 0 && pushcount <= maxpush >> pushcount += 1 >> u = shift!(q) # I've tried DataStructures Queue here, but no >> change >> #du = convert(Float64,colptr[u+1]-colptr[u]) # get the degree >> #du = Float64(colptr[u+1]-colptr[u]) >> du = Float64(length(nzrange(A,u))) >> pushval = r[u] - 0.5*eps*du >> x[u] += (1-P.alpha)*pushval >> r[u] = 0.5*eps*du >> >> #@printf("pushing on %4i with resid %.9f rho=%f\n", u, pushval, >> rho) >> >> pushval = pushval*P.alpha/du >> >> #for nzi in colptr[u]:(colptr[u+1] - 1) >> for nzi in nzrange(P.A,u) >> pushvol += 1 >> v = rowval[nzi] >> #dv = convert(Float64,colptr[v+1]-colptr[v]) # degree of v >> dv = Float64(length(nzrange(A,v))) >> rvold = r[v] >> rvnew = rvold + pushval >> r[v] = rvnew >> if rvnew > eps*dv && rvold <= eps*dv >> push!(q,v) >> end >> end >> end >> >> return x, r, pushcount, pushvol >> >> end >> >> Thanks, >> David Gleich >> >