<commit_before>// Copyright 2020 The TensorFlow Runtime Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//===- event_manager_test.cc ------------------------------------*- C++ -*-===//
//
// Unit test for GPU EventManager
//
//===----------------------------------------------------------------------===//
#include "tfrt/gpu/event_manager.h"

#include <math.h>

#include <cstring>
#include <ostream>

#include "benchmark/benchmark.h"
#include "gtest/gtest.h"
#include "tfrt/cpp_tests/error_util.h"
#include "tfrt/gpu/stream/stream_wrapper.h"
#include "tfrt/support/latch.h"
#include "tfrt/support/logging.h"
#include "tfrt/support/thread_annotations.h"

namespace tfrt {
namespace gpu {
namespace stream {

struct StreamAndBuffers {
  StreamAndBuffers(CurrentContext current, size_t size) : size(size) {
    TFRT_ASSIGN_OR_DIE(stream, StreamCreate(current, StreamFlags::DEFAULT));
    TFRT_ASSIGN_OR_DIE(gpu_buf, MemAlloc(current, size));
    TFRT_ASSIGN_OR_DIE(host_buf_src,
                       MemHostAlloc(current, size, MemHostAllocFlags::DEFAULT));
    TFRT_ASSIGN_OR_DIE(host_buf_dst,
                       MemHostAlloc(current, size, MemHostAllocFlags::DEFAULT));
    std::memset(host_buf_src.get().raw(), 'z', size);
    std::memset(host_buf_dst.get().raw(), 0, size);
  }

  void H2D(CurrentContext current, Event event) {
    EXPECT_TRUE(
        IsSuccess(MemcpyAsync(current, /*dst=*/gpu_buf.get(),
                              /*src=*/host_buf_src.get(), size, stream.get())));
    EXPECT_TRUE(IsSuccess(EventRecord(event, stream.get())));
  }

  void D2H(CurrentContext current, Event event) {
    EXPECT_TRUE(
        IsSuccess(MemcpyAsync(current, /*dst=*/host_buf_dst.get(),
                              /*src=*/gpu_buf.get(), size, stream.get())));
    EXPECT_TRUE(IsSuccess(EventRecord(event, stream.get())));
  }

  void CheckBuffersEqual() {
    EXPECT_EQ(0, std::memcmp(host_buf_dst.get().raw(), host_buf_src.get().raw(),
                             size));
  }

  void ResetHostBuffers() {
    std::memset(host_buf_src.get().raw(), 'z', size);
    std::memset(host_buf_dst.get().raw(), 0, size);
  }

  size_t size;
  OwningStream stream;
  DeviceMemory<void> gpu_buf;
  HostMemory<void> host_buf_src;
  HostMemory<void> host_buf_dst;
};

class EventManagerTest : public ::testing::Test {
 protected:
  EventManagerTest() : platform_(Platform::CUDA) {}
  void SetUp() override {
    ASSERT_TRUE(IsSuccess(Init(platform_)));
    TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform_));
    ASSERT_GT(count, 0);
    TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform_, 0));
    TFRT_ASSERT_AND_ASSIGN(context_, DevicePrimaryCtxRetain(device));
  }

  // Use 32 MB for copies so that they usually don't complete immediately.
  const size_t kBufferSize = 32 << 20;

  Platform platform_;
  OwningContext context_;
};

TEST_F(EventManagerTest, TestOneStreamOneEvent) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb.H2D(current, event.get());
  sb.D2H(current, event.get());

  latch latch(1);
  manager.Synchronize(event.get(), sb.stream.get(),
                      [&latch, &sb](llvm::Error error) {
                        sb.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestOneStreamTwoEvents) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb.H2D(current, event1.get());
  sb.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(event1.get(), sb.stream.get(),
                      [&latch](llvm::Error error) { latch.count_down(); });
  manager.Synchronize(event2.get(), sb.stream.get(),
                      [&latch, &sb](llvm::Error error) {
                        sb.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestOneStreamTwoEventsOneByOne) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  {
    TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                           EventCreate(current, EventFlags::DISABLE_TIMING));

    sb.H2D(current, event.get());
    sb.D2H(current, event.get());

    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch, &sb](llvm::Error error) {
                          sb.CheckBuffersEqual();
                          latch.count_down();
                        });
    latch.wait();
  }
  {
    sb.ResetHostBuffers();
    TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                           EventCreate(current, EventFlags::DISABLE_TIMING));

    sb.H2D(current, event.get());
    sb.D2H(current, event.get());

    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch, &sb](llvm::Error error) {
                          sb.CheckBuffersEqual();
                          latch.count_down();
                        });
    latch.wait();
  }
}

TEST_F(EventManagerTest, TestTwoStreamsTwoEvents) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb2.H2D(current, event2.get());
  sb1.D2H(current, event1.get());
  sb2.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(event1.get(), sb1.stream.get(),
                      [&latch, &sb1](llvm::Error error) {
                        sb1.CheckBuffersEqual();
                        latch.count_down();
                      });
  manager.Synchronize(event2.get(), sb2.stream.get(),
                      [&latch, &sb2](llvm::Error error) {
                        sb2.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestStealing) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb1.D2H(current, event1.get());

  latch latch1(1);
  manager.Synchronize(event1.get(), sb1.stream.get(),
                      [&latch1, &sb1](llvm::Error error) {
                        sb1.CheckBuffersEqual();
                        latch1.count_down();
                      });
  latch1.wait();

  // stream in sb1 should be idle now. Synchronizing event with stream in
  // sb2 should now steal the thread.

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb2.H2D(current, event2.get());
  sb2.D2H(current, event2.get());

  latch latch2(1);
  manager.Synchronize(event2.get(), sb2.stream.get(),
                      [&latch2, &sb2](llvm::Error error) {
                        sb2.CheckBuffersEqual();
                        latch2.count_down();
                      });
  latch2.wait();
}

TEST_F(EventManagerTest, TestCallSynchronizeFromOnReached) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb1.D2H(current, event1.get());
  sb2.H2D(current, event2.get());
  sb2.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(
      event1.get(), sb1.stream.get(),
      [&latch, &sb1, &manager, &event2, &sb2](llvm::Error error) {
        sb1.CheckBuffersEqual();
        latch.count_down();
        manager.Synchronize(event2.get(), sb2.stream.get(),
                            [&latch, &sb2](llvm::Error error) {
                              sb2.CheckBuffersEqual();
                              latch.count_down();
                            });
      });
  latch.wait();
}

void BM_EventEnqueue(benchmark::State& state) {
  Platform platform(Platform::CUDA);
  ASSERT_TRUE(IsSuccess(Init(platform)));
  TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform));
  ASSERT_GT(count, 0);
  TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform, 0));
  TFRT_ASSERT_AND_ASSIGN(auto context, DevicePrimaryCtxRetain(device));
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context.get()));

  EventManager manager;

  StreamAndBuffers sb(current, /*size=*/4);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  {
    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch](llvm::Error error) { latch.count_down(); });
    latch.wait();
  }
  for (auto _ : state) {
    manager.Synchronize(event.get(), sb.stream.get(), [](llvm::Error error) {
      TFRT_LOG_IF(FATAL, error.success())
          << "Hit an error in calback: " << error;
    });
  }
  {
    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch](llvm::Error error) { latch.count_down(); });
    latch.wait();
  }
}
BENCHMARK(BM_EventEnqueue);

}  // namespace stream
}  // namespace gpu
}  // namespace tfrt
<commit_msg>Add non-trivial benchmark to event_manager_test.<commit_after>// Copyright 2020 The TensorFlow Runtime Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//===- event_manager_test.cc ------------------------------------*- C++ -*-===//
//
// Unit test for GPU EventManager
//
//===----------------------------------------------------------------------===//
#include "tfrt/gpu/event_manager.h"

#include <math.h>

#include <cstring>
#include <ostream>

#include "benchmark/benchmark.h"
#include "gtest/gtest.h"
#include "tfrt/cpp_tests/error_util.h"
#include "tfrt/gpu/stream/stream_wrapper.h"
#include "tfrt/support/latch.h"
#include "tfrt/support/logging.h"
#include "tfrt/support/thread_annotations.h"

namespace tfrt {
namespace gpu {
namespace stream {

struct StreamAndBuffers {
  StreamAndBuffers(CurrentContext current, size_t size) : size(size) {
    TFRT_ASSIGN_OR_DIE(stream, StreamCreate(current, StreamFlags::DEFAULT));
    TFRT_ASSIGN_OR_DIE(gpu_buf, MemAlloc(current, size));
    TFRT_ASSIGN_OR_DIE(host_buf_src,
                       MemHostAlloc(current, size, MemHostAllocFlags::DEFAULT));
    TFRT_ASSIGN_OR_DIE(host_buf_dst,
                       MemHostAlloc(current, size, MemHostAllocFlags::DEFAULT));
    std::memset(host_buf_src.get().raw(), 'z', size);
    std::memset(host_buf_dst.get().raw(), 0, size);
  }

