<?xml-model href='http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng' schematypens='http://relaxng.org/ns/structure/1.0'?><TEI xmlns="http://www.tei-c.org/ns/1.0">
	<teiHeader>
		<fileDesc>
			<titleStmt><title level='a'>Accelerating Graph Sampling for Graph Machine Learning using GPUs</title></titleStmt>
			<publicationStmt>
				<publisher></publisher>
				<date>04/26/2021</date>
			</publicationStmt>
			<sourceDesc>
				<bibl> 
					<idno type="par_id">10220881</idno>
					<idno type="doi">10.1145/3447786.3456244</idno>
					<title level='j'>European Conference on Computer Systems (EuroSys)</title>
<idno></idno>
<biblScope unit="volume"></biblScope>
<biblScope unit="issue"></biblScope>					

					<author>Abhinav Jangda</author><author>Sandeep Polisetty</author><author>Arjun Guha</author><author>Marco Serafini</author>
				</bibl>
			</sourceDesc>
		</fileDesc>
		<profileDesc>
			<abstract><ab><![CDATA[Representation learning algorithms automatically learn the features of data.Several representation learning algorithms for graph data, such as DeepWalk,node2vec, and GraphSAGE, sample the graph to produce mini-batches that aresuitable for training a DNN. However, sampling time can be a significantfraction of training time, and existing systems do not efficiently parallelizesampling.    Sampling is an "embarrassingly parallel" problem and may appear to lenditself to GPU acceleration, but the irregularity of graphs makes it hard to useGPU resources effectively. This paper presents NextDoor, a system designed toeffectively perform graph sampling on GPUs. NextDoor employs a new approach tograph sampling that we call transit-parallelism, which allows load balancingand caching of edges. NextDoor provides end-users with a high-level abstractionfor writing a variety of graph sampling algorithms. We implement several graphsampling applications, and show that NextDoor runs them orders of magnitudefaster than existing systems.]]></ab></abstract>
		</profileDesc>
	</teiHeader>
	<text><body xmlns="http://www.tei-c.org/ns/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink">
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="1">Introduction</head><p>Representation learning is a fundamental problem in machine learning. Its goal is to learn features of data instead of handengineering them. Representation learning on graph data involves mapping vertices (or subgraphs) to a &#119889;-dimensional vector known as an embedding. The embedding is then used as a feature vector for other downstream graph machine learning tasks. Graph representation learning is a fundamental step in domains such as social network analysis, recommendations, epidemiology, and more.</p><p>Several algorithms for graph representation learning first sample the input graph to obtain mini-batches and then train a deep neural network (DNN) or a graph neural network (GNN) based on the samples. Moreover, different learning algorithms require different sampling mechanisms. For example, DeepWalk <ref type="bibr">[28]</ref> and node2vec <ref type="bibr">[12]</ref> use variants of random walks. In contrast, GraphSAGE <ref type="bibr">[13]</ref>, which Pinterest uses for recommendation <ref type="bibr">[39]</ref>, samples the &#119896;-hop neighborhood of a vertex and uses their attributes to learn an embedding for each vertex.</p><p>Although several systems effectively leverage GPUs for the DNN training step, the same is not true for the sampling step. Graph sampling takes a significant portion of total training time in real-world applications. Table <ref type="table">1</ref> shows the impact of graph sampling in existing GNNs. In each epoch, a GNN first samples the input graph to obtain mini-batches and then trains the DNN. Graph sampling is an irregular computation that is typically performed using the CPU, whereas training is performed on the GPU. In our experiments, we found that graph sampling can take up to 62% of an epoch's time. <ref type="foot">1</ref> This bottleneck is further exacerbated if the CPU is attached to multiple GPUs and cannot produce enough samples to saturate them. Hence, accelerating graph sampling is important to improve the end-to-end training time.</p><p>Since samples are drawn independently, graph sampling is an "embarrassingly parallel" problem that seems ideal for exploiting the parallelism of GPUs. However, for a GPU to provide peak performance, the algorithm must be carefully designed to ensure regular computation and memory accesses, which is challenging on irregular graphs. Several Input Graphs PPI Reddit GraphSAGE <ref type="bibr">[13]</ref> 51% 45% FastGCN <ref type="bibr">[3]</ref> 26% 52% LADIES <ref type="bibr">[44]</ref> 40% 62% ClusterGCN <ref type="bibr">[6]</ref> 4.1% 24% GraphSAINT <ref type="bibr">[40]</ref> 25% 30% MVS <ref type="bibr">[7]</ref> 24% 25%</p><p>Table <ref type="table">1</ref>. Fraction of time spent in graph sampling in training.</p><p>systems have been designed for random walks <ref type="bibr">[38]</ref>, graph mining <ref type="bibr">[5,</ref><ref type="bibr">15,</ref><ref type="bibr">23,</ref><ref type="bibr">35]</ref>, and graph analytics <ref type="bibr">[19,</ref><ref type="bibr">26,</ref><ref type="bibr">31,</ref><ref type="bibr">37]</ref>. These systems consider samples (or subgraphs) as the fundamental unit of parallelism: they grow all samples in parallel by looking up the neighbors of the vertices of each sample. However, such an approach leads to two issues in these systems: (i) irregular memory accesses and divergent control flow because consecutive threads can access the neighbors of different vertices, and (ii) lower parallelism because computation on all vertices in a sample is performed serially by the thread responsible for growing the sample.</p><p>In this paper, we present NextDoor, the first system to perform efficient graph sampling on GPUs. NextDoor introduces transit-parallelism, which is a new approach to parallel graph sampling. In transit-parallelism, the fundamental unit of parallelism is a transit vertex, which is a vertex whose neighbors may be added to one or more samples of the graph. In transit-parallelism, each transit vertex is assigned to a group of threads such that each thread adds one neighbor of the transit vertex to one sample. With this technique we obtain better GPU execution efficiency due to lower warp divergence, coalesced global memory accesses, and caching of the transit vertex edges in low-latency shared memory. Thus the irregular computation on the graph is changed to a regular computation. NextDoor effectively balances load across transit vertices, by assigning them to different kernels based on the number of samples associated with a transit vertex. Each kernel uses a different scheduling and caching strategy to maximize the usage of execution resources and memory hierarchy. NextDoor has a high-level API that abstracts away the low-level details of implementing sampling on GPUs and enables ML domain experts to write efficient graph sampling algorithms with few lines of code. NextDoor achieves significant speedups over state-of-theart systems for graph sampling and improves training time of existing GNN systems by up to 4.75&#215;. The contributions of this paper are:</p><p>&#8226; A high-level API for building graph sampling algorithms with efficient execution on GPUs (Section 4). &#8226; A new transit-parallel paradigm to perform graph sampling on GPUs (Section 5). &#8226; NextDoor, which leverages transit-parallelism and adds techniques for load balancing and caching of a transit's adjacency list (Section 6). &#8226; Performance evaluation of NextDoor against state-ofthe-art systems: (i) a system of writing random walks KnightKing <ref type="bibr">[38]</ref>, (ii) existing GNNs (GraphSAGE <ref type="bibr">[13]</ref>,</p><p>FastGCN <ref type="bibr">[3]</ref>, LADIES <ref type="bibr">[44]</ref>, GraphSAINT <ref type="bibr">[40]</ref>, MVS <ref type="bibr">[7]</ref>, ClusterGCN <ref type="bibr">[6]</ref>), and (iii) two graph processing frameworks Gunrock <ref type="bibr">[37]</ref> and Tigr <ref type="bibr">[26]</ref> (Section 8). NextDoor and our experimental setup is available at <ref type="url">https://plasma-umass.org/nextdoor-eurosys21/</ref>.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2">Background and Motivation</head></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.1">Representation Learning on Graphs</head><p>The goal of a graph representation learning algorithm is to map vertices (or subgraphs) to an embedding, which is a &#119889;-dimensional vector (Figure <ref type="figure">1</ref>).</p><p>Early algorithms, such as DeepWalk <ref type="bibr">[28]</ref> and node2vec <ref type="bibr">[12]</ref> employ shallow encodings. Given an input graph with &#119899; vertices and a target &#119889;-dimensional Euclidean space, a shallow encoding is a &#119889; &#215; &#119899; matrix where the &#119894; &#119905;&#8462; column contains the embedding of vertex &#119907; &#119894; . These algorithms are transductive: they take a static graph as input and produce embeddings only for the vertices in that graph. They typically adapt the Skip-Gram approach <ref type="bibr">[24]</ref> to graphs, performing random walks to obtain context and target vertices.</p><p>More recent algorithms, including GraphSAGE <ref type="bibr">[13]</ref>, are inductive: they produce embeddings that generalize to previously unseen vertices. This property is particularly useful to build inference algorithms that work on dynamic, realworld graphs. Inductive algorithms learn a deep encoding, i.e., a function describing how to obtain a mapping, instead of the static map, and are also known as Graph Neural Networks (GNNs). Social networks like Pinterest uses GNNs to recommend newly added posts to users <ref type="bibr">[39]</ref>.</p><p>During GNN training and inference, each vertex aggregates information from nodes in its &#119896;-hop neighborhood using a neural network. Hops correspond to network layers, which are arranged as a tree. Aggregation follows the tree from the &#119896;-hop vertices back to the root vertex (Figure <ref type="figure">1</ref>). Some GNN training systems perform whole-graph training, that is, they execute aggregation across the entire input graph without sampling <ref type="bibr">[16,</ref><ref type="bibr">21]</ref>. Most GNN algorithms, however, use mini-batching, where a mini-batch consists of a set of root vertices and a sample of their &#119896;-hop neighborhood (e.g., <ref type="bibr">[3,</ref><ref type="bibr">6,</ref><ref type="bibr">7,</ref><ref type="bibr">13,</ref><ref type="bibr">40,</ref><ref type="bibr">44]</ref>). The mini-batching approach based on sampling is easier to parallelize and scale to large graphs.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2.2">Requirements for GPU Performance</head><p>We now present an overview of modern GPU architectures and highlight characteristics of high-performance GPU code. These characteristics motivate the design of NextDoor.</p><p>The fundamental unit of computation in a GPU is a thread. Threads are statically grouped into thread blocks and assigned a unique ID within a block. A GPU has multiple streaming multiprocessors (SMs), each of which executes one or more thread blocks. GPUs have several types of memory, two of which are relevant for this paper: (1) Each SM has a private memory, called shared memory, which is only available to thread blocks assigned to that SM; <ref type="bibr">(2)</ref> The GPU has global memory, which is accessible to all SMs. The access latency for global memory is significantly higher compared to shared memory and registers.</p><p>To run a thread block, an SM schedules a subset of threads from the thread block, known as a warp. A warp typically consists of 32 threads with consecutive thread IDs. Moreover, GPUs employ a Single Instruction Multiple Threads (SIMT) execution model: all threads in a warp run the same instruction in lock-step. One consequence of this execution model is that two threads cannot execute both sides of a branch concurrently. Therefore, when the threads in a warp encounter a branch, the subset of threads that do not take the branch must wait for other threads to complete the branch. This phenomenon is known as warp divergence can lead to poor performance. Thus, minimizing warp divergence is key to achieving high-performance on GPUs.</p><p>It is also important to balance load across thread blocks. Suppose an SM is assigned to run thread blocks &#119860; and &#119861;. Each thread block reserves a portion of SM resources, including registers and shared memory. When &#119860; is waiting, e.g., due to memory latency, the SM cannot switch execution to &#119861; because the resources reserved by &#119860; are unavailable to &#119861;. (This behavior is very different from threads on a CPU, where context switches save registers to memory, thus all CPU registers are available to all threads.) Hence, we need to balance resource usage across thread blocks to concurrently execute the maximum number of thread blocks per SM.</p><p>Finally, a GPU program must explicitly choose to work with shared or global memory, and use shared memory when possible to maximize performance. In particular, when a thread waits on a memory access, it blocks all other threads in the same warp (another consequence of the SIMT execution model). Therefore, the high latency of global memory access is particularly significant. Fortunately, the GPU can provide high-bandwidth access to global memory by coalescing several memory accesses from the same warp. This is only possible when concurrent memory accesses from threads in the same warp access consecutive memory segments.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3">An Abstraction for Graph Sampling</head><p>We introduce a general-purpose abstraction for graph sampling and use it to express common sampling algorithms. The input to a graph sampling algorithm is a graph and an initial set of samples, where each sample is a subset of vertices (and optionally edges) of the graph. The algorithm iteratively grows each sample to include additional vertices in a series of steps, and its output is the final set of expanded samples. At each step, a sampling algorithm performs the following operations for each sample: 1. Iteratively sample one vertex at a time and add it to the sample. This operation can access the neighborhood of some vertices, which we call transit vertices. 2. Determine the set of transit vertices for the next step. A graph sampling application can be expressed by providing user-defined functions that describe how to perform these operations. Namely, the next function describes how to sample one new vertex. The samplingType function describes the granularity at which we sample new vertices. There are two types of sampling: 1. Individual Transit Sampling: the next function is executed per-transit a fixed number of times. It has access to the neighborhood of that transit. 2. Collective Transit Sampling: the next function is executed per-sample a fixed number of times. It has access to the combined neighborhood of all transit vertices. Finally, the stepTransits function selects the vertices of the sample that will act as transit vertices in the next step. Other user-defined parameters are the number of steps &#119896;, which could be set to &#8734; if it varies from sample to sample, and the maximum number &#119898; &#119894; of new vertices sampled per transit vertex (for individual transit sampling) or per sample (for collective transit sampling) at step &#119894;. We now show that by changing these user-defined functions and parameters, we can express a wide variety of sampling algorithms.</p><p>Random walks <ref type="bibr">[12,</ref><ref type="bibr">27,</ref><ref type="bibr">28]</ref> A random walk starts from some initial set of root vertices. In a static random walk, the probability of picking an edge is known beforehand, whereas in a dynamic random walk, the probability of picking an edge depends on properties of vertices that were previously visited on that walk. DeepWalk <ref type="bibr">[28]</ref> performs fixed-size biased static random walks, where the probability of following an edge is proportional to the edge weight. Personalized Page Rank <ref type="bibr">[14]</ref> performs a variable-size biased static random walk, where the probability of ending the random walk is defined by the user. In contrast, node2vec <ref type="bibr">[12]</ref> is a dynamic random walk, which can be biased to stay closer to the starting vertex or to sample vertices that are further away. Yang et al. <ref type="bibr">[38]</ref> provide a taxonomy of different types of random walks.  For both applications the &#119899;&#119890;&#119909;&#119905; function uniformly samples two neighbors i.e., &#119898; 1 = 2 and &#119898; 2 = 2, and stepTransits returns the vertices added in previous step as transits. S &#119894; &#119895; denotes the vertices obtained after step &#119894; for sample S &#119895; . Initially, &#119878; 1 , &#119878; 2 , and &#119878; 3 contains a single vertex. In the first step, the neighbors of transit vertices, i.e., 2 &#9675;, 3 &#9675;, and 1 &#9675; are added to the sample by both applications. While 2-hop Neighborhood choose two neighbors of each transit vertex, Layer Sampling choose two neighbors from the set of all neighbors of all transit vertices of a sample. In the second step, vertices sampled in first step becomes the transit vertices. Output of both sampling applications for each sample contains all vertices sampled at all steps.</p><p>Our abstraction supports random walks as follows. Random walks are individual transit sampling applications because they sample a single neighbor of each transit vertex of the sample at each step. Every element &#119898; &#119894; is 1, since all random walks add at most one vertex at each step. Since the transit vertex is the previously sampled vertex, the stepTransits function returns the previously sampled vertex in the sample. The root vertices are the initial samples, such that each sample is assigned one root vertex. The number of steps &#119896; describes the length of the fixed-size random walks in algorithms like DeepWalk and node2vec. In these algorithms, &#119899;&#119890;&#119909;&#119905; always returns a vertex. However, for applications that perform a variable-size walk, such as Personalized Page Rank, &#119896; is set to &#8734;. For termination, &#119899;&#119890;&#119909;&#119905; can decide to not add a new vertex to the sample. The walk for a sample ends when the sample has no more new transit vertices.</p><p>MultiDimensional Random Walks <ref type="bibr">[30]</ref> generalize regular random walks. Each initial sample (walk) has a set of root vertices, which are potential transit vertices. Each step extends the walk as follows. First, a transit vertex is selected from the set of root vertices. Then, a neighbor of the transit vertex is added to the sample and replaces the transit vertex in the set of roots. Multi-dimensional random walks can be represented in our abstraction as follows. These walks perform individual transit sampling with &#119896; set to the length of walk, and each element &#119898; &#119894; to one. The function stepTransits returns a transit vertex for a sample by randomly choosing one of the root vertices and then the &#119899;&#119890;&#119909;&#119905; function chooses a neighbor of the transit vertex. GraphSAINT <ref type="bibr">[40]</ref> samples the graph using multi-dimensional random walks.</p><p>&#119896;-hop Neighborhood Sampling <ref type="bibr">[13]</ref> A &#119896;-hop neighborhood sampling algorithm employed in GraphSAGE <ref type="bibr">[13]</ref> adds one or more neighbors of a transit vertex at each step. Figure <ref type="figure">2b</ref> shows the execution of a 2-hop Neighborhood sampler that samples two neighbors of each transit at every step. This is individual transit sampling and can be represented in our abstraction by setting &#119896; = 2, &#119898; 1 = &#119898; 2 = 2, having stepTransits return all the vertices added in previous step as transit, and having next uniformly choose neighbors of each transit vertex and add them to the sample.</p><p>Layer Sampling <ref type="bibr">[10]</ref> At each step &#119894;, layer sampling samples &#119898; &#119894; vertices from the set of neighbors of all transit vertices of a sample, until the size of the sample reaches a maximum size (&#119872;) given by the user. Unlike the sampling applications we have seen previously, layer sampling is a collective transit sampling algorithm, where &#119898; &#119894; neighbors are chosen from the set of all neighbors of all transit vertices of a sample. The transit vertices of a sample at a step are the vertices added in previous step to the sample. Since this sampling can run for arbitrary steps, we set &#119896; to &#8734; and the next function chooses a neighbor from the set of all neighbors, if the size of the sample is less than &#119872;, otherwise next does to not add a new vertex to the sample. Figure <ref type="figure">2c</ref> shows the execution of Layer Sampling that samples two edges from each transit vertex. This can be represented in our abstraction by setting &#119896; = 2, &#119898; 1 = &#119898; 2 = 2, having stepTransits return the vertices added in previous step, and having next uniformly choose a neighbor from the combined neighborhood.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4">Graph Sampling using NextDoor</head><p>This section presents NextDoor's API, which is based on our graph sampling abstraction that we presented in the previous section. The API allows users to write a variety of graph sampling algorithms in just a few lines of code. Moreover, it allows users who are not experts in GPU programming to leverage modern GPU architectures.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4.1">Programming API</head><p>The inputs to NextDoor are a graph, an initial set of samples, and several user-defined functions (Figure <ref type="figure">3</ref>), which we detail below. The output is an expanded set of samples. If desired, NextDoor can pick the initial set of samples automatically (e.g., select one random vertex per sample).</p><p>The user selects collective or individual transit sampling using samplingType. The stepTransits function returns the transit vertices for a sample at a given step. In individual transit sampling, the number of transit vertices for each sample at step &#119895; are &#119895; &#119894;=0 &#119898; &#119894; . In collective transit sampling, the number of transit vertices for each sample are &#119898; &#119894;-1 . This function takes three arguments: 1) the step (step), 2) the sample (s), and 3) the index of transit out of all transits to return (transitIdx). The user must also define a sampling function to use at each step of the computation (next). This function receives four arguments: 1) the sample (s), 2) the source edge set to sample neighbors from (srcEdges), 3) transit vertices (transits) forming the source edge set, and 4) the current step (step). If the sampling is individual transit sampling then transits contains only a single transit vertex and srcEdges contains the edges of this transit vertex. Otherwise, transits contains all transit vertices of the sample and srcEdges contains edges of all transit vertices. The result of next must be a vertex to add to &#119904; (or a constant NULL that indicates not to add a neighbor). The function s.prevVertex(i, pos) returns the vertex added at position pos of the last &#119894; &#119905;&#8462; step, and the function s.prevEdges(i, pos) returns the edges of that vertex. This information is necessary for applications, such as node2vec. The steps function defines the number of computational steps in the application (&#119896;). For applications that do not run for a fixed number of steps, such as Personalized Page Rank and Layer Sampling, they can return a special constant INF and the sampling process for a sample is stopped when no new transit vertices are added to the sample. The value returned by the sampleSize function determines how many times the next function is invoked on each individual or collective neighborhood for each sample at each step. The unique function specifies if at a step the sample should contain only unique vertices. The Vertex class has utility methods for computing the vertex degree, the maximum weight of all edges (maxEdgeWeight), and the prefix sum of all edges' weights. Users can extend the class to include application-specific vertex attributes to be added to the samples.</p><p>Output format NextDoor supports two output formats based on the application. 1) NextDoor can return an array of samples, such that each sample contains all transit vertices sampled at all steps. This format is required by GNNs that use random walks and layer sampling. 2) NextDoor can return vertices sampled at each step in an individual array. This format is required by GNNs that uses &#119896;-hop neighborhood sampling. The arrays are stored in the GPU in both cases.  </p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4.2">Use Cases</head><p>We now present the implementation of several graph sampling algorithms using NextDoor.</p><p>node2vec The node2vec algorithm is a second-order random walk. Let &#119907; be transit vertex and &#119905; be the transit vertex of the last step. The probability of picking edge (&#119907;, &#119906;) depends on hyperparameters &#119901; and &#119902;, and is determined using three cases: (i) if &#119906; = &#119905; then the probability is &#119901;, (ii) if &#119906; &#8800; &#119905; and &#119906; is a neighbor of &#119905; then the probability is 1/&#119902;, or (iii) if &#119906; &#8800; &#119905; and &#119906; is not a neighbor of &#119905; then the probability is 1. The next vertex is sampled using rejection sampling, which takes these parameters as input <ref type="bibr">[38]</ref>.</p><p>Figure <ref type="figure">4a</ref> presents node2vec in NextDoor. The argument transits of next contains one transit vertex, since random walk is an individual transit sampling algorithm. Parameters &#119901; and &#119902; can be returned by a user-defined function or added as constants. next performs rejection sampling (rejection-smpl), the details of which are discussed in <ref type="bibr">[38]</ref>. stepTransits returns the vertex added at previous step. sampleSize returns 1 because we add only one neighbor of transit at each step. steps returns the length of walk, i.e., 100.</p><p>&#119896;-hop neighbors Figure <ref type="figure">4d</ref> implements GraphSAGE's 2hop neighborhood sampler in NextDoor. stepTransits returns the vertices added at previous step as transits. next retrieves the transit vertex for this sample in the transit variable, and chooses a neighbor of the transit vertex. Since this is a 2-hop sampling, steps returns 2. GraphSAGE <ref type="bibr">[13]</ref> sets the number of neighbors as &#119898; 1 = 10 and &#119898; 2 = 25, as reflected in sampleSize. MVS <ref type="bibr">[7]</ref> is implemented in a similar way as it obtains 1-hop neighbors of all initial vertices in the sample.   Importance Sampling In FastGCN <ref type="bibr">[3]</ref> and LADIES <ref type="bibr">[44]</ref> every sample includes an adjacency matrix that records the edges between vertices added in the previous step (the transit vertices) and the current step. At each step &#119894;, &#119898; &#119894; vertices are sampled from the graph according to a probability distribution and these vertices are added to the sample. Figure <ref type="figure">4b</ref> implements importance sampling as a collective transit sampling as returned by samplingType. At each step 64 vertices are sampled. next chooses a vertex of graph according to a probability distribution and adds an edge between the vertex and all transits, if it exists. The sampling criteria in <ref type="bibr">[3,</ref><ref type="bibr">44]</ref> can be added in next. stepTransits returns the vertices sampled in the last step.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>MultiDimensional Random Walk</head><p>Cluster Sampling ClusterGCN <ref type="bibr">[6]</ref> sampling obtains an adjacency matrix between all vertices of one or more clusters. Figure <ref type="figure">4b</ref> sketches the implementation where at each step an edge is recorded in a sample's adjacency matrix if the edge exists between any two transits.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5">Paradigms for Graph Sampling on GPUs</head><p>This section presents two paradigms for parallel graph sampling. Existing systems for graph sampling <ref type="bibr">[3,</ref><ref type="bibr">6,</ref><ref type="bibr">7,</ref><ref type="bibr">13,</ref><ref type="bibr">38,</ref><ref type="bibr">40,</ref><ref type="bibr">44]</ref> use sample parallellism. We discuss its shortcomings on GPUs and propose an alternative transit parallel paradigm.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.1">Sample-Parallelism</head><p>Graph sampling is an "embarrassingly parallel" problem and the natural approach to parallelization is to process each sample in parallel, which we call the sample parallel paradigm. The approach is analogous to subgraph parallel expansion in graph mining systems <ref type="bibr">[5,</ref><ref type="bibr">23,</ref><ref type="bibr">35]</ref>. We now discuss how to apply this approach to NextDoor's applications, performing both individual and collective transit sampling.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Individual Transit Sampling</head><p>The naive way to implement sample parallelism for individual transit sampling on GPUs is to assign a thread to each sample but this limits the amount of parallelism to the number of samples. NextDoor's API enables a new, fine-grained approach to sample parallelism. At each step &#119894;, we assign consecutive &#119898; &#119894; threads to a pair of sample and transit. Each thread then calls the user-defined function (next) on its transit. Since consecutive threads add vertices to the same sample, this approach allows writes to global memory to be coalesced. The algorithm visits samples and their transits in parallel. Figure <ref type="figure">5a</ref> shows an example of sample parallel execution for the second step of Figure <ref type="figure">2b</ref>. In this example, each sample is assigned to a thread block containing four threads. Each thread samples one vertex for the assigned transit and writes this vertex to the output.</p><p>Collective Transit Sampling For collective transit sampling, before calling the next function on the combined neighborhood of all transits, we need to compute this neighborhood. In a sample parallel approach, the combined neighborhood is computed in the same way as the individual transit sampling is performed. Consecutive threads are assigned to each pair of sample and transit, such that these threads copy the neighbors of one transit to the combined neighborhood, which is stored in global memory. After computing the combined neighborhood, we assign each pair of sample and transit to &#119898; &#119894; consecutive threads and call next on this neighborhood.</p><p>Limitations Despite the finer-grained approach enabled by the API, sample parallelism makes poor use of the GPU for the following reasons. 1) In an individual transit sampling, for each sample, the algorithm calls next on the neighbors of several transit vertices in parallel. However, if two threads in a warp are assigned to process two distinct transit vertices with different numbers of neighbors, the thread processing the smaller set of neighbors may stall until the other thread completes. Thus the algorithm suffers from warp divergence. Similarly, there is warp divergence when computing the combined neighborhood. 2) The algorithm also suffers from poor load balancing. The amount of work done by next is likely to depend on the number of neighbors of the transit vertex. For example, while computing combined neighborhood in collective transit sampling, different number of neighbors of each transit vertex leads to load imbalance within a thread block. 3) The graph must be stored in global memory, so accessing neighbors of transit vertex incurs high latency. Moreover, threads in a block may access the neighbors of different transit vertices, which leads to no locality. Hence, the GPU cannot coalesce reads or cache neighbors in shared memory.</p><p>For example, the execution in Figure <ref type="figure">5a</ref> suffers from both of the above issues. Since all four threads do not process same transit, there is divergent control flow and the adjacency list must be stored in global memory, leading to lack of locality among all threads of a thread block.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.2">Transit-Parallelism</head><p>To overcome the limitations of sample parallelism, we present the transit parallel paradigm. Transit parallelism groups all samples with the same transit vertex and process all samples for one transit vertex by assigning these samples to consecutive threads. This approach exposes regularity in sampling.</p><p>At each step the transit parallel paradigm works as follows. Before running sampling on the GPU, we create a map of transit vertices to their samples by grouping all samples associated with same transit vertex. We assign each transit vertex to a group of threads, which may be organized as a grid, thread block, or warp. In individual transit sampling, we assign each sample to consecutive threads in the group, and each thread calls next to add one neighbor of the transit to its sample. Similarly, in collective transit sampling, we create the combined neighborhood of the transits by assigning each sample to consecutive threads in the transit group (grid, thread block, or warp), and consecutive threads in the group add neighbors of the transit to the combined neighborhood of the sample. Building the combined neighborhood in a sampleparallel manner takes a significant portion of execution time.</p><p>NextDoor speeds up this step by using the transit parallel approach. In this case, instead of sampling new vertices from the neighborhood of each transit of the sample using next, the system adds the entire neighborhood to the combined neighborhood. Collective sampling applications then select new vertices from the combined neighborhood per sample.</p><p>Figure <ref type="figure">5b</ref> shows the execution of the second step of 2hop neighbor sampling of Figure <ref type="figure">2a</ref> in NextDoor using the transit parallel paradigm. Using load balancing (Section 6), NextDoor assigns transit 4</p><p>&#9675; to a grid, such that all thread blocks in that grid are assigned samples of 4</p><p>&#9675; and each thread adds one neighbor of 4</p><p>&#9675; to one sample of 4 &#9675;, i.e., either &#119878; 1 , &#119878; 2 , or &#119878; 3 . Similarly, it assigns vertex 1 &#9675; to a thread block and each thread adds one neighbor of 1 &#9675; to one of the samples associated with 1 &#9675;.</p><p>Advantages The transit parallel paradigm has two advantages for both individual and collective transit sampling: 1) contiguous threads perform a similar amount of work, because each thread calls the next function with same neighbors, and 2) contiguous threads accesses the neighbors of same transit. Both ensure non-divergent control flow, and locality of memory accesses. This eliminates warp divergence and addresses load balancing <ref type="foot">2</ref> . Moreover, since all threads work with same neighbors, we can cache the neighbors in shared memory to speed up later accesses. For example, in the execution shown in Figure <ref type="figure">5b</ref> each transit is assigned to one group of threads and this group caches the neighbors of each transit vertex in either shared memory or registers. Furthermore, each thread calls the next function on the same set of neighbors, which ensures nondivergent control flow among contiguous threads.   </p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6">Efficient Transit Parallelism on GPUs</head><p>NextDoor implements transit parallelism on a GPU, with CPU-based coordination. We first describe the techniques that allow NextDoor to execute individual transit sampling applications efficiently. We then describe how NextDoor uses the same techniques to execute collective transit sampling applications.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.1">Sampling in Individual Transit Sampling</head><p>In this section, we describe how NextDoor executes individual transit applications using transit parallelism.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.1.1">Leveraging Warp-Level Parallelism.</head><p>A GPU can coalesce several global memory accesses together into one memory transaction only if threads in a warp access consecutive addresses. The transit parallel paradigm lends itself to a GPU implementation that supports coalescing reads to global memory, by having consecutive threads read the same adjacency list (i.e., of the shared transit vertex). However, coalescing writes of new vertices to samples requires extra care. A two-level transit parallel approach maps different transit vertices to thread blocks and different samples to threads. This does not result in coalesced writes, since threads in the same warp add vertices to different samples. Instead, NextDoor uses three levels of parallelism: transits to thread blocks, samples to warps, and a single execution of the next function to a thread. Thus each thread writes one vertex to its sample and all threads in the warp issue one coalesced write to the same sample. Figure <ref type="figure">5b</ref> shows this mapping as follows. First, transits 4 &#9675;, 1 &#9675;, and 6 &#9675; are mapped to a group of threads. Then, samples (S 1 , S 2 , S 3 ) are mapped to subwarps and each thread executes next.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Sub-warps</head><p>In an ideal scenario, there would be a one-toone relationship between warps and samples, which would ensure that each thread in a warp writes to the same sample, using a single coalesced transaction to the global memory. However, there is a fixed number of threads per warp (usually 32) and this number can sometimes be larger than the required number of executions of the next function. Instead of letting threads be idle, NextDoor shares a warp among several samples. This yields some advantages. Suppose we share a warp of 32 threads among 4 samples, each having 8 contiguous threads. Then writes to the samples only generate 4 memory transactions rather than the 32 that we would obtain by assigning each thread to different sample. This also does not lead to warp divergence because all threads in a warp sample neighbors of the same transit vertex.</p><p>We use the term sub-warp to refer to a set of contiguous threads of same warp assigned to same sample. NextDoor uses sub warps as a fundamental unit of resource scheduling. All sub warps have the same size, which is determined using sampleSize function for the current step. Threads of the same sub-warp share the information of their registers using warp shuffles, and coordinate using syncwarp.</p><p>6.1.2 Load Balancing. In the transit parallel paradigm, each transit vertex is associated with a set of samples, which varies among transit vertices and steps. With three levels of parallelism, a transit vertex requires as many threads in a step as the total number of neighbors that will be added to its samples. Thus we obtain sub-optimal performance if we always assign a single thread block to each transit vertex. At the limit, the number of threads required by a transit vertex may exceed the limit of number of threads in a block. On the other hand, if a transit vertex only requires a small number of threads, dedicating an entire thread block to the transit wastes GPU resources. To address this problem, NextDoor uses three types of GPU kernel (see Table <ref type="table">2</ref> Scheduling To assign transits to kernels, NextDoor creates a scheduling index for each transit vertex. Creating a scheduling index involves three stages. First, NextDoor creates a transit-to-sample map based on the transits obtained from the stepTransits function (Figure <ref type="figure">5b</ref>). Then, NextDoor partitions all transit vertices into three sets based on the number of samples associated with each transit vertex using parallel scan operations. Finally, the scheduling index of a transit vertex is set to the index of the transit vertex in its set. After picking a kernel type for a transit vertex, we assign each sample of the transit vertex to a sub-warp in the kernel based on the thread index.</p><p>Caching NextDoor uses different caching strategies for different kernels to minimize memory access costs. When sampling neighbors of transit vertices in the grid and thread block kernels, the thread blocks for these kernels load the neighbors of transit vertices into shared memory. However, when the neighbors do not fit in shared memory, NextDoor transparently loads neighbors from global memory. For transit vertices assigned to a sub-warp, NextDoor utilizes both shared memory and thread local registers to store neighbors. In this case, NextDoor transparently manages accesses to the neighbor list using warp shuffle instructions that allows consecutive threads to read neighbors from each others' registers. In summary, NextDoor uses the fastest caching mechanisms available for each kernel.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.2">Transit-Parallel Collective Transit Sampling</head><p>Collective transit sampling applications require computing the combined neighborhood of all the transits of each sample. This is a potential performance bottleneck, so NextDoor uses transit parallelism to speed up the process. It constructs the combined neighborhood as if it were an individual transit sampling application that runs for only one step. Instead of sampling new vertices from the neighborhood of one transit, NextDoor adds all the vertices in the neighborhood to the combined neighborhood of the sample. After building a single combined transit neighborhood per sample, one could in principle detect which samples have the same combined neighborhoods and expand all these samples in a transitparallel manner. The likelihood of two combined neighborhood being equal, however, is generally low, and detecting which samples have the same combined neighborhood is expensive. Therefore, NextDoor adds new vertices to the sample using a sample-parallel approach.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.3">Unique Neighbors</head><p>Certain applications, require all sampled neighbors from all transit vertices to be unique. After sampling at each step NextDoor removes duplicated sampled vertices by first sorting them with a parallel radix sort, and then getting distinct vertices using parallel scan. If sampled neighbors fit in the shared memory then NextDoor performs this computation by assigning one sample to one thread block, otherwise one kernel is called for each sample. After this process if the sample size is less than the stepSize, then NextDoor performs sampling using a sample-parallel approach instead of the transit-parallel one.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.4">Graph Sampling using Multiple</head><p>NextDoor utilizes the embarrassingly parallel nature of graph sampling to parallelize graph sampling over multiple GPUs in the following way. First NextDoor distributes samples equally among all GPUs. Then, NextDoor performs load balancing and scheduling and calls the sampling kernels on each GPU independently. Finally, it collects the output from all GPUs.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.5">Integration in GNNs using Python API</head><p>NextDoor provides Python 2 and 3 modules that can be used to do sampling from within a GNN. For this, users first define NextDoor API functions, then call doSampling function to do transit-parallel sampling, and finally call getFinalSamples to obtain samples in a numpy.ndarray. Table <ref type="table">2</ref>. Types of kernels used to process transit vertices based on the number of neighbors to sample for the transit vertex.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6.6">Advantages of</head><p>sample and transit parallelism. NextDoor's API is general purpose and supports different kinds of graph sampling applications, while existing systems either running specific graph sampling applications <ref type="bibr">[3,</ref><ref type="bibr">6,</ref><ref type="bibr">10,</ref><ref type="bibr">13,</ref><ref type="bibr">40,</ref><ref type="bibr">44]</ref> or only support expressing specific kinds of graph sampling applications, as for example random walks for KnightKing <ref type="bibr">[38]</ref>. Furthermore, NextDoor's API requires applications to explicitly indicate which vertices in each sample are transit vertices. This distinction is critical to enable transit parallelism. Finally, the API requires applications to explicitly state the number of vertices that must be sampled at each step. This information is used by NextDoor to effectively load balance computation across the execution hierarchy of the GPU.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="7">Alternative Graph Processing Systems</head><p>Abstractions provided by existing GPU based graph processing systems to implement graph algorithms can be divided into two types: (i) Message Passing and (ii) Frontier Centric. We now study the implementation of graph sampling using both abstractions and discuss why these implementations provides sub-optimal performance.</p><p>Message-passing Abstraction is provided by several graph computation frameworks <ref type="bibr">[9,</ref><ref type="bibr">17,</ref><ref type="bibr">22,</ref><ref type="bibr">26,</ref><ref type="bibr">31]</ref>, where each vertex is associated with a local state and a vertex can send messages to its neighbors. Upon receiving messages, vertices update their state and can send new messages. Graph computations written in this abstraction advances the computation by exchanging messages between vertices at each step. A transit-parallel approach for graph sampling implemented using message passing works in the following way. First, in each step for each sample associated with a transit, neighbors of the transit are sampled. Then, the stepTransits function is called to retrieve transit for next step and the associated samples are send to the transit in the form of messages. Each transit vertex is associated with only one thread, which processes all its samples sequentially.</p><p>Frontier-centric Abstraction is provided by Gunrock <ref type="bibr">[37]</ref>, which exploits the property that after any step of a graph computation, a set of frontier vertices are produced for the next step of the computation. The Advance operator in this abstraction defines the computation and generates a new frontier by assigning one thread to each neighbor of each vertex in the input frontier.</p><p>A transit-parallel approach for graph sampling can be implemented in this abstraction as follows way. The Advance operator contains the user-defined sampling criteria, which is invoked on each neighbor of the transit vertex. This operator will decide whether the neighbor should be added to the sample. In that case, stepTransits is called to retrieve the transit vertex for the sample and the transit vertex is added to the new frontier. Each thread for a neighbor must make this decision for all the associated samples, which are processed sequentially.</p><p>Limitations over NextDoor Graph processing systems providing above abstractions suffers from two fundamental issues. First, these systems only consider one degree of parallelism, i.e., all transit vertices can be processed in parallel but samples for each transit are processed sequentially. This is because these systems are designed for traditional graph computations, such as Breadth First Search, Connected Components, etc., which only has one degree of parallelism. Second, these systems balances the load based on the number of neighbors for each vertex because all neighbors of each vertex are visited in a traditional graph processing application. But, in a graph sampling number of neighbors to sample at a step can be significantly less than the neighbors of a transit vertex. Hence, NextDoor takes a different approach from existing system to solve these issues. Section 8.3 shows that NextDoor performs better than these systems.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8">Evaluation</head><p>We implemented NextDoor in NVIDIA CUDA 11.2.</p><p>Benchmarks We use the graph sampling applications mentioned in Section 4 as benchmarks for our evaluation. We set applications' parameters as follows. For PPR the termination probability is set to 1/100, i.e., mean length is 100. For all other random walks, we set the walk length to 100. For node2vec we set &#119901; to 2.0 and &#119902; to 0.5. For these random walks, initially there is one vertex per sample. For MultiDimensional Random Walk (MultiRW), we set 100 root vertices per sample. We use GraphSAGE <ref type="bibr">[13]</ref>'s hyperparameters for k-hop Neighborhood Sampling, i.e., &#119896; = 2, &#119898; 1 = 25, and &#119898; 2 = 10. For Layer Sampling we set final sample size to 2000 and step size for all steps to 1000. For FastGCN, LADIES, and MVS Sampling batch size and step size are set to 64. For ClusterGCN Sampling we randomly assigned vertices in clusters and each sample contains 20 clusters.</p><p>Datasets Table <ref type="table">3</ref> lists the details of real world graphs used in our evaluation obtained from Stanford Network Analysis Project <ref type="bibr">[18]</ref>. We generate a weighted version of these graphs by assigning weights to each edge randomly from <ref type="bibr">[1,</ref><ref type="bibr">5)</ref>. Table <ref type="table">3</ref>. Graph used in our evaluation.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Experimental setup</head><p>We perform experiments on a system containing two 16-core Intel Xeon(R) Silver 4216 CPU, 128 GB RAM, and an NVIDIA Tesla V100 GPU with 16GB memory running Ubuntu 18.04. We report the average time of 10 executions. We report the execution time spent on the GPU, which includes the time spent in sampling and creating the scheduling index. Since transferring graphs to the GPU that fits inside the GPU memory takes only few milliseconds (less than 5% of total execution time), we do not consider these times in the total execution time unless specified otherwise.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.1">Execution Time Breakdown</head><p>The execution time of an application in NextDoor consists of the time spent in sampling and creating the scheduling index. NextDoor builds the scheduling index by sorting the samples based on the neighbors in each sample as keys and then dividing the transit vertices into three sets based on the number of samples for each transit, using parallel scan. Figure <ref type="figure">6</ref> shows the time spent in both phases as a fraction of the total execution time. The time spent in building scheduling index ranges from 5% of the total time in Clus-terGCN for sampling LiveJ graph to 40.4% of the total time in DeepWalk for sampling Orkut graph. Random walks spend a higher fraction of time building the scheduling index. This is because they sample only a single vertex per step, leading to fewer common samples and less work per transit than other applications. NextDoor uses parallel radix sort and parallel scan of NVIDIA CUB <ref type="bibr">[1]</ref> to create the scheduling index efficiently. With more efficient implementations of these algorithms <ref type="bibr">[34]</ref> available for GPUs, we expect this time to decrease significantly in future.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.2">Graph Sampling Performance</head><p>We compare NextDoor with the following systems.</p><p>SP NextDoor is the first system for graph sampling on GPUs. Since we cannot compare it with other systems, we implemented an optimized sample-parallel graph sampling system based on the NextDoor API, which we refer to as SP. We implemented all the optimizations of NextDoor that could be adapted to a sample-parallel system, such as load balancing, scheduling, and the fine-grained parallelism discussed in Section 5.1. The purpose of SP is to evaluate the benefits of transit-parallelism in isolation, without considering all the other optimizations enabled by the new API. Since TensorFlow based reference implementation of layer sampling <ref type="bibr">[10]</ref> does not support the datasets used in evaluation and the implementation follows sample-parallel paradigm, we use SP as a baseline in layer sampling.</p><p>TP To show the performance improvement due to NextDoor's load balancing and scheduling optimizations described in Section 6, we compare against vanilla transit-parallel approach (see Section 5.2), which assigns each transit and sample pair to &#119898; &#119894; consecutive threads. We refer to this implementation as TP.</p><p>KnightKing KnightKing <ref type="bibr">[38]</ref> is a state of the art system for doing random walks using CPUs. It uses rejection sampling as a technique to select new vertices of a random walk and supports sampling using distributed systems. Its API restricts expressing only random walks, hence, we use the system as a baseline only for random walks.</p><p>Existing GNN SamplersWe compare against the samplers of existing GNNs. These samplers are written for Tensor-Flow or numpy and are designed to run only on multi-core CPUs, not GPUs. This is because sampling is an irregular computation that is more easily implemented on CPUs. For &#119896;-hop neighborhood, we compare against GraphSAGE's sampler <ref type="bibr">[13]</ref>. For MultiRW, we compare against GraphSAINT's sampler <ref type="bibr">[40]</ref>. For sampling algorithms in FastGCN <ref type="bibr">[3]</ref>, Clus-terGCN <ref type="bibr">[6]</ref>, MVS <ref type="bibr">[7]</ref>, and LADIES <ref type="bibr">[44]</ref>, we compare against samplers in their reference implementations.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Performance Results</head><p>NextDoor provides an order of magnitude speedup over KnightKing (Figure <ref type="figure">7a</ref>) for all random walk applications, with speedups ranging from 26.1&#215; to 50&#215;.</p><p>NextDoor provides an order of magnitude speedup over the implementations of existing GNNs (Figure <ref type="figure">7b</ref>). These large speedups are possible due to the massive parallelism and memory access latency hiding capabilities of the GPU. Furthermore, SP is significantly faster than all baselines.</p><p>NextDoor provides significant speedups over SP on all graph sampling applications, with speedups ranging from 1.09&#215; to 6&#215;. The speedup depends significantly on the application. For example, NextDoor obtains more speedup in DeepWalk and PPR than in node2vec because in node2vec at each step, for an edge from current transit vertex &#119907; to a vertex &#119906;, the algorithm might do a search over the edges of the previous transit vertex &#119905; to check if &#119906; is a neighbor of &#119905;, leading to memory accesses and warp divergence. Nevertheless, NextDoor still obtains speedup due to its transit-parallel paradigm. NextDoor achieves speedup over SP in all applications because NextDoor uses three levels of parallelism while SP can use only two levels of parallelism. Moreover, with FastGCN and LADIES, NextDoor is faster because it speeds up the computation of the combined neighborhood.  NextDoor significantly improves performance over TP due to better load balancing and scheduling. TP is competitive to SP in random walks even though significant time is spent in map inversion because TP caches the neighbors in shared memory. TP outperforms SP in other applications because caching neighbors in shared memory decreases memory access time when sampling many neighbors.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.2.1">NextDoor's Effectiveness over SP. To explain</head><p>NextDoor's effectiveness over SP, we obtained values of L2 Cache Read Transaction performance metrics using nvprof. This metric represents the total number of L2 cache load transactions in the entire execution. Figure <ref type="figure">8</ref> shows the value of this metrics for NextDoor relative to SP. NextDoor performs a fraction of the transactions of SP because it performs coalesced reads and caches edges of transit vertices in shared memory and registers. ClusterGCN, MVS, FastGCN, and LADIES sampling perform a similar number of loads and stores as &#119896;-hop and Layer sampling. Global Memory Store Efficiency is the ratio of extra store transactions over the ideal number of transactions to the ideal number of transactions. Hence, higher efficiency is better. NextDoor performs fully efficient global memory stores because of the sub-warp execution. Since ClusterGCN, MVS, FastGCN, and LADIES sampling perform number of loads and stores similar to &#119896;-hop and Layer sampling, we found similar store efficiency for these applications.</p><p>Multiprocessor Activity is the average usage of all SMs over the entire execution of the application. For PPI, Multiprocessor Activity is low because PPI is a small graph and not enough threads are generated to fully utilize all SMs. For all graphs NextDoor fully utilizes all SMs. Hence, NextDoor's load balancing strategy balances load across all SMs. We found similar results other sampling applications.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.3">Alternative GPU-Based Abstractions</head><p>We also compare NextDoor with two state-of-the-art graph processing frameworks: Gunrock <ref type="bibr">[37]</ref> and Tigr <ref type="bibr">[26]</ref>, which follow the frontier-centric and message-passing abstractions, respectively (see <ref type="bibr">Section 7)</ref>. Figure <ref type="figure">9</ref>  poor load balancing due to the mismatch between graph sampling and graph processing abstraction result in speedup.</p><p>We found similar results on other applications.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.4">Sampling Large Graphs</head><p>We evaluate a simple approach for sampling large graphs.</p><p>NextDoor can sample graphs that do not fit in GPU memory by creating disjoint sub-graphs, such that each of these sub-graphs and its samples be allocated in the GPU memory. After creating these sub-graphs at each computation step, NextDoor performs sampling for each sample by transferring all sub-graphs containing the transit vertices of each sample to the GPU. In this experiment, we consider the time taken to transfer graph from CPU to GPU.</p><p>We evaluate this approach by executing &#119896;-hop and random walks on the FriendS graph, which does not fit in the GPU memory. For &#119896;-hop neighborhood and layer sampling, NextDoor is the only system in our experiments that can sample a graph of that size. NextDoor gives a throughput of 3.3&#215;10 6 samples per second on &#119896;-hop and 2&#215;10 6 on layer sampling. Both applications are computation bound and not memory transfer bound. For random walks, KnightKing is the only baseline that can perform the sampling because it is CPU based. NextDoor performs worse than KnightKing for random walks where the computation load is low: it provides about 1/2 of the throughput with DeepWalk and PPR. However, in node2vec where the computation time is larger, NextDoor gives 1.50&#215; speedup over KnightKing.</p><p>In summary, NextDoor is able to sample graphs that do not fit in GPU memory, and can outperform state-of-theart systems when the graph sampling application performs significant amount of computation. We plan to improve the support for large graphs in NextDoor as future work.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.5">Sampling on Multiple GPUs</head><p>We used NextDoor to perform sampling on four NVIDIA Tesla V100 GPUs. Figure <ref type="figure">10</ref> presents the speedup of sampling using four GPUs over single GPU. Multi-GPU sampling achieves significant speedup over single GPU on several ap-Random walks achieves significant speedup in all graphs except PPI because PPI is a small graph. On the other hand, &#119896;-hop neighbors achieves almost full scaling even in small graph like PPI because it increases the number of transit vertices exponentially at each step. In summary, NextDoor is able to utilize multiple GPUs efficiently.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8.6">End-to-End Integration in GNN Systems</head><p>We performed an end-to-end evaluation of existing GNNs by replacing their sampler with the sampling implementation in NextDoor. Table <ref type="table">5</ref> shows the performance improvement of our integration. The speedup for GraphSAGE is less the maximum possible improvement in Table <ref type="table">1</ref> due to a limitation of Tensorflow, which does not allow creating a tensor on the GPU memory. Therefore, samples are copied to the CPU and then again to the GPU for training. For FastGCN and LADIES, the speedup increases with larger graphs because the sampling time depends on the number of vertices in the graph, while the training time per batch remains constant. Since NextDoor provides significant speedup over samplers in GraphSAINT and MVS, we believe NextDoor integration will improve training time.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="9">Related Work</head><p>We now discuss related work beyond KnightKing, Gunrock, and Tigr, which we discussed in Sections 7 and 8.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head>Message-passing graph processing</head><p>There are several graph processing systems that provide a message-passing abstraction that run on CPUs <ref type="bibr">[11,</ref><ref type="bibr">20,</ref><ref type="bibr">22,</ref><ref type="bibr">25,</ref><ref type="bibr">33,</ref><ref type="bibr">42,</ref><ref type="bibr">43]</ref> and GPUs <ref type="bibr">[9,</ref><ref type="bibr">17,</ref><ref type="bibr">26,</ref><ref type="bibr">31,</ref><ref type="bibr">41]</ref>. Our evaluation shows that NextDoor outperforms Tigr <ref type="bibr">[26]</ref> on graph sampling tasks (Section 8).</p><p>Medusa <ref type="bibr">[41]</ref> was the first GPU-based graph processing framework to provide a message passing abstraction. CuSha <ref type="bibr">[17]</ref> and MapGraph <ref type="bibr">[9]</ref> provide a Gather And Scatter (GAS) abstraction. CuSha uses a parallel sliding-window graph representation ("G-Shards") to avoid irregular memory accesses. Subway <ref type="bibr">[31]</ref> splits the large graphs that do not fit in GPU memory into sub-graphs and optimizes memory transfers between CPU and GPU. Shi et al <ref type="bibr">[32]</ref> present an extensive review of systems for graph processing on GPUs. Power-Lyra <ref type="bibr">[4]</ref> uses different computations on vertices based on their degree.</p><p>Frontier-centric graph processing SIMD-X <ref type="bibr">[19]</ref> extends the frontier abstraction of Gunrock <ref type="bibr">[37]</ref>, but these extensions are not relevant for graph sampling.</p><p>Graph mining Graph mining systems follow a subgraphparallel paradigm that is analogous to sample-parallelism <ref type="bibr">[2,</ref><ref type="bibr">5,</ref><ref type="bibr">8,</ref><ref type="bibr">15,</ref><ref type="bibr">23,</ref><ref type="bibr">29,</ref><ref type="bibr">35,</ref><ref type="bibr">36]</ref>. However, even the sample-parallel sampling algorithm of Section 5 introduces optimizations that are specific to the graph sampling abstraction of Section 3 and do not generalize to graph mining problems. 1) In graph sampling the number of samples is fixed, whereas graph mining problem may involve exploring an exponential number of subgraphs. 2) sampling adds a constant number of new vertices to each sample at each step. This makes it possible to associate new vertices to threads at scheduling time, before visiting the graph. 3) Sampling has a notion of transit vertices. NextDoor leverages all these features.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="10">Conclusion</head><p>We show that efficient graph sampling on GPUs is non-trivial. Existing sampling and graph processing systems do not provide the right abstractions to efficiently support several graph sampling algorithms on GPUs. We introduce transitparallel sampling, a new paradigm for graph sampling that is amenable to an efficient GPU implementation. We present NextDoor, a system that implements transit-parallel sampling for GPUs to provide regular memory access and computation, and a high-level API to express several graph sampling applications. We show that NextDoor is significantly faster than the existing systems on several applications.</p></div><note xmlns="http://www.tei-c.org/ns/1.0" place="foot" n="1" xml:id="foot_0"><p>We use a 16-core Intel Xeon Silver CPU and an NVIDIA Tesla V100 GPU.</p></note>
			<note xmlns="http://www.tei-c.org/ns/1.0" place="foot" n="2" xml:id="foot_1"><p>A badly-written user-defined function may have these issues, but NextDoor avoids them in the core algorithm.</p></note>
		</body>
		</text>
</TEI>
