private void execute(int numIters) throws Exception {
        File graphFile = new File(baseFilename);

        /** Use local drunkard mob companion. You can also pass a remote reference
         *  by using Naming.lookup("rmi://my-companion")
         */
        final RemoteDrunkardCompanion companion;
        if (companionUrl.equals("local")) {
            companion = new IntDrunkardCompanion(4, Runtime.getRuntime().maxMemory() / 3);
        }  else {
            companion = (RemoteDrunkardCompanion) Naming.lookup(companionUrl);
        }

        /* Step 1: Compute random walks */
        /* Configure walk sources. Note, GraphChi's internal ids are used. */

        DrunkardJob drunkardJob = this.drunkardMobEngine.addJob("twitterwtf",
                EdgeDirection.OUT_EDGES, this, companion);

        drunkardJob.configureSourceRangeInternalIds(firstSource, numSources, numWalksPerSource);
        drunkardMobEngine.run(numIters);


        // Empty from memory so can use cache in the SALSA
        this.drunkardMobEngine = null;
        drunkardJob = null;

        /* Step 2: SALSA */
        final int circleOfTrustSize = 200;

        final long startTime = System.currentTimeMillis();

        final AtomicInteger numRecs = new AtomicInteger();
        final AtomicInteger pending = new AtomicInteger();

        // FIXME: hardcoded
        ExecutorService executor = Executors.newFixedThreadPool(4);

        logger.info("Started 4 threads");


        // Each thread need to have a local query service so the file descriptors don't clash.
        final ThreadLocal<VertexQuery> queryService = new ThreadLocal<VertexQuery>() {
            @Override
            protected VertexQuery initialValue() {
                try {
                    return new VertexQuery(baseFilename, numShards);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    throw new RuntimeException(ioe);
                }
            }


        };

        //
 
        long t = System.currentTimeMillis();

        for(int vertexId=firstSource; vertexId < firstSource+numSources; vertexId++) {
            final int _vertexId = vertexId;
            pending.incrementAndGet();
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        CircleOfTrustSalsa csalsa = new CircleOfTrustSalsa(queryService.get(), salsaCacheSize);
                        computeRecs(companion, circleOfTrustSize, startTime, csalsa, numRecs, _vertexId);

                    } catch (Exception err) {
                        err.printStackTrace();
                    }
                    pending.decrementAndGet();
                }
            });
        }

        while(pending.get() > 0) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
            System.out.println("Pending WTF queries: " + pending.get());
        }
 
        System.out.println("WTF-recs," + (System.currentTimeMillis() - t));

    }