  void H2D(CurrentContext current, Event event) {
    EXPECT_TRUE(
        IsSuccess(MemcpyAsync(current, /*dst=*/gpu_buf.get(),
                              /*src=*/host_buf_src.get(), size, stream.get())));
    EXPECT_TRUE(IsSuccess(EventRecord(event, stream.get())));
  }

  void D2H(CurrentContext current, Event event) {
    EXPECT_TRUE(
        IsSuccess(MemcpyAsync(current, /*dst=*/host_buf_dst.get(),
                              /*src=*/gpu_buf.get(), size, stream.get())));
    EXPECT_TRUE(IsSuccess(EventRecord(event, stream.get())));
  }

  void CheckBuffersEqual() {
    EXPECT_EQ(0, std::memcmp(host_buf_dst.get().raw(), host_buf_src.get().raw(),
                             size));
  }

  void ResetHostBuffers() {
    std::memset(host_buf_src.get().raw(), 'z', size);
    std::memset(host_buf_dst.get().raw(), 0, size);
  }

  size_t size;
  OwningStream stream;
  DeviceMemory<void> gpu_buf;
  HostMemory<void> host_buf_src;
  HostMemory<void> host_buf_dst;
};

class EventManagerTest : public ::testing::Test {
 protected:
  EventManagerTest() : platform_(Platform::CUDA) {}
  void SetUp() override {
    ASSERT_TRUE(IsSuccess(Init(platform_)));
    TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform_));
    ASSERT_GT(count, 0);
    TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform_, 0));
    TFRT_ASSERT_AND_ASSIGN(context_, DevicePrimaryCtxRetain(device));
  }

  // Use 32 MB for copies so that they usually don't complete immediately.
  const size_t kBufferSize = 32 << 20;

  Platform platform_;
  OwningContext context_;
};

TEST_F(EventManagerTest, TestOneStreamOneEvent) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb.H2D(current, event.get());
  sb.D2H(current, event.get());

  latch latch(1);
  manager.Synchronize(event.get(), sb.stream.get(),
                      [&latch, &sb](llvm::Error error) {
                        sb.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestOneStreamTwoEvents) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb.H2D(current, event1.get());
  sb.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(event1.get(), sb.stream.get(),
                      [&latch](llvm::Error error) { latch.count_down(); });
  manager.Synchronize(event2.get(), sb.stream.get(),
                      [&latch, &sb](llvm::Error error) {
                        sb.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestOneStreamTwoEventsOneByOne) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb(current, kBufferSize);
  {
    TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                           EventCreate(current, EventFlags::DISABLE_TIMING));

    sb.H2D(current, event.get());
    sb.D2H(current, event.get());

    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch, &sb](llvm::Error error) {
                          sb.CheckBuffersEqual();
                          latch.count_down();
                        });
    latch.wait();
  }
  {
    sb.ResetHostBuffers();
    TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                           EventCreate(current, EventFlags::DISABLE_TIMING));

    sb.H2D(current, event.get());
    sb.D2H(current, event.get());

    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch, &sb](llvm::Error error) {
                          sb.CheckBuffersEqual();
                          latch.count_down();
                        });
    latch.wait();
  }
}

TEST_F(EventManagerTest, TestTwoStreamsTwoEvents) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb2.H2D(current, event2.get());
  sb1.D2H(current, event1.get());
  sb2.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(event1.get(), sb1.stream.get(),
                      [&latch, &sb1](llvm::Error error) {
                        sb1.CheckBuffersEqual();
                        latch.count_down();
                      });
  manager.Synchronize(event2.get(), sb2.stream.get(),
                      [&latch, &sb2](llvm::Error error) {
                        sb2.CheckBuffersEqual();
                        latch.count_down();
                      });
  latch.wait();
}

TEST_F(EventManagerTest, TestStealing) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb1.D2H(current, event1.get());

  latch latch1(1);
  manager.Synchronize(event1.get(), sb1.stream.get(),
                      [&latch1, &sb1](llvm::Error error) {
                        sb1.CheckBuffersEqual();
                        latch1.count_down();
                      });
  latch1.wait();

  // stream in sb1 should be idle now. Synchronizing event with stream in
  // sb2 should now steal the thread.

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb2.H2D(current, event2.get());
  sb2.D2H(current, event2.get());

  latch latch2(1);
  manager.Synchronize(event2.get(), sb2.stream.get(),
                      [&latch2, &sb2](llvm::Error error) {
                        sb2.CheckBuffersEqual();
                        latch2.count_down();
                      });
  latch2.wait();
}

TEST_F(EventManagerTest, TestCallSynchronizeFromOnReached) {
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context_.get()));

  EventManager manager;

  StreamAndBuffers sb1(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event1,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  StreamAndBuffers sb2(current, kBufferSize);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event2,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  sb1.H2D(current, event1.get());
  sb1.D2H(current, event1.get());
  sb2.H2D(current, event2.get());
  sb2.D2H(current, event2.get());

  latch latch(2);
  manager.Synchronize(
      event1.get(), sb1.stream.get(),
      [&latch, &sb1, &manager, &event2, &sb2](llvm::Error error) {
        sb1.CheckBuffersEqual();
        latch.count_down();
        manager.Synchronize(event2.get(), sb2.stream.get(),
                            [&latch, &sb2](llvm::Error error) {
                              sb2.CheckBuffersEqual();
                              latch.count_down();
                            });
      });
  latch.wait();
}

void BM_EventEnqueue(benchmark::State& state) {
  Platform platform(Platform::CUDA);
  ASSERT_TRUE(IsSuccess(Init(platform)));
  TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform));
  ASSERT_GT(count, 0);
  TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform, 0));
  TFRT_ASSERT_AND_ASSIGN(auto context, DevicePrimaryCtxRetain(device));
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context.get()));

  EventManager manager;

  StreamAndBuffers sb(current, /*size=*/4);
  TFRT_ASSERT_AND_ASSIGN(OwningEvent event,
                         EventCreate(current, EventFlags::DISABLE_TIMING));

  {
    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch](llvm::Error error) { latch.count_down(); });
    latch.wait();
  }
  for (auto _ : state) {
    manager.Synchronize(event.get(), sb.stream.get(), [](llvm::Error error) {
      TFRT_LOG_IF(FATAL, error.success())
          << "Hit an error in calback: " << error;
    });
  }
  {
    latch latch(1);
    manager.Synchronize(event.get(), sb.stream.get(),
                        [&latch](llvm::Error error) { latch.count_down(); });
    latch.wait();
  }
}

void BM_ManyThreadsManyStreams(benchmark::State& state) {
  Platform platform(Platform::CUDA);
  ASSERT_TRUE(IsSuccess(Init(platform)));
  TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform));
  ASSERT_GT(count, 0);
  TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform, 0));
  TFRT_ASSERT_AND_ASSIGN(auto context, DevicePrimaryCtxRetain(device));
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context.get()));

  const int thread_count = state.range(0);
  const size_t size = state.range(1);
  EventManager manager;

  std::vector<StreamAndBuffers> sb;
  sb.reserve(thread_count);
  for (int i = 0; i < thread_count; ++i) {
    sb.emplace_back(current, size);
  }
  std::vector<OwningEvent> events(thread_count);
  std::generate(events.begin(), events.end(), [&] {
    return std::move(*EventCreate(current, EventFlags::DISABLE_TIMING));
  });

  for (auto _ : state) {
    latch latch(thread_count);
    for (int i = 0; i < thread_count; ++i) {
      sb[i].H2D(current, events[i].get());
    }
    for (int i = 0; i < thread_count; ++i) {
      manager.Synchronize(events[i].get(), sb[i].stream.get(),
                          [&latch](llvm::Error error) { latch.count_down(); });
    }
    latch.wait();
  }
}

void BM_MultipleEventsPerStream(benchmark::State& state) {
  Platform platform(Platform::CUDA);
  ASSERT_TRUE(IsSuccess(Init(platform)));
  TFRT_ASSERT_AND_ASSIGN(auto count, DeviceGetCount(platform));
  ASSERT_GT(count, 0);
  TFRT_ASSERT_AND_ASSIGN(auto device, DeviceGet(platform, 0));
  TFRT_ASSERT_AND_ASSIGN(auto context, DevicePrimaryCtxRetain(device));
  TFRT_ASSERT_AND_ASSIGN(auto current, CtxSetCurrent(context.get()));

  const int thread_count = state.range(0);
  const int events_per_stream = state.range(1);
  EventManager manager;

  std::vector<StreamAndBuffers> sb;
  sb.reserve(thread_count);
  for (int i = 0; i < thread_count; ++i) {
    sb.emplace_back(current, /*size=*/8192);
  }

  std::vector<OwningEvent> events(thread_count * events_per_stream);
  std::generate(events.begin(), events.end(), [&] {
    return std::move(*EventCreate(current, EventFlags::DISABLE_TIMING));
  });

  for (auto _ : state) {
    latch latch(thread_count * events_per_stream);
    for (int j = 0; j < events_per_stream; ++j) {
      for (int i = 0; i < thread_count; ++i) {
        sb[i].H2D(current, events[i * events_per_stream + j].get());
      }
    }
    for (int i = 0; i < thread_count; ++i) {
      for (int j = 0; j < events_per_stream; ++j) {
        manager.Synchronize(
            events[i * events_per_stream + j].get(), sb[i].stream.get(),
            [&latch](llvm::Error error) { latch.count_down(); });
      }
    }
    latch.wait();
  }
}

