Parallel Optimization of the Set Data Structure

Total Page:16

File Type:pdf, Size:1020Kb

Parallel Optimization of the Set Data Structure Parallel optimization of the set data structure Gustav Karlsson Gustav Karlsson Spring 2015 Bachelor’s thesis, 15 hp Supervisor: Jerry Eriksson Examiner: Pedher Johansson Bachelor’s program in computer science, 180 hp Abstract The Set data structure is a powerful and popular programmer’s tool based on set theory. Bulk operations such as addAll provide a sim- ple way of working with big collections of elements but can severely limit the performance of a multi-processor system when invoked on big sets if performed sequentially. Parallel processing is a technique that can significantly shorten the ex- ecution time of otherwise sequentially executed tasks. In this thesis, a new type of set is proposed that uses multiple threads to employ parallel processing for bulk operations. A new set is designed based on a non-blocking hash table with a high level of concurrency. The parallelization of the set makes use of paral- lel Java 8 streams to allow for quick iteration of the source collection elements, resulting in a speedup in processing of bulk operations. Testing the parallel set shows a significant increase in execution speed on bulk operations when operating on more than 10000 elements. Acknowledgements I would like to thank my supervisor Jerry Eriksson at Umea˚ University for helping me keep this work on track. I would also like to thank Pedher Johansson at Umea˚ University for giving me some valuable assistance and feedback. Finally, thank you Judith for your support, patience, and for putting up with my ramblings and rants. Contents 1 Introduction 1 2 The set data structure 1 2.1 Operations 2 2.1.1 Inspecting operations 2 2.1.2 Mutating operations 2 2.1.3 Set creation operations 2 2.1.4 Bulk operations 3 2.2 Performance and common implementations 3 2.2.1 Array 3 2.2.2 Linked list 4 2.2.3 Binary search tree 4 2.2.4 Hash table 4 3 Concurrency and parallelism 5 3.1 Turning concurrent into parallel 8 3.2 Bulk operations 9 3.3 The producer – consumer bottleneck 9 4 A case for parallel sets 9 5 Method 10 5.1 Java 8 as a test platform 10 5.2 Designing a parallel set 10 5.2.1 Cliff Click’s non-blocking hash table 11 5.2.2 Achieving non-blocking concurrency 11 5.2.3 Turning the hash table into a set 12 5.2.4 Parallelization 12 5.3 Testing 13 5.3.1 Parameters 13 5.3.2 Test setup 14 6 Results 15 7 Conclusion 18 8 Discussion 18 8.1 CPU scaling 18 8.2 Number of elements scaling 18 8.3 Future work 19 8.4 Closing 19 References 21 1(21) 1 Introduction Data structures are foundational in computer science and come in many different forms such as lists, maps, trees, queues, stacks and sets. They are used for many different pur- poses such as assuring the flow of data, controlling relations between elements, or to simply act as containers. An interesting aspect of data structures is how they are represented in computer programs. The elements held in a data structure must be mapped to the comput- ers main memory and as they grow in size, performance becomes an increasingly interesting topic of research. Execution time for lookups and modifications is one of the most impor- tant performance metrics of a data structure and can vary greatly depending on how it is implemented. As time goes and development continues, computer systems get increasingly faster, but in recent years, processor speed is increasing slower and slower due to difficulties in the manufacturing process known as the “power wall” [1]. Instead, focus has shifted towards increasing the number of processors (or processor cores). This has forced programmers to make better use of multiple processors in computations – a difficult task that requires careful design to avoid issues such as race conditions, deadlocks and resource starvation. One way of simplifying the use of multiple processors is to hide the parallelization behind a layer of abstraction such as a class in object oriented design. By encapsulating the com- plex parts, the solution can be reused in other projects to help spread the use of parallel computing. Goal The goal of this work is to design and implement a mutable set1 capable of executing a selection of its operations in parallel by encapsulating the parallelism in the implementation of the set. Sets are targeted both to limit the scope of the work and because they are inter- esting from a performance standpoint. The resulting set is tested to answer the following questions: • How does a parallel set perform in comparison to a sequential set when running on a multi-processor system? • How does the performance of a parallel set scale with the number of used processors? • How does the performance of a parallel set scale with the size of the operation? 2 The set data structure The set data structure is useful tool for programmers and originates from set theory – a branch of mathematical logic – in which it would more accurately be described as a finite set2. 1A mutable set can be modified by inserting or removing elements. 2A finite set has a limited number of elements, as opposed to an infinite set such as the set of all positive integers. 2(21) A set is a collection of elements where any given element may only occur once. The ele- ments of a set are not ordered3 so the only two states an element can have in relation to a set is being a member of the set, or not being a member of the set. 2.1 Operations Sets can be operated on in a number of ways depending on the type of set and what the intended purpose is. Some operations only inspect the state of the set, while some make modifications to it or create new sets from existing sets. 2.1.1 Inspecting operations Inspecting operations are used to inspect the state of the set. The most basic operations are: contains Checks whether the set contains a given element. size Returns the cardinality (number of contained elements) of the set. 2.1.2 Mutating operations Mutable sets must provide at least the following operations for the set to be “fully muta- ble”4: add Adds a given element to the set. The element is rejected if it is already a member of the set. Many implementations return a boolean value indicating if the insertion was accepted or rejected. remove Removes a given element from the set. Many implementations return a boolean value indicating if the element was removed or if it is not a member of the set. 2.1.3 Set creation operations In addition to operations performed on a set, some operations can be used to create new sets from multiple input sets. union Creates a set from elements that are members of any of the input sets. intersection Creates a set from elements that are members of all input sets. difference Creates a set from two existing sets A and B, consisting of elements from A that are not members of B. 3Although some implementations order elements to provide a predictable iteration order or faster lookups. 4Fully mutable in this case means that a set can always go from any possible state to any other possible state through mutable operations 3(21) 2.1.4 Bulk operations For the convenience of the programmer, some implementations provide bulk versions of single element operations. Bulk operations do not provide any extra functionality but in- stead act as a replacement for the typical “for each item in A, do X on B” approach. They take as input an arbitrary number of elements (often packed in a data structure of their own) and perform an operation on the target set with each of the input elements. addAll Adds all elements of the input collection to the set. If the input is also a set, the target set will become the union of both sets. removeAll Removes all elements of the input collection from the set. If the input is also a set, the target set will become the difference between the target set and the input set. containsAll Checks whether the set contains all elements in the input collection. If the input is also a set, this will effectively determine if the input set is a subset of the target set. retainAll Removes all elements from the set that are not in the input collection. This is the inverse of removeAll. 2.2 Performance and common implementations The restriction on sets to only contain a single instance of any element leads to an interesting observation: When adding an element to a set, the implementation must have some mech- anism to rule out every other member as a duplicate of the element being inserted before accepting it. This can have a considerable impact on performance and a poorly designed implementation might need to traverse the full set on every insertion. Another interesting property is the disorderliness of sets. Since elements are not ordered, there is no straightforward way of finding an element and the full set might have to be traversed in order to find the desired element. Ultimately, this means that calls to add, remove and contains are O(n) for any trivial implementation. There are numerous ways to implement sets. Implementations come with different char- acteristics that make them suitable for different situations. Some of the most common ap- proaches are: 2.2.1 Array Elements are kept in a fixed size array where empty slots hold a null reference.
Recommended publications
  • Metaobject Protocols: Why We Want Them and What Else They Can Do
    Metaobject protocols: Why we want them and what else they can do Gregor Kiczales, J.Michael Ashley, Luis Rodriguez, Amin Vahdat, and Daniel G. Bobrow Published in A. Paepcke, editor, Object-Oriented Programming: The CLOS Perspective, pages 101 ¾ 118. The MIT Press, Cambridge, MA, 1993. © Massachusetts Institute of Technology All rights reserved. No part of this book may be reproduced in any form by any electronic or mechanical means (including photocopying, recording, or information storage and retrieval) without permission in writing from the publisher. Metaob ject Proto cols WhyWeWant Them and What Else They Can Do App ears in Object OrientedProgramming: The CLOS Perspective c Copyright 1993 MIT Press Gregor Kiczales, J. Michael Ashley, Luis Ro driguez, Amin Vahdat and Daniel G. Bobrow Original ly conceivedasaneat idea that could help solve problems in the design and implementation of CLOS, the metaobject protocol framework now appears to have applicability to a wide range of problems that come up in high-level languages. This chapter sketches this wider potential, by drawing an analogy to ordinary language design, by presenting some early design principles, and by presenting an overview of three new metaobject protcols we have designed that, respectively, control the semantics of Scheme, the compilation of Scheme, and the static paral lelization of Scheme programs. Intro duction The CLOS Metaob ject Proto col MOP was motivated by the tension b etween, what at the time, seemed liketwo con icting desires. The rst was to have a relatively small but p owerful language for doing ob ject-oriented programming in Lisp. The second was to satisfy what seemed to b e a large numb er of user demands, including: compatibility with previous languages, p erformance compara- ble to or b etter than previous implementations and extensibility to allow further exp erimentation with ob ject-oriented concepts see Chapter 2 for examples of directions in which ob ject-oriented techniques might b e pushed.
    [Show full text]
  • 250P: Computer Systems Architecture Lecture 10: Caches
    250P: Computer Systems Architecture Lecture 10: Caches Anton Burtsev April, 2021 The Cache Hierarchy Core L1 L2 L3 Off-chip memory 2 Accessing the Cache Byte address 101000 Offset 8-byte words 8 words: 3 index bits Direct-mapped cache: each address maps to a unique address Sets Data array 3 The Tag Array Byte address 101000 Tag 8-byte words Compare Direct-mapped cache: each address maps to a unique address Tag array Data array 4 Increasing Line Size Byte address A large cache line size smaller tag array, fewer misses because of spatial locality 10100000 32-byte cache Tag Offset line size or block size Tag array Data array 5 Associativity Byte address Set associativity fewer conflicts; wasted power because multiple data and tags are read 10100000 Tag Way-1 Way-2 Tag array Data array Compare 6 Example • 32 KB 4-way set-associative data cache array with 32 byte line sizes • How many sets? • How many index bits, offset bits, tag bits? • How large is the tag array? 7 Types of Cache Misses • Compulsory misses: happens the first time a memory word is accessed – the misses for an infinite cache • Capacity misses: happens because the program touched many other words before re-touching the same word – the misses for a fully-associative cache • Conflict misses: happens because two words map to the same location in the cache – the misses generated while moving from a fully-associative to a direct-mapped cache • Sidenote: can a fully-associative cache have more misses than a direct-mapped cache of the same size? 8 Reducing Miss Rate • Large block
    [Show full text]
  • Chapter 2 Basics of Scanning And
    Chapter 2 Basics of Scanning and Conventional Programming in Java In this chapter, we will introduce you to an initial set of Java features, the equivalent of which you should have seen in your CS-1 class; the separation of problem, representation, algorithm and program – four concepts you have probably seen in your CS-1 class; style rules with which you are probably familiar, and scanning - a general class of problems we see in both computer science and other fields. Each chapter is associated with an animating recorded PowerPoint presentation and a YouTube video created from the presentation. It is meant to be a transcript of the associated presentation that contains little graphics and thus can be read even on a small device. You should refer to the associated material if you feel the need for a different instruction medium. Also associated with each chapter is hyperlinked code examples presented here. References to previously presented code modules are links that can be traversed to remind you of the details. The resources for this chapter are: PowerPoint Presentation YouTube Video Code Examples Algorithms and Representation Four concepts we explicitly or implicitly encounter while programming are problems, representations, algorithms and programs. Programs, of course, are instructions executed by the computer. Problems are what we try to solve when we write programs. Usually we do not go directly from problems to programs. Two intermediate steps are creating algorithms and identifying representations. Algorithms are sequences of steps to solve problems. So are programs. Thus, all programs are algorithms but the reverse is not true.
    [Show full text]
  • BALANCING the Eulisp METAOBJECT PROTOCOL
    LISP AND SYMBOLIC COMPUTATION An International Journal c Kluwer Academic Publishers Manufactured in The Netherlands Balancing the EuLisp Metaob ject Proto col y HARRY BRETTHAUER bretthauergmdde JURGEN KOPP koppgmdde German National Research Center for Computer Science GMD PO Box W Sankt Augustin FRG HARLEY DAVIS davisilogfr ILOG SA avenue Gal lieni Gentil ly France KEITH PLAYFORD kjpmathsbathacuk School of Mathematical Sciences University of Bath Bath BA AY UK Keywords Ob jectoriented Programming Language Design Abstract The challenge for the metaob ject proto col designer is to balance the con icting demands of eciency simplici ty and extensibil ity It is imp ossible to know all desired extensions in advance some of them will require greater functionality while oth ers require greater eciency In addition the proto col itself must b e suciently simple that it can b e fully do cumented and understo o d by those who need to use it This pap er presents the framework of a metaob ject proto col for EuLisp which provides expressiveness by a multileveled proto col and achieves eciency by static semantics for predened metaob jects and mo dularizin g their op erations The EuLisp mo dule system supp orts global optimizations of metaob ject applicati ons The metaob ject system itself is structured into mo dules taking into account the consequences for the compiler It provides introsp ective op erations as well as extension interfaces for various functionaliti es including new inheritance allo cation and slot access semantics While
    [Show full text]
  • Third Party Channels How to Set Them up – Pros and Cons
    Third Party Channels How to Set Them Up – Pros and Cons Steve Milo, Managing Director Vacation Rental Pros, Property Manager Cell: (904) 707.1487 [email protected] Company Summary • Business started in June, 2006 First employee hired in late 2007. • Today Manage 950 properties in North East Florida and South West Florida in resort ocean areas with mostly Saturday arrivals and/or Saturday departures and minimum stays (not urban). • Hub and Spoke Model. Central office is in Ponte Vedra Beach (Accounting, Sales & Marketing). Operations office in St Augustine Beach, Ft. Myers Beach and Orlando (model home). Total company wide - 69 employees (61 full time, 8 part time) • Acquired 3 companies in 2014. The PROS of AirBNB Free to list your properties. 3% fee per booking (they pay cc fee) Customer base is different & sticky – young, urban & foreign. Smaller properties book better than larger properties. Good generator of off-season bookings. Does not require Rate Parity. Can add fees to the rent. All bookings are direct online (no phone calls). You get to review the guest who stayed in your property. The Cons of AirBNB Labor intensive. Time consuming admin. 24 hour response. Not designed for larger property managers. Content & Prices are static (only calendar has data feed). Closed Communication (only through Airbnb). Customers want more hand holding, concierge type service. “Rate Terms” not easy. Only one minimum stay, No minimum age ability. No easy way to add fees (pets, damage waiver, booking fee). Need to add fees into nightly rates. Why Booking.com? Why not Booking.com? Owned by Priceline.
    [Show full text]
  • Abstract Data Types
    Chapter 2 Abstract Data Types The second idea at the core of computer science, along with algorithms, is data. In a modern computer, data consists fundamentally of binary bits, but meaningful data is organized into primitive data types such as integer, real, and boolean and into more complex data structures such as arrays and binary trees. These data types and data structures always come along with associated operations that can be done on the data. For example, the 32-bit int data type is defined both by the fact that a value of type int consists of 32 binary bits but also by the fact that two int values can be added, subtracted, multiplied, compared, and so on. An array is defined both by the fact that it is a sequence of data items of the same basic type, but also by the fact that it is possible to directly access each of the positions in the list based on its numerical index. So the idea of a data type includes a specification of the possible values of that type together with the operations that can be performed on those values. An algorithm is an abstract idea, and a program is an implementation of an algorithm. Similarly, it is useful to be able to work with the abstract idea behind a data type or data structure, without getting bogged down in the implementation details. The abstraction in this case is called an \abstract data type." An abstract data type specifies the values of the type, but not how those values are represented as collections of bits, and it specifies operations on those values in terms of their inputs, outputs, and effects rather than as particular algorithms or program code.
    [Show full text]
  • POINTER (IN C/C++) What Is a Pointer?
    POINTER (IN C/C++) What is a pointer? Variable in a program is something with a name, the value of which can vary. The way the compiler and linker handles this is that it assigns a specific block of memory within the computer to hold the value of that variable. • The left side is the value in memory. • The right side is the address of that memory Dereferencing: • int bar = *foo_ptr; • *foo_ptr = 42; // set foo to 42 which is also effect bar = 42 • To dereference ted, go to memory address of 1776, the value contain in that is 25 which is what we need. Differences between & and * & is the reference operator and can be read as "address of“ * is the dereference operator and can be read as "value pointed by" A variable referenced with & can be dereferenced with *. • Andy = 25; • Ted = &andy; All expressions below are true: • andy == 25 // true • &andy == 1776 // true • ted == 1776 // true • *ted == 25 // true How to declare pointer? • Type + “*” + name of variable. • Example: int * number; • char * c; • • number or c is a variable is called a pointer variable How to use pointer? • int foo; • int *foo_ptr = &foo; • foo_ptr is declared as a pointer to int. We have initialized it to point to foo. • foo occupies some memory. Its location in memory is called its address. &foo is the address of foo Assignment and pointer: • int *foo_pr = 5; // wrong • int foo = 5; • int *foo_pr = &foo; // correct way Change the pointer to the next memory block: • int foo = 5; • int *foo_pr = &foo; • foo_pr ++; Pointer arithmetics • char *mychar; // sizeof 1 byte • short *myshort; // sizeof 2 bytes • long *mylong; // sizeof 4 byts • mychar++; // increase by 1 byte • myshort++; // increase by 2 bytes • mylong++; // increase by 4 bytes Increase pointer is different from increase the dereference • *P++; // unary operation: go to the address of the pointer then increase its address and return a value • (*P)++; // get the value from the address of p then increase the value by 1 Arrays: • int array[] = {45,46,47}; • we can call the first element in the array by saying: *array or array[0].
    [Show full text]
  • Signedness-Agnostic Program Analysis: Precise Integer Bounds for Low-Level Code
    Signedness-Agnostic Program Analysis: Precise Integer Bounds for Low-Level Code Jorge A. Navas, Peter Schachte, Harald Søndergaard, and Peter J. Stuckey Department of Computing and Information Systems, The University of Melbourne, Victoria 3010, Australia Abstract. Many compilers target common back-ends, thereby avoid- ing the need to implement the same analyses for many different source languages. This has led to interest in static analysis of LLVM code. In LLVM (and similar languages) most signedness information associated with variables has been compiled away. Current analyses of LLVM code tend to assume that either all values are signed or all are unsigned (except where the code specifies the signedness). We show how program analysis can simultaneously consider each bit-string to be both signed and un- signed, thus improving precision, and we implement the idea for the spe- cific case of integer bounds analysis. Experimental evaluation shows that this provides higher precision at little extra cost. Our approach turns out to be beneficial even when all signedness information is available, such as when analysing C or Java code. 1 Introduction The “Low Level Virtual Machine” LLVM is rapidly gaining popularity as a target for compilers for a range of programming languages. As a result, the literature on static analysis of LLVM code is growing (for example, see [2, 7, 9, 11, 12]). LLVM IR (Intermediate Representation) carefully specifies the bit- width of all integer values, but in most cases does not specify whether values are signed or unsigned. This is because, for most operations, two’s complement arithmetic (treating the inputs as signed numbers) produces the same bit-vectors as unsigned arithmetic.
    [Show full text]
  • Metaclasses: Generative C++
    Metaclasses: Generative C++ Document Number: P0707 R3 Date: 2018-02-11 Reply-to: Herb Sutter ([email protected]) Audience: SG7, EWG Contents 1 Overview .............................................................................................................................................................2 2 Language: Metaclasses .......................................................................................................................................7 3 Library: Example metaclasses .......................................................................................................................... 18 4 Applying metaclasses: Qt moc and C++/WinRT .............................................................................................. 35 5 Alternatives for sourcedefinition transform syntax .................................................................................... 41 6 Alternatives for applying the transform .......................................................................................................... 43 7 FAQs ................................................................................................................................................................. 46 8 Revision history ............................................................................................................................................... 51 Major changes in R3: Switched to function-style declaration syntax per SG7 direction in Albuquerque (old: $class M new: constexpr void M(meta::type target,
    [Show full text]
  • 4 Hash Tables and Associative Arrays
    4 FREE Hash Tables and Associative Arrays If you want to get a book from the central library of the University of Karlsruhe, you have to order the book in advance. The library personnel fetch the book from the stacks and deliver it to a room with 100 shelves. You find your book on a shelf numbered with the last two digits of your library card. Why the last digits and not the leading digits? Probably because this distributes the books more evenly among the shelves. The library cards are numbered consecutively as students sign up, and the University of Karlsruhe was founded in 1825. Therefore, the students enrolled at the same time are likely to have the same leading digits in their card number, and only a few shelves would be in use if the leadingCOPY digits were used. The subject of this chapter is the robust and efficient implementation of the above “delivery shelf data structure”. In computer science, this data structure is known as a hash1 table. Hash tables are one implementation of associative arrays, or dictio- naries. The other implementation is the tree data structures which we shall study in Chap. 7. An associative array is an array with a potentially infinite or at least very large index set, out of which only a small number of indices are actually in use. For example, the potential indices may be all strings, and the indices in use may be all identifiers used in a particular C++ program.Or the potential indices may be all ways of placing chess pieces on a chess board, and the indices in use may be the place- ments required in the analysis of a particular game.
    [Show full text]
  • RICH: Automatically Protecting Against Integer-Based Vulnerabilities
    RICH: Automatically Protecting Against Integer-Based Vulnerabilities David Brumley, Tzi-cker Chiueh, Robert Johnson [email protected], [email protected], [email protected] Huijia Lin, Dawn Song [email protected], [email protected] Abstract against integer-based attacks. Integer bugs appear because programmers do not antici- We present the design and implementation of RICH pate the semantics of C operations. The C99 standard [16] (Run-time Integer CHecking), a tool for efficiently detecting defines about a dozen rules governinghow integer types can integer-based attacks against C programs at run time. C be cast or promoted. The standard allows several common integer bugs, a popular avenue of attack and frequent pro- cases, such as many types of down-casting, to be compiler- gramming error [1–15], occur when a variable value goes implementation specific. In addition, the written rules are out of the range of the machine word used to materialize it, not accompanied by an unambiguous set of formal rules, e.g. when assigning a large 32-bit int to a 16-bit short. making it difficult for a programmer to verify that he un- We show that safe and unsafe integer operations in C can derstands C99 correctly. Integer bugs are not exclusive to be captured by well-known sub-typing theory. The RICH C. Similar languages such as C++, and even type-safe lan- compiler extension compiles C programs to object code that guages such as Java and OCaml, do not raise exceptions on monitors its own execution to detect integer-based attacks.
    [Show full text]
  • A Metaobject Protocol for Fault-Tolerant CORBA Applications
    A Metaobject Protocol for Fault-Tolerant CORBA Applications Marc-Olivier Killijian*, Jean-Charles Fabre*, Juan-Carlos Ruiz-Garcia*, Shigeru Chiba** *LAAS-CNRS, 7 Avenue du Colonel Roche **Institute of Information Science and 31077 Toulouse cedex, France Electronics, University of Tsukuba, Tennodai, Tsukuba, Ibaraki 305-8573, Japan Abstract The corner stone of a fault-tolerant reflective The use of metalevel architectures for the architecture is the MOP. We thus propose a special implementation of fault-tolerant systems is today very purpose MOP to address the problems of general-purpose appealing. Nevertheless, all such fault-tolerant systems ones. We show that compile-time reflection is a good have used a general-purpose metaobject protocol (MOP) approach for developing a specialized runtime MOP. or are based on restricted reflective features of some The definition and the implementation of an object-oriented language. According to our past appropriate runtime metaobject protocol for implementing experience, we define in this paper a suitable metaobject fault tolerance into CORBA applications is the main protocol, called FT-MOP for building fault-tolerant contribution of the work reported in this paper. This systems. We explain how to realize a specialized runtime MOP, called FT-MOP (Fault Tolerance - MetaObject MOP using compile-time reflection. This MOP is CORBA Protocol), is sufficiently general to be used for other aims compliant: it enables the execution and the state evolution (mobility, adaptability, migration, security). FT-MOP of CORBA objects to be controlled and enables the fault provides a mean to attach dynamically fault tolerance tolerance metalevel to be developed as CORBA software. strategies to CORBA objects as CORBA metaobjects, enabling thus these strategies to be implemented as 1 .
    [Show full text]