Home | History | Annotate | Download | only in Orc
      1 //===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
     11 #include "llvm/ExecutionEngine/Orc/RPCUtils.h"
     12 #include "gtest/gtest.h"
     13 
     14 #include <queue>
     15 
     16 using namespace llvm;
     17 using namespace llvm::orc;
     18 using namespace llvm::orc::remote;
     19 
     20 class Queue : public std::queue<char> {
     21 public:
     22   std::mutex &getLock() { return Lock; }
     23 
     24 private:
     25   std::mutex Lock;
     26 };
     27 
     28 class QueueChannel : public RPCChannel {
     29 public:
     30   QueueChannel(Queue &InQueue, Queue &OutQueue)
     31       : InQueue(InQueue), OutQueue(OutQueue) {}
     32 
     33   Error readBytes(char *Dst, unsigned Size) override {
     34     while (Size != 0) {
     35       // If there's nothing to read then yield.
     36       while (InQueue.empty())
     37         std::this_thread::yield();
     38 
     39       // Lock the channel and read what we can.
     40       std::lock_guard<std::mutex> Lock(InQueue.getLock());
     41       while (!InQueue.empty() && Size) {
     42         *Dst++ = InQueue.front();
     43         --Size;
     44         InQueue.pop();
     45       }
     46     }
     47     return Error::success();
     48   }
     49 
     50   Error appendBytes(const char *Src, unsigned Size) override {
     51     std::lock_guard<std::mutex> Lock(OutQueue.getLock());
     52     while (Size--)
     53       OutQueue.push(*Src++);
     54     return Error::success();
     55   }
     56 
     57   Error send() override { return Error::success(); }
     58 
     59 private:
     60   Queue &InQueue;
     61   Queue &OutQueue;
     62 };
     63 
     64 class DummyRPC : public testing::Test, public RPC<QueueChannel> {
     65 public:
     66   enum FuncId : uint32_t {
     67     VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId,
     68     IntIntId,
     69     AllTheTypesId
     70   };
     71 
     72   typedef Function<VoidBoolId, void(bool)> VoidBool;
     73   typedef Function<IntIntId, int32_t(int32_t)> IntInt;
     74   typedef Function<AllTheTypesId,
     75                    void(int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
     76                         int64_t, uint64_t, bool, std::string, std::vector<int>)>
     77       AllTheTypes;
     78 };
     79 
     80 TEST_F(DummyRPC, TestAsyncVoidBool) {
     81   Queue Q1, Q2;
     82   QueueChannel C1(Q1, Q2);
     83   QueueChannel C2(Q2, Q1);
     84 
     85   // Make an async call.
     86   auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true);
     87   EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
     88 
     89   {
     90     // Expect a call to Proc1.
     91     auto EC = expect<VoidBool>(C2, [&](bool &B) {
     92       EXPECT_EQ(B, true) << "Bool serialization broken";
     93       return Error::success();
     94     });
     95     EXPECT_FALSE(EC) << "Simple expect over queue failed";
     96   }
     97 
     98   {
     99     // Wait for the result.
    100     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
    101     EXPECT_FALSE(EC) << "Could not read result.";
    102   }
    103 
    104   // Verify that the function returned ok.
    105   auto Val = ResOrErr->first.get();
    106   EXPECT_TRUE(Val) << "Remote void function failed to execute.";
    107 }
    108 
    109 TEST_F(DummyRPC, TestAsyncIntInt) {
    110   Queue Q1, Q2;
    111   QueueChannel C1(Q1, Q2);
    112   QueueChannel C2(Q2, Q1);
    113 
    114   // Make an async call.
    115   auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21);
    116   EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
    117 
    118   {
    119     // Expect a call to Proc1.
    120     auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> {
    121       EXPECT_EQ(I, 21) << "Bool serialization broken";
    122       return 2 * I;
    123     });
    124     EXPECT_FALSE(EC) << "Simple expect over queue failed";
    125   }
    126 
    127   {
    128     // Wait for the result.
    129     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
    130     EXPECT_FALSE(EC) << "Could not read result.";
    131   }
    132 
    133   // Verify that the function returned ok.
    134   auto Val = ResOrErr->first.get();
    135   EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
    136   EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
    137 }
    138 
    139 TEST_F(DummyRPC, TestSerialization) {
    140   Queue Q1, Q2;
    141   QueueChannel C1(Q1, Q2);
    142   QueueChannel C2(Q2, Q1);
    143 
    144   // Make a call to Proc1.
    145   std::vector<int> v({42, 7});
    146   auto ResOrErr = callAsyncWithSeq<AllTheTypes>(
    147       C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000,
    148       10000000000, true, "foo", v);
    149   EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed";
    150 
    151   {
    152     // Expect a call to Proc1.
    153     auto EC = expect<AllTheTypes>(
    154         C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16,
    155                 int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t &u64,
    156                 bool &b, std::string &s, std::vector<int> &v) {
    157 
    158           EXPECT_EQ(s8, -101) << "int8_t serialization broken";
    159           EXPECT_EQ(u8, 250) << "uint8_t serialization broken";
    160           EXPECT_EQ(s16, -10000) << "int16_t serialization broken";
    161           EXPECT_EQ(u16, 10000) << "uint16_t serialization broken";
    162           EXPECT_EQ(s32, -1000000000) << "int32_t serialization broken";
    163           EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization broken";
    164           EXPECT_EQ(s64, -10000000000) << "int64_t serialization broken";
    165           EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization broken";
    166           EXPECT_EQ(b, true) << "bool serialization broken";
    167           EXPECT_EQ(s, "foo") << "std::string serialization broken";
    168           EXPECT_EQ(v, std::vector<int>({42, 7}))
    169               << "std::vector serialization broken";
    170           return Error::success();
    171         });
    172     EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
    173   }
    174 
    175   {
    176     // Wait for the result.
    177     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
    178     EXPECT_FALSE(EC) << "Could not read result.";
    179   }
    180 
    181   // Verify that the function returned ok.
    182   auto Val = ResOrErr->first.get();
    183   EXPECT_TRUE(Val) << "Remote void function failed to execute.";
    184 }
    185 
    186 // Test the synchronous call API.
    187 // FIXME: Re-enable once deadlock encountered on S390 has been debugged / fixed,
    188 //        see http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/3459
    189 // TEST_F(DummyRPC, TestSynchronousCall) {
    190 //   Queue Q1, Q2;
    191 //   QueueChannel C1(Q1, Q2);
    192 //   QueueChannel C2(Q2, Q1);
    193 //
    194 //   auto ServerResult =
    195 //     std::async(std::launch::async,
    196 //       [&]() {
    197 //         return expect<IntInt>(C2, [&](int32_t V) { return V; });
    198 //       });
    199 //
    200 //   auto ValOrErr = callST<IntInt>(C1, 42);
    201 //
    202 //   EXPECT_FALSE(!!ServerResult.get())
    203 //     << "Server returned an error.";
    204 //   EXPECT_TRUE(!!ValOrErr)
    205 //     << "callST returned an error.";
    206 //   EXPECT_EQ(*ValOrErr, 42)
    207 //     << "Incorrect callST<IntInt> result";
    208 // }
    209