BENCHMARK(BM_EventEnqueue);
BENCHMARK(BM_ManyThreadsManyStreams)->RangePair(1, 32, 4, 32 << 20);
BENCHMARK(BM_MultipleEventsPerStream)->RangePair(1, 32, 2, 32);

}  // namespace stream
}  // namespace gpu
}  // namespace tfrt
<|endoftext|>


<commit_before>#ifndef MLT_MODELS_PIPELINE_HPP
#define MLT_MODELS_PIPELINE_HPP

#include <Eigen/Core>

#include "transformers/transformer_mixin.hpp"

namespace mlt {
namespace models {

	// Forward declaration
	template <class... Ts>
	class Pipeline {
	};

namespace internal {
	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element;

	template<size_t _Index>
	struct sub_pipeline_element<_Index, Pipeline<> >
	{
		static_assert(std::_Always_false<std::integral_constant<size_t, _Index> >::value, "pipeline index out of bounds");
	};

	template<class _This, class... _Rest>
	struct sub_pipeline_element<0, Pipeline<_This, _Rest...> >
	{
		typedef _This model_type;
		typedef Pipeline<_This, _Rest...> type;
	};

	template<size_t _Index, class _This, class... _Rest>
	struct sub_pipeline_element<_Index, Pipeline<_This, _Rest...> >
		: public sub_pipeline_element<_Index - 1, Pipeline<_Rest...> >
	{};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, const _Pipline>
		: public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_const<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_const<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, volatile _Pipline> : public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_volatile<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_volatile<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, const volatile _Pipline> : public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_cv<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_cv<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};
}
	template<>
	class Pipeline<> {
		Pipeline() = delete;
	};

	template <class T>
	class Pipeline<T> : public T {
	public:
		explicit Pipeline(T& estimator) : T(estimator) {}

		template<size_t _Index>
		using pipeline_model_t = typename internal::sub_pipeline_element<_Index, Pipeline<T>>::model_type;

		template<size_t _Index>
		using sub_pipeline_t = typename internal::sub_pipeline_element<_Index, Pipeline<T>>::type;

		T& top_estimator() { return *this; }

		template<size_t Index>
		inline sub_pipeline_t<Index>& get()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this);
		}

		template<size_t Index>
		inline typename pipeline_model_t<Index>& get_model()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this).top_estimator();
		}

	protected:

	};

	template <class T, class... Ts>
	class Pipeline<T, Ts...> : protected Pipeline<Ts...>, public transformers::TransformerMixin<Pipeline<T, Ts...>> {
	public:
		explicit Pipeline(T& estimator, Ts & ... following) : Pipeline<Ts...>(following...), _estimator(estimator) {}

		template<size_t _Index>
		using pipeline_model_t = typename internal::sub_pipeline_element<_Index, Pipeline<T, Ts...>>::model_type;

		template<size_t _Index>
		using sub_pipeline_t = typename internal::sub_pipeline_element<_Index, Pipeline<T, Ts...>>::type;

		Pipeline<T, Ts...>& fit(const Eigen::MatrixXd& input, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, cold_start), cold_start);
			return *this;
		}

		Pipeline<T, Ts...>& fit(const Eigen::MatrixXd& input, const Eigen::MatrixXd& target, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, target, cold_start), target, cold_start);
			return *this;
		}

		Pipeline<T, Ts...>& fit(const Eigen::MatrixXd& input, const Eigen::MatrixXi& classes, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, classes, cold_start), classes, cold_start);
			return *this;
		}

		Eigen::MatrixXd transform(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::transform(_estimator.transform(input));
		}

		Eigen::MatrixXi classify(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::classify(_estimator.transform(input));
		}

		Eigen::MatrixXd predict(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::predict(_estimator.transform(input));
		}

		Eigen::MatrixXi cluster(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::cluster(_estimator.transform(input));
		}

		T& top_estimator() { return _estimator; }

		template<size_t Index>
		inline sub_pipeline_t<Index>& get()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this);
		}

		template<size_t Index>
		inline typename pipeline_model_t<Index>& get_model()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this).top_estimator();
		}
	protected:
		T& _estimator;
	};

	template <class... Ts>
	Pipeline<Ts...> create_pipeline(Ts & ... models) {
		return Pipeline<Ts...>(models...);
	}
}
}
#endif<commit_msg>Added score to pipeline and fixed Matrix References<commit_after>#ifndef MLT_MODELS_PIPELINE_HPP
#define MLT_MODELS_PIPELINE_HPP

#include <Eigen/Core>

#include "transformers/transformer_mixin.hpp"

namespace mlt {
namespace models {

	// Forward declaration
	template <class... Ts>
	class Pipeline {
	};

namespace internal {
	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element;

	template<size_t _Index>
	struct sub_pipeline_element<_Index, Pipeline<> >
	{
		static_assert(std::_Always_false<std::integral_constant<size_t, _Index> >::value, "pipeline index out of bounds");
	};

	template<class _This, class... _Rest>
	struct sub_pipeline_element<0, Pipeline<_This, _Rest...> >
	{
		typedef _This model_type;
		typedef Pipeline<_This, _Rest...> type;
	};

	template<size_t _Index, class _This, class... _Rest>
	struct sub_pipeline_element<_Index, Pipeline<_This, _Rest...> >
		: public sub_pipeline_element<_Index - 1, Pipeline<_Rest...> >
	{};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, const _Pipline>
		: public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_const<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_const<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, volatile _Pipline> : public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_volatile<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_volatile<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};

	template<size_t _Index, class _Pipline>
	struct sub_pipeline_element<_Index, const volatile _Pipline> : public sub_pipeline_element<_Index, _Pipline>
	{
		typedef typename std::add_cv<typename sub_pipeline_element<_Index, _Pipline>::model_type>::type model_type;
		typedef typename std::add_cv<typename sub_pipeline_element<_Index, _Pipline>::type>::type type;
	};
}
	template<>
	class Pipeline<> {
		Pipeline() = delete;
	};

	template <class T>
	class Pipeline<T> : public T {
	public:
		explicit Pipeline(T& estimator) : T(estimator) {}

		template<size_t _Index>
		using pipeline_model_t = typename internal::sub_pipeline_element<_Index, Pipeline<T>>::model_type;

		template<size_t _Index>
		using sub_pipeline_t = typename internal::sub_pipeline_element<_Index, Pipeline<T>>::type;

		T& top_estimator() { return *this; }

		template<size_t Index>
		inline sub_pipeline_t<Index>& get()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this);
		}

		template<size_t Index>
		inline typename pipeline_model_t<Index>& get_model()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this).top_estimator();
		}

	protected:

	};

	template <class T, class... Ts>
	class Pipeline<T, Ts...> : protected Pipeline<Ts...> {
	public:
		explicit Pipeline(T& estimator, Ts & ... following) : Pipeline<Ts...>(following...), _estimator(estimator) {}

		template<size_t _Index>
		using pipeline_model_t = typename internal::sub_pipeline_element<_Index, Pipeline<T, Ts...>>::model_type;

		template<size_t _Index>
		using sub_pipeline_t = typename internal::sub_pipeline_element<_Index, Pipeline<T, Ts...>>::type;

		Pipeline<T, Ts...>& fit(const Eigen::Ref<const Eigen::MatrixXd>& input, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, cold_start), cold_start);
			return *this;
		}

		Pipeline<T, Ts...>& fit(const Eigen::Ref<const Eigen::MatrixXd>& input, const Eigen::Ref<const Eigen::MatrixXd>& target, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, target, cold_start), target, cold_start);
			return *this;
		}

		Pipeline<T, Ts...>& fit(const Eigen::Ref<const Eigen::MatrixXd>& input, const Eigen::Ref<const Eigen::VectorXi>& classes, bool cold_start = true)
		{
			sub_pipeline_t<1>::fit(_estimator.fit_transform(input, classes, cold_start), classes, cold_start);
			return *this;
		}

		Eigen::MatrixXd transform(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::transform(_estimator.transform(input));
		}

		Eigen::MatrixXi classify(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::classify(_estimator.transform(input));
		}

		Eigen::MatrixXd predict(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::predict(_estimator.transform(input));
		}

		Eigen::MatrixXi cluster(const Eigen::MatrixXd& input) const
		{
			return sub_pipeline_t<1>::cluster(_estimator.transform(input));
		}

		double score(const Eigen::Ref<const Eigen::MatrixXd>& input, const Eigen::Ref<const Eigen::MatrixXd>& target) const {
			return sub_pipeline_t<1>::score(_estimator.transform(input), target);
		}

		double score(const Eigen::Ref<const Eigen::MatrixXd>& input, const Eigen::Ref<const Eigen::VectorXi>& classes) const {
			return sub_pipeline_t<1>::score(_estimator.transform(input), classes);
		}

		T& top_estimator() { return _estimator; }

		template<size_t Index>
		inline sub_pipeline_t<Index>& get()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this);
		}

		template<size_t Index>
		inline typename pipeline_model_t<Index>& get_model()
		{
			return static_cast<sub_pipeline_t<Index>&>(*this).top_estimator();
		}
	protected:
		T& _estimator;
	};

	template <class... Ts>
	Pipeline<Ts...> create_pipeline(Ts & ... models) {
		return Pipeline<Ts...>(models...);
	}
}
}
#endif<|endoftext|>


<commit_before>#include "mini_ion.h"
#include "mini_mman.h"
#include "android_ioctl.h"
#include "scoped_mutex_lock.h"
#include "printer.h"

namespace Halide { namespace Runtime { namespace Internal { namespace Ion {

typedef int ion_user_handle_t;

// Ion data structures.
struct ion_allocation_data {
    size_t len;
    size_t align;
    unsigned int heap_id_mask;
    unsigned int flags;
    ion_user_handle_t handle;
};

struct ion_fd_data {
    ion_user_handle_t handle;
    int fd;
};

struct ion_handle_data {
    ion_user_handle_t handle;
};

#define ION_IOC_MAGIC  'I'
#define ION_IOC_ALLOC  _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_FREE   _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define ION_IOC_MAP    _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)

// A ion fd defined in this module with weak linkage
WEAK int dev_ion_fd = -1;
WEAK halide_mutex thread_lock = { { 0 } };

// The default implementation of halide_hexagon_get_descriptor uses the global
// pointers above, and serializes access with a spin lock.
// Overriding implementations of get_descriptor must implement the following
// behavior:
// - halide_hexagon_get_descriptor should always store a valid file descriptor to
//   /dev/ion in fd, or return an error code.
extern "C" WEAK int halide_ion_get_descriptor(void *user_context, int *fd, bool create = true) {
    // TODO: Should we use a more "assertive" assert? these asserts do
    // not block execution on failure.
    halide_assert(user_context, fd != NULL);

    ScopedMutexLock lock(&thread_lock);

    // If the context has not been initialized, initialize it now.
    if (dev_ion_fd == -1 && create) {
        debug(user_context) << "    open /dev/ion -> ";
        dev_ion_fd = open("/dev/ion", O_RDONLY, 0);
        debug(user_context) << "        " << dev_ion_fd << "\n";
        if (dev_ion_fd == -1) {
            error(user_context) << "Failed to open /dev/ion.\n";
        }
    }

    *fd = dev_ion_fd;
    if (dev_ion_fd == -1) {
        return -1;
    } else {
        return 0;
    }
}

WEAK ion_user_handle_t ion_alloc(int ion_fd, size_t len, size_t align, unsigned int heap_id_mask, unsigned int flags) {
    ion_allocation_data alloc;
    alloc.len = len;
    alloc.align = align;
    alloc.heap_id_mask = heap_id_mask;
    alloc.flags = flags;
    if (ioctl(ion_fd, ION_IOC_ALLOC, &alloc) < 0) {
        return -1;
    }
    return alloc.handle;
}

WEAK void ion_free(int ion_fd, ion_user_handle_t ion_handle) {
    if(ioctl(ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
        // warn?
    }
}

WEAK int ion_map(int ion_fd, ion_user_handle_t ion_handle) {
    ion_fd_data map;
    map.handle = ion_handle;
    if (ioctl(ion_fd, ION_IOC_MAP, &map) < 0) {
        return -1;
    }
    return map.fd;
}

struct allocation_record {
    int dev_ion;
    ion_user_handle_t handle;
    int fd;
    void *mapped;
    size_t size;
};

// Allocate an ION buffer, and map it, returning the mapped pointer.
WEAK void *ion_alloc(void *user_context, size_t len, int heap_id) {
    int dev_ion = -1;
    int result = halide_ion_get_descriptor(user_context, &dev_ion);
    if (result != 0) return NULL;

    const size_t align = 4096;

    // Allocate enough space to hold information about the allocation prior to the pointer we return.
    ion_user_handle_t ion_h = ion_alloc(dev_ion, len + align, align, 1 << heap_id, 0);

    int buf_fd = ion_map(dev_ion, ion_h);

    debug(user_context) << "    mmap map_size=" << (uint64_t)len << " Read Write Shared fd=" << buf_fd << " -> ";
    void *mem = mmap(NULL, len, MapProtocol::Read | MapProtocol::Write, MapFlags::Shared, buf_fd, 0);
    if (mem == MAP_FAILED) {
        ion_free(dev_ion, ion_h);
        debug(user_context) << "        MAP_FAILED\n";
        error(user_context) << "mmap failed\n";
        return NULL;
    } else {
        debug(user_context) << "        " << mem << "\n";
    }

    // Store a record of the ION allocation data before the pointer we return.
    allocation_record rec = { dev_ion, ion_h, buf_fd, mem, len };
    mem = reinterpret_cast<char *>(mem) + align;
    memcpy(reinterpret_cast<allocation_record *>(mem) - 1, &rec, sizeof(rec));
    return mem;
}

// Free a previously allocated ION buffer.
WEAK void ion_free(void *user_context, void *ion) {
    if (!ion) return;
    allocation_record *rec = reinterpret_cast<allocation_record *>(ion) - 1;
    munmap(rec->mapped, rec->size);

    ion_free(rec->dev_ion, rec->handle);
}

}}}}  // namespace Halide::Runtime::Internal::Ion
<commit_msg>Fix bad memory access to ION buffers of unaligned size.<commit_after>#include "mini_ion.h"
#include "mini_mman.h"
#include "android_ioctl.h"
#include "scoped_mutex_lock.h"
#include "printer.h"

namespace Halide { namespace Runtime { namespace Internal { namespace Ion {

typedef int ion_user_handle_t;

// Ion data structures.
struct ion_allocation_data {
    size_t len;
    size_t align;
    unsigned int heap_id_mask;
    unsigned int flags;
    ion_user_handle_t handle;
};

struct ion_fd_data {
    ion_user_handle_t handle;
    int fd;
};

struct ion_handle_data {
    ion_user_handle_t handle;
};

#define ION_IOC_MAGIC  'I'
#define ION_IOC_ALLOC  _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_FREE   _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define ION_IOC_MAP    _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)

// A ion fd defined in this module with weak linkage
WEAK int dev_ion_fd = -1;
WEAK halide_mutex thread_lock = { { 0 } };

// The default implementation of halide_hexagon_get_descriptor uses the global
// pointers above, and serializes access with a spin lock.
// Overriding implementations of get_descriptor must implement the following
// behavior:
// - halide_hexagon_get_descriptor should always store a valid file descriptor to
//   /dev/ion in fd, or return an error code.
extern "C" WEAK int halide_ion_get_descriptor(void *user_context, int *fd, bool create = true) {
    // TODO: Should we use a more "assertive" assert? these asserts do
    // not block execution on failure.
    halide_assert(user_context, fd != NULL);

    ScopedMutexLock lock(&thread_lock);

    // If the context has not been initialized, initialize it now.
    if (dev_ion_fd == -1 && create) {
        debug(user_context) << "    open /dev/ion -> ";
        dev_ion_fd = open("/dev/ion", O_RDONLY, 0);
        debug(user_context) << "        " << dev_ion_fd << "\n";
        if (dev_ion_fd == -1) {
            error(user_context) << "Failed to open /dev/ion.\n";
        }
    }

    *fd = dev_ion_fd;
    if (dev_ion_fd == -1) {
        return -1;
    } else {
        return 0;
    }
}

WEAK ion_user_handle_t ion_alloc(int ion_fd, size_t len, size_t align, unsigned int heap_id_mask, unsigned int flags) {
    ion_allocation_data alloc;
    alloc.len = len;
    alloc.align = align;
    alloc.heap_id_mask = heap_id_mask;
    alloc.flags = flags;
    if (ioctl(ion_fd, ION_IOC_ALLOC, &alloc) < 0) {
        return -1;
    }
    return alloc.handle;
}

WEAK void ion_free(int ion_fd, ion_user_handle_t ion_handle) {
    if(ioctl(ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
        // warn?
    }
}

WEAK int ion_map(int ion_fd, ion_user_handle_t ion_handle) {
    ion_fd_data map;
    map.handle = ion_handle;
    if (ioctl(ion_fd, ION_IOC_MAP, &map) < 0) {
        return -1;
    }
    return map.fd;
}

struct allocation_record {
    int dev_ion;
    ion_user_handle_t handle;
    int fd;
    void *mapped;
    size_t size;
};

// Allocate an ION buffer, and map it, returning the mapped pointer.
WEAK void *ion_alloc(void *user_context, size_t len, int heap_id) {
    int dev_ion = -1;
    int result = halide_ion_get_descriptor(user_context, &dev_ion);
    if (result != 0) return NULL;

    const size_t align = 4096;

    // Align the allocation size.
    len = (len + align - 1) & ~(align - 1);

    // Allocate enough space to hold information about the allocation prior to the pointer we return.
    len += align;

    ion_user_handle_t ion_h = ion_alloc(dev_ion, len, align, 1 << heap_id, 0);

    int buf_fd = ion_map(dev_ion, ion_h);

    debug(user_context) << "    mmap map_size=" << (uint64_t)len << " Read Write Shared fd=" << buf_fd << " -> ";
    void *mem = mmap(NULL, len, MapProtocol::Read | MapProtocol::Write, MapFlags::Shared, buf_fd, 0);
    if (mem == MAP_FAILED) {
        ion_free(dev_ion, ion_h);
        debug(user_context) << "        MAP_FAILED\n";
        error(user_context) << "mmap failed\n";
        return NULL;
    } else {
        debug(user_context) << "        " << mem << "\n";
    }

    // Store a record of the ION allocation data before the pointer we return.
    allocation_record rec = { dev_ion, ion_h, buf_fd, mem, len };
    mem = reinterpret_cast<char *>(mem) + align;
    memcpy(reinterpret_cast<allocation_record *>(mem) - 1, &rec, sizeof(rec));
    return mem;
}

// Free a previously allocated ION buffer.
WEAK void ion_free(void *user_context, void *ion) {
    if (!ion) return;
    allocation_record *rec = reinterpret_cast<allocation_record *>(ion) - 1;
    munmap(rec->mapped, rec->size);

    ion_free(rec->dev_ion, rec->handle);
}

}}}}  // namespace Halide::Runtime::Internal::Ion
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <chrono>
#include <functional>

#include "core/shared_ptr.hh"
#include "core/reactor.hh"
#include "core/future.hh"

template <typename Clock = steady_clock_type, typename Rep, typename Period>
future<> sleep(std::chrono::duration<Rep, Period> dur) {
    struct sleeper {
        promise<> done;
        timer<Clock> tmr;
        sleeper(std::chrono::duration<Rep, Period> dur)
            : tmr([this] { done.set_value(); })
        {
            tmr.arm(dur);
        }
    };
    sleeper *s = new sleeper(dur);
    future<> fut = s->done.get_future();
    return fut.then([s] { delete s; });
}
<commit_msg>sleep: document<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <chrono>
#include <functional>

#include "core/shared_ptr.hh"
#include "core/reactor.hh"
#include "core/future.hh"

/// \file

/// Returns a future which completes after a specified time has elapsed.
///
/// \param dur minimum amount of time before the returned future becomes
///            ready.
/// \return A \ref future which becomes ready when the sleep duration elapses.
template <typename Clock = steady_clock_type, typename Rep, typename Period>
future<> sleep(std::chrono::duration<Rep, Period> dur) {
    struct sleeper {
        promise<> done;
        timer<Clock> tmr;
        sleeper(std::chrono::duration<Rep, Period> dur)
            : tmr([this] { done.set_value(); })
        {
            tmr.arm(dur);
        }
    };
    sleeper *s = new sleeper(dur);
    future<> fut = s->done.get_future();
    return fut.then([s] { delete s; });
}
<|endoftext|>


<commit_before>
/// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=--=-=-=-=-=-
/// river
/// Copyright (c) 2014, Tony Di Croce
/// All rights reserved.
///
/// Redistribution and use in source and binary forms, with or without modification, are permitted
/// provided that the following conditions are met:
///
/// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and
///    the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
///    and the following disclaimer in the documentation and/or other materials provided with the
///    distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
/// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
/// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
/// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
/// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
/// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
/// The views and conclusions contained in the software and documentation are those of the authors and
/// should not be interpreted as representing official policies, either expressed or implied, of the cppkit
/// Project.
/// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=--=-=-=-=-=-

#include "river/client_connection.h"

using namespace river;
using namespace cppkit;
using namespace std;

client_connection::client_connection( const cppkit::ck_string& serverIP, int port ) :
    _serverIP( serverIP ),
    _serverPort( port ),
    _sok( new ck_socket ),
    _sequence( 0 ),
    _sessionID(),
    _recvTimeoutMillis( 5000 )
{
}

client_connection::~client_connection() throw()
{
}

bool client_connection::connect( int timeoutMillis )
{
    return _sok->query_connect( _serverIP, _serverPort, timeoutMillis );
}

void client_connection::disconnect()
{
    _sequence = 0;
    _sessionID = "";
    _sok->close();
}

void client_connection::write_request( shared_ptr<client_request> request )
{
    _sequence++;

    request->set_server_ip( _serverIP );
    request->set_server_port( _serverPort );

    request->set_header( "CSeq", ck_string::from_int( _sequence ) );

    if( _sessionID.length() > 0 )
        request->set_header( "Session", _sessionID );

    request->write_request( _sok );
}

shared_ptr<client_response> client_connection::read_response()
{
    shared_ptr<client_response> response = make_shared<client_response>();

    response->read_response( _sok );

    ck_string value;
    if( response->get_header( "Session", value ) )
    {
        if( _sessionID.empty() )
            _sessionID = value.substr( 0, value.find(';') ); // If no ';' found, entire string is taken.
    }

    return response;
}

cppkit::ck_string client_connection::get_session_id() const
{
    return _sessionID;
}

void client_connection::set_session_id( const cppkit::ck_string& sessionID )
{
    _sessionID = sessionID;
}

bool client_connection::receive_interleaved_packet( uint8_t& channel, std::shared_ptr<cppkit::ck_memory> buffer )
{
    buffer->clear();

    uint8_t dollarSign = 0;
    uint16_t length = 0;
    uint16_t maxIterations = 10000;

    while( maxIterations > 0 )
    {
        maxIterations--;

        size_t bytesRead = _sok->recv( &dollarSign, 1, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        if( dollarSign != 36 )
        {
            CK_LOG_WARNING( "client_connection [%s] invalid token: %d", _serverIP.c_str(), dollarSign );
            continue;
        }

        bytesRead = _sok->recv( &channel, 1, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        if( channel > 2 )
        {
            CK_LOG_WARNING( "client_connections [%s] invalid channel: %d", _serverIP.c_str(), channel );
            continue;
        }

        uint16_t sizeShort;
        bytesRead = _sok->recv( &sizeShort, 2, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        length = ck_ntohs( sizeShort );

        //Interleaved appears to use the same RTP packets as UDP - given that,the max packet size of UDP would be 1500 bytes,
        //we really shouldn't see anything greater than 1600
        if( length > 1600 || length == 0 )
        {
            CK_LOG_WARNING( "client_connection [%s] invalid size: %d", _serverIP.c_str(), length );
            continue;
        }

        bytesRead = _sok->recv( buffer->extend_data( length ).get_ptr(), length, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        return true;
    }

    CK_LOG_ERROR("client_connection [%s] Unable to sync with stream.", _serverIP.c_str() );

    return false;
}
<commit_msg>Added include<commit_after>
/// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=--=-=-=-=-=-
/// river
/// Copyright (c) 2014, Tony Di Croce
/// All rights reserved.
///
/// Redistribution and use in source and binary forms, with or without modification, are permitted
/// provided that the following conditions are met:
///
/// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and
///    the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
///    and the following disclaimer in the documentation and/or other materials provided with the
///    distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
/// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
/// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
/// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
/// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
/// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
/// The views and conclusions contained in the software and documentation are those of the authors and
/// should not be interpreted as representing official policies, either expressed or implied, of the cppkit
/// Project.
/// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=--=-=-=-=-=-

#include "river/client_connection.h"
#include "cppkit/ck_socket.h"

using namespace river;
using namespace cppkit;
using namespace std;

client_connection::client_connection( const cppkit::ck_string& serverIP, int port ) :
    _serverIP( serverIP ),
    _serverPort( port ),
    _sok( new ck_socket ),
    _sequence( 0 ),
    _sessionID(),
    _recvTimeoutMillis( 5000 )
{
}

client_connection::~client_connection() throw()
{
}

bool client_connection::connect( int timeoutMillis )
{
    return _sok->query_connect( _serverIP, _serverPort, timeoutMillis );
}

void client_connection::disconnect()
{
    _sequence = 0;
    _sessionID = "";
    _sok->close();
}

void client_connection::write_request( shared_ptr<client_request> request )
{
    _sequence++;

    request->set_server_ip( _serverIP );
    request->set_server_port( _serverPort );

    request->set_header( "CSeq", ck_string::from_int( _sequence ) );

    if( _sessionID.length() > 0 )
        request->set_header( "Session", _sessionID );

    request->write_request( _sok );
}

shared_ptr<client_response> client_connection::read_response()
{
    shared_ptr<client_response> response = make_shared<client_response>();

    response->read_response( _sok );

    ck_string value;
    if( response->get_header( "Session", value ) )
    {
        if( _sessionID.empty() )
            _sessionID = value.substr( 0, value.find(';') ); // If no ';' found, entire string is taken.
    }

    return response;
}

cppkit::ck_string client_connection::get_session_id() const
{
    return _sessionID;
}

void client_connection::set_session_id( const cppkit::ck_string& sessionID )
{
    _sessionID = sessionID;
}

bool client_connection::receive_interleaved_packet( uint8_t& channel, std::shared_ptr<cppkit::ck_memory> buffer )
{
    buffer->clear();

    uint8_t dollarSign = 0;
    uint16_t length = 0;
    uint16_t maxIterations = 10000;

    while( maxIterations > 0 )
    {
        maxIterations--;

        size_t bytesRead = _sok->recv( &dollarSign, 1, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        if( dollarSign != 36 )
        {
            CK_LOG_WARNING( "client_connection [%s] invalid token: %d", _serverIP.c_str(), dollarSign );
            continue;
        }

        bytesRead = _sok->recv( &channel, 1, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        if( channel > 2 )
        {
            CK_LOG_WARNING( "client_connections [%s] invalid channel: %d", _serverIP.c_str(), channel );
            continue;
        }

        uint16_t sizeShort;
        bytesRead = _sok->recv( &sizeShort, 2, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        length = ck_ntohs( sizeShort );

        //Interleaved appears to use the same RTP packets as UDP - given that,the max packet size of UDP would be 1500 bytes,
        //we really shouldn't see anything greater than 1600
        if( length > 1600 || length == 0 )
        {
            CK_LOG_WARNING( "client_connection [%s] invalid size: %d", _serverIP.c_str(), length );
            continue;
        }

        bytesRead = _sok->recv( buffer->extend_data( length ).get_ptr(), length, _recvTimeoutMillis );

        if( bytesRead == 0 )
            return false;

        return true;
    }

    CK_LOG_ERROR("client_connection [%s] Unable to sync with stream.", _serverIP.c_str() );

    return false;
}
<|endoftext|>


<commit_before>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <String.h>
#include <Halide.h>

int main(int argc, char **argv)
{
	isl_ctx *ctx = isl_ctx_alloc();
	IRProgram pgm("program0");
	IRFunction fct("function0", &pgm);

	// Declare the computations.  Each computation has: (1) a Halide expression,
	// (2) an isl set representing its iteration space and (3) is attached to a
	// function.
	Computation computation0(ctx, Halide::Expr(3), "{S0[i,j]: 0<=i<=1000 and 0<=j<=1000}", &fct);
	Computation computation1(ctx, Halide::Expr(5), "{S1[i,j]: 0<=i<=1023 and 0<=j<=1023}", &fct);
//	Computation computation2(ctx, Halide::Expr(7), "{S2[i,j]: 0<=i<=1023 and 0<=j<=1023}", &fct);

	// Create memory buffers, then map the computations to those buffers.
	Halide::Buffer buf(Halide::Int(32), 10, 10, 0, 0, NULL, "buf");
	fct.buffers_list.insert(std::pair<std::string, Halide::Buffer *>(buf.name(), &buf));
	Halide::Argument buffer_arg("buf", Halide::Argument::OutputBuffer, Halide::Int(32), 2);
	std::vector<Halide::Argument> args(1);
	args[0] = buffer_arg;

	computation0.SetAccess("{S0[i,j]->buf[i, j]}");
	computation1.SetAccess("{S1[i,j]->buf[0, 0]}");
//	computation2.SetAccess("{S2[i,j]->buf[0, 0]}");

	// Set the schedule of each computation.
	computation0.Tile(0,1,32,32);
	computation1.Schedule("{S1[i,j]->[1,i1,j1,i2,j3,j4]: i1=floor(i/32) and j1=floor(j/32) and i2=i and j3=floor(j/4) and j4=j%4 and 0<=i<=1023 and 0<=j<=1023}");
/*	computation2.Split(0, 32);
	computation2.Split(2, 32);
	computation2.Interchange(1, 2);*/
	pgm.tag_parallel_dimension("S0", 1);
//	pgm.tag_vector_dimension("S1", 5);

	isl_union_map *schedule_map = pgm.get_schedule_map();

	// Create time space IR
	isl_union_set *time_space_representaion =
		coli_create_time_space_representation(isl_union_set_copy(pgm.get_iteration_spaces()), isl_union_map_copy(schedule_map));

	// Generate code
	isl_ast_build *ast_build = isl_ast_build_alloc(ctx);
	isl_options_set_ast_build_atomic_upper_bound(ctx, 1);
	ast_build = isl_ast_build_set_after_each_for(ast_build, &for_halide_code_generator_after_for, NULL);
	ast_build = isl_ast_build_set_at_each_domain(ast_build, &stmt_halide_code_generator, NULL);
	isl_ast_node *program = isl_ast_build_node_from_schedule_map(ast_build, isl_union_map_copy(schedule_map));
	isl_ast_build_free(ast_build);

	if (DEBUG)
		isl_ast_node_dump_c_code(ctx, program);

	std::vector<std::string> generated_stmts, iterators;
	Halide::Internal::Stmt halide_pgm = generate_Halide_stmt_from_isl_node(pgm, program, 0, generated_stmts, iterators);

	// Dump IRs
	pgm.dump_ISIR();
	pgm.dump_schedule();
	IF_DEBUG(coli_str_dump("\n\nTime Space IR:\n")); IF_DEBUG(isl_union_set_dump(time_space_representaion)); IF_DEBUG(coli_str_dump("\n\n"));
	halide_IR_dump(halide_pgm);

	Halide::Target target;
	target.os = Halide::Target::OSX;
	target.arch = Halide::Target::X86;
	target.bits = 64;
	std::vector<Halide::Target::Feature> x86_features;
	x86_features.push_back(Halide::Target::AVX);
	x86_features.push_back(Halide::Target::SSE41);
	target.set_features(x86_features);

	Halide::Module::Module m("test1", target);
	m.append(Halide::Internal::LoweredFunc("test1", args, halide_pgm, Halide::Internal::LoweredFunc::External));

	Halide::compile_module_to_object(m, "LLVM_generated_code.o");

	return 0;
}
<commit_msg>Fix the probem of type of halide expressions<commit_after>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <String.h>
#include <Halide.h>

int main(int argc, char **argv)
{
	isl_ctx *ctx = isl_ctx_alloc();
	IRProgram pgm("program0");
	IRFunction fct("function0", &pgm);

	// Declare the computations.  Each computation has: (1) a Halide expression,
	// (2) an isl set representing its iteration space and (3) is attached to a
	// function.
	Computation computation0(ctx, Halide::Expr((uint8_t) 3), "{S0[i,j]: 0<=i<=1000 and 0<=j<=1000}", &fct);
	Computation computation1(ctx, Halide::Expr((uint8_t) 5), "{S1[i,j]: 0<=i<=1023 and 0<=j<=1023}", &fct);
	Computation computation2(ctx, Halide::Expr((uint8_t) 7), "{S2[i,j]: 0<=i<=1023 and 0<=j<=1023}", &fct);

	// Create memory buffers, then map the computations to those buffers.
	Halide::Buffer buf(Halide::Int(8), 10, 10, 0, 0, NULL, "buf");
	fct.buffers_list.insert(std::pair<std::string, Halide::Buffer *>(buf.name(), &buf));
	Halide::Argument buffer_arg("buf", Halide::Argument::OutputBuffer, Halide::Int(8), 2);
	std::vector<Halide::Argument> args(1);
	args[0] = buffer_arg;

	computation0.SetAccess("{S0[i,j]->buf[i, j]}");
	computation1.SetAccess("{S1[i,j]->buf[0, 3]}");
	computation2.SetAccess("{S2[i,j]->buf[0, 0]}");

	// Set the schedule of each computation.
	computation0.Tile(0,1,32,32);
	computation1.Schedule("{S1[i,j]->[2,i1,j1,i2,j3,j4]: i1=floor(i/32) and j1=floor(j/32) and i2=i and j3=floor(j/4) and j4=j%4 and 0<=i<=1023 and 0<=j<=1023}");
	computation2.Split(0, 32);
	computation2.Split(2, 32);
	computation2.Interchange(1, 2);
	pgm.tag_parallel_dimension("S0", 1);
//	pgm.tag_vector_dimension("S1", 5);

	isl_union_map *schedule_map = pgm.get_schedule_map();

	// Create time space IR
	isl_union_set *time_space_representaion =
		coli_create_time_space_representation(isl_union_set_copy(pgm.get_iteration_spaces()), isl_union_map_copy(schedule_map));

	// Generate code
	isl_ast_build *ast_build = isl_ast_build_alloc(ctx);
	isl_options_set_ast_build_atomic_upper_bound(ctx, 1);
	ast_build = isl_ast_build_set_after_each_for(ast_build, &for_halide_code_generator_after_for, NULL);
	ast_build = isl_ast_build_set_at_each_domain(ast_build, &stmt_halide_code_generator, NULL);
	isl_ast_node *program = isl_ast_build_node_from_schedule_map(ast_build, isl_union_map_copy(schedule_map));
	isl_ast_build_free(ast_build);

	if (DEBUG)
		isl_ast_node_dump_c_code(ctx, program);

	std::vector<std::string> generated_stmts, iterators;
	Halide::Internal::Stmt halide_pgm = generate_Halide_stmt_from_isl_node(pgm, program, 0, generated_stmts, iterators);

	// Dump IRs
	pgm.dump_ISIR();
	pgm.dump_schedule();
	IF_DEBUG(coli_str_dump("\n\nTime Space IR:\n")); IF_DEBUG(isl_union_set_dump(time_space_representaion)); IF_DEBUG(coli_str_dump("\n\n"));
	halide_IR_dump(halide_pgm);

	Halide::Target target;
	target.os = Halide::Target::OSX;
	target.arch = Halide::Target::X86;
	target.bits = 64;
	std::vector<Halide::Target::Feature> x86_features;
	x86_features.push_back(Halide::Target::AVX);
	x86_features.push_back(Halide::Target::SSE41);
	target.set_features(x86_features);

	Halide::Module::Module m("test1", target);
	m.append(Halide::Internal::LoweredFunc("test1", args, halide_pgm, Halide::Internal::LoweredFunc::External));

	Halide::compile_module_to_object(m, "LLVM_generated_code.o");

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>

#include <boost/function.hpp>

#include "object_factory_impl.hpp"

namespace sak
{

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
            { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto factory = find(m_lookup_by_factory_id, factory_id);

                assert(factory);

                typedef object_factory_impl<Factory> factory_type;

                auto factory_impl =
                    boost::dynamic_pointer_cast<factory_type>(factory);

                assert(factory_impl);
                assert(factory_impl->m_factory);
                return factory_impl->m_factory;
            }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered objects can be created
        template<class Factory, class Object>
        void set_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto object_id  = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(factory_id.m_id != object::id()->m_id);

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_impl<Factory> >();

                m_lookup_by_factory_id[factory_id] = factory;
                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        template<class Object>
        void set_factory(const boost::function<boost::shared_ptr<Object>(
                             object_registry &)> &function)
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_function<Object> >(function);

                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory with the object registry. This methods
        /// can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(object_id.m_id != object::id()->m_id);

                auto object = boost::make_shared<Object>();

                m_lookup_by_shared_object_id[object_id] = object;
            }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
            {
                auto object_id = *get_object_id<Object>();
                auto object = find(m_lookup_by_shared_object_id, object_id);

                assert(object);
                return boost::dynamic_pointer_cast<Object>(object);
            }

        /// Clears all registered factories
        void clear_factories()
            {
                m_lookup_by_factory_id.clear();
                m_lookup_by_object_id.clear();
            }

        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
            {
                assert(has_object_id(m_lookup_by_object_id, *get_object_id<Object>() ));

                auto factory = find(m_lookup_by_object_id, *get_object_id<Object>() );

                assert(factory);

                auto object = factory->build(*this);

                return boost::dynamic_pointer_cast<Object>(object);
            }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
            {
                return map.find(id) != map.end();
            }

        /*template<class Object>
        object_id get_object_id() const
            {
                return *Object::id();
            }*/

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
        find(const factory_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object>
        find(const object_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };

    /// Template must be specialized by all object classes used with the object registry
    template<class Object> object_id* get_object_id();
}

#endif

<commit_msg>template moved in front of registry<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>

#include <boost/function.hpp>

#include "object_factory_impl.hpp"

namespace sak
{
	/// Template must be specialized by all object classes used with the object registry
    template<class Object> object_id* get_object_id();

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
            { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto factory = find(m_lookup_by_factory_id, factory_id);

                assert(factory);

                typedef object_factory_impl<Factory> factory_type;

                auto factory_impl =
                    boost::dynamic_pointer_cast<factory_type>(factory);

                assert(factory_impl);
                assert(factory_impl->m_factory);
                return factory_impl->m_factory;
            }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered objects can be created
        template<class Factory, class Object>
        void set_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto object_id  = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(factory_id.m_id != object::id()->m_id);

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_impl<Factory> >();

                m_lookup_by_factory_id[factory_id] = factory;
                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        template<class Object>
        void set_factory(const boost::function<boost::shared_ptr<Object>(
                             object_registry &)> &function)
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_function<Object> >(function);

                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory with the object registry. This methods
        /// can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(object_id.m_id != object::id()->m_id);

                auto object = boost::make_shared<Object>();

                m_lookup_by_shared_object_id[object_id] = object;
            }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
            {
                auto object_id = *get_object_id<Object>();
                auto object = find(m_lookup_by_shared_object_id, object_id);

                assert(object);
                return boost::dynamic_pointer_cast<Object>(object);
            }

        /// Clears all registered factories
        void clear_factories()
            {
                m_lookup_by_factory_id.clear();
                m_lookup_by_object_id.clear();
            }

        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
            {
                assert(has_object_id(m_lookup_by_object_id, *get_object_id<Object>() ));

                auto factory = find(m_lookup_by_object_id, *get_object_id<Object>() );

                assert(factory);

                auto object = factory->build(*this);

                return boost::dynamic_pointer_cast<Object>(object);
            }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
            {
                return map.find(id) != map.end();
            }

        /*template<class Object>
        object_id get_object_id() const
            {
                return *Object::id();
            }*/

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
        find(const factory_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object>
        find(const object_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };
}

#endif

<|endoftext|>


<commit_before>#include <Arduino.h>
#include <HX711.h>

HX711::HX711(byte dout, byte pd_sck, byte gain) {
	PD_SCK 	= pd_sck;
	DOUT 	= dout;

	pinMode(PD_SCK, OUTPUT);
	pinMode(DOUT, INPUT);

	set_gain(gain);
}

HX711::~HX711() {

}

bool HX711::is_ready() {
	return digitalRead(DOUT) == LOW;
}

void HX711::set_gain(byte gain) {
	switch (gain) {
		case 128:		// channel A, gain factor 128
			GAIN = 1;
			break;
		case 64:		// channel A, gain factor 64
			GAIN = 3;
			break;
		case 32:		// channel B, gain factor 32
			GAIN = 2;
			break;
	}

	digitalWrite(PD_SCK, LOW);
	read();
}

long HX711::read() {
	// wait for the chip to become ready
	while (!is_ready());

	byte data[3];

	// pulse the clock pin 24 times to read the data
	for (byte j = 3; j--;) {
		for (char i = 8; i--;) {
			digitalWrite(PD_SCK, HIGH);
			bitWrite(data[j], i, digitalRead(DOUT));
			digitalWrite(PD_SCK, LOW);
		}
	}

	// set the channel and the gain factor for the next reading using the clock pin
	for (int i = 0; i < GAIN; i++) {
		digitalWrite(PD_SCK, HIGH);
		digitalWrite(PD_SCK, LOW);
	}

	data[2] ^= 0x80;

	return ((uint32_t) data[2] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[0];
}

long HX711::read_average(byte times) {
	long sum = 0;
	for (byte i = 0; i < times; i++) {
		sum += read();
	}
	return sum / times;
}

double HX711::get_value(byte times) {
	return read_average(times) - OFFSET;
}

float HX711::get_units(byte times) {
	return get_value(times) / SCALE;
}

void HX711::tare(byte times) {
	double sum = read_average(times);
	set_offset(sum);
}

void HX711::set_scale(float scale) {
	SCALE = scale;
}

void HX711::set_offset(long offset) {
	OFFSET = offset;
}

void HX711::power_down() {
	digitalWrite(PD_SCK, LOW);
	digitalWrite(PD_SCK, HIGH);
}

void HX711::power_up() {
	digitalWrite(PD_SCK, LOW);
}<commit_msg>Unroll loop for performance and use Wiring API `shiftIn()`<commit_after>#include <Arduino.h>
#include <HX711.h>

HX711::HX711(byte dout, byte pd_sck, byte gain) {
	PD_SCK 	= pd_sck;
	DOUT 	= dout;

	pinMode(PD_SCK, OUTPUT);
	pinMode(DOUT, INPUT);

	set_gain(gain);
}

HX711::~HX711() {

}

bool HX711::is_ready() {
	return digitalRead(DOUT) == LOW;
}

void HX711::set_gain(byte gain) {
	switch (gain) {
		case 128:		// channel A, gain factor 128
			GAIN = 1;
			break;
		case 64:		// channel A, gain factor 64
			GAIN = 3;
			break;
		case 32:		// channel B, gain factor 32
			GAIN = 2;
			break;
	}

	digitalWrite(PD_SCK, LOW);
	read();
}

long HX711::read() {
	// wait for the chip to become ready
	while (!is_ready());

	byte data[3];

	// pulse the clock pin 24 times to read the data
    data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
    data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
    data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);

	// set the channel and the gain factor for the next reading using the clock pin
	for (int i = 0; i < GAIN; i++) {
		digitalWrite(PD_SCK, HIGH);
		digitalWrite(PD_SCK, LOW);
	}

	data[2] ^= 0x80;

	return ((uint32_t) data[2] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[0];
}

long HX711::read_average(byte times) {
	long sum = 0;
	for (byte i = 0; i < times; i++) {
		sum += read();
	}
	return sum / times;
}

double HX711::get_value(byte times) {
	return read_average(times) - OFFSET;
}

float HX711::get_units(byte times) {
	return get_value(times) / SCALE;
}

void HX711::tare(byte times) {
	double sum = read_average(times);
	set_offset(sum);
}

void HX711::set_scale(float scale) {
	SCALE = scale;
}

void HX711::set_offset(long offset) {
	OFFSET = offset;
}

void HX711::power_down() {
	digitalWrite(PD_SCK, LOW);
	digitalWrite(PD_SCK, HIGH);
}

void HX711::power_up() {
	digitalWrite(PD_SCK, LOW);
}<|endoftext|>


<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "winsock2.h"

#include <objbase.h>
#include <initguid.h>
#include <connmgr.h>
#include <wininet.h>

#include "http/GPRSConnection.h"
#include "base/Log.h"

/*
* Method to test if connection is alive. If no one is found, it tries to establish
* default connection.
*/

BOOL EstablishConnection() {

    HANDLE  phWebConnection = NULL;

    // First we check if we might have a connection
    DWORD  pdwStatus = 0;
    LOG.debug("Establish connection: test internet connection status...");
    ConnMgrConnectionStatus(phWebConnection, &pdwStatus);

    if (pdwStatus == CONNMGR_STATUS_CONNECTED) {
        LOG.info("Already connected");
        //We are already connected!
        return TRUE;
    }
#if _WIN32_WCE > 0x500
    else if (pdwStatus == CONNMGR_STATUS_PHONEOFF) {
        LOG.info("phone off");
        //We are already connected!
        return FALSE;
    }
#endif
    else {
        LOG.debug("Not connected: try to connect...");
        //We are not connected, so lets try:
        //The CONNECTIONINFO is the structure that
        //tells Connection Manager how we want
        //to connect

        CONNMGR_CONNECTIONINFO sConInfo;
        memset(&sConInfo,0, sizeof(CONNMGR_CONNECTIONINFO));
        sConInfo.cbSize = sizeof(CONNMGR_CONNECTIONINFO);
        // We want to use the "guidDestNet" parameter
        sConInfo.dwParams = CONNMGR_PARAM_GUIDDESTNET;
        // This is the highest data priority.
        sConInfo.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;
        // sConInfo.dwFlags = 0;
        sConInfo.dwFlags=CONNMGR_FLAG_PROXY_HTTP;
        // Lets be nice and share the connection with
        // other applications
        sConInfo.bExclusive = FALSE;
        sConInfo.bDisabled = FALSE;
        sConInfo.guidDestNet = IID_DestNetInternet;
        LOG.debug("Try to establish connection...");
        if (ConnMgrEstablishConnection(&sConInfo,&phWebConnection) == S_OK) {
            LOG.debug("Start internet connection process...");
            //We start successfully process!
            for (unsigned int k = 0; k < 6; k++) {
                ConnMgrConnectionStatus(phWebConnection,&pdwStatus);

                if (pdwStatus == CONNMGR_STATUS_CONNECTED) {
                    LOG.info("Internet connection succesfully completed.");
                    return TRUE;

                }
                else {
                    if (pdwStatus == CONNMGR_STATUS_CONNECTIONCANCELED || pdwStatus == CONNMGR_STATUS_WAITINGCONNECTIONABORT) {
                        LOG.debug("Internet connection not succeded.");
                        return FALSE;

                    }
                    Sleep(2000);

                    ConnMgrConnectionStatus(phWebConnection,&pdwStatus);
                    if (pdwStatus == CONNMGR_STATUS_WAITINGCONNECTION) {
                        // it is possible to do something...
                    }

                    if (pdwStatus == CONNMGR_STATUS_CONNECTIONCANCELED || pdwStatus == CONNMGR_STATUS_WAITINGCONNECTIONABORT) {
                        LOG.debug("Internet connection not succeded");
                        return FALSE;
                    }
                }
            }
            LOG.debug("Internet connection not succeded after connection process");
            return FALSE;
        }
        else {
            //Connection failed!
            LOG.info("Internet connection failed.");
            return FALSE;

        }

    }

}
<commit_msg>just changed some logging<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "winsock2.h"

#include <objbase.h>
#include <initguid.h>
#include <connmgr.h>
#include <wininet.h>

#include "http/GPRSConnection.h"
#include "base/Log.h"

/*
* Method to test if connection is alive. If no one is found, it tries to establish
* default connection.
*/

BOOL EstablishConnection() {

    HANDLE  phWebConnection = NULL;

    // First we check if we might have a connection
    DWORD  pdwStatus = 0;
    LOG.debug("Establish connection: test internet connection status...");
    ConnMgrConnectionStatus(phWebConnection, &pdwStatus);

    if (pdwStatus == CONNMGR_STATUS_CONNECTED) {
        LOG.info("Already connected");
        //We are already connected!
        return TRUE;
    }
#if _WIN32_WCE > 0x500
    else if (pdwStatus == CONNMGR_STATUS_PHONEOFF) {
        LOG.info("phone off");
        //We are already connected!
        return FALSE;
    }
#endif
    else {
        LOG.debug("Not connected (status = 0x%02x): try to connect...", pdwStatus);
        //We are not connected, so lets try:
        //The CONNECTIONINFO is the structure that
        //tells Connection Manager how we want
        //to connect

        CONNMGR_CONNECTIONINFO sConInfo;
        memset(&sConInfo,0, sizeof(CONNMGR_CONNECTIONINFO));
        sConInfo.cbSize = sizeof(CONNMGR_CONNECTIONINFO);
        // We want to use the "guidDestNet" parameter
        sConInfo.dwParams = CONNMGR_PARAM_GUIDDESTNET;
        // This is the highest data priority.
        sConInfo.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;
        // sConInfo.dwFlags = 0;
        sConInfo.dwFlags=CONNMGR_FLAG_PROXY_HTTP;
        // Lets be nice and share the connection with
        // other applications
        sConInfo.bExclusive = FALSE;
        sConInfo.bDisabled = FALSE;
        sConInfo.guidDestNet = IID_DestNetInternet;
        LOG.debug("Try to establish connection...");
        if (ConnMgrEstablishConnection(&sConInfo,&phWebConnection) == S_OK) {
            LOG.debug("Start internet connection process...");
            //We start successfully process!
            for (unsigned int k = 0; k < 6; k++) {
                ConnMgrConnectionStatus(phWebConnection,&pdwStatus);

                if (pdwStatus == CONNMGR_STATUS_CONNECTED) {
                    LOG.info("Internet connection succesfully completed.");
                    return TRUE;

                }
                else {
                    if (pdwStatus == CONNMGR_STATUS_CONNECTIONCANCELED || pdwStatus == CONNMGR_STATUS_WAITINGCONNECTIONABORT) {
                        LOG.debug("Internet connection not succeded.");
                        return FALSE;

                    }
                    Sleep(2000);

                    ConnMgrConnectionStatus(phWebConnection,&pdwStatus);
                    if (pdwStatus == CONNMGR_STATUS_WAITINGCONNECTION) {
                        // it is possible to do something...
                    }

                    if (pdwStatus == CONNMGR_STATUS_CONNECTIONCANCELED || pdwStatus == CONNMGR_STATUS_WAITINGCONNECTIONABORT) {
                        LOG.debug("Internet connection not succeded");
                        return FALSE;
                    }
                }
            }
            LOG.debug("Internet connection not succeded after connection process");
            return FALSE;
        }
        else {
            //Connection failed!
            LOG.info("Internet connection failed.");
            return FALSE;

        }

    }

}
<|endoftext|>