<commit_before>
// NetworkSingleton.cpp

// Implements the cNetworkSingleton class representing the storage for global data pertaining to network API
// such as a list of all connections, all listening sockets and the LibEvent dispatch thread.

#include "Globals.h"
#include "NetworkSingleton.h"
#include <event2/event.h>
#include <event2/thread.h>
#include <event2/bufferevent.h>
#include <event2/dns.h>
#include <event2/listener.h>
#include "IPLookup.h"
#include "HostnameLookup.h"

cNetworkSingleton::cNetworkSingleton(void):
	m_HasTerminated(false)
{
	// Windows: initialize networking:
	#ifdef _WIN32
		WSADATA wsaData;
		memset(&wsaData, 0, sizeof(wsaData));
		int res = WSAStartup (MAKEWORD(2, 2), &wsaData);
		if (res != 0)
		{
			int err = WSAGetLastError();
			LOGWARNING("WSAStartup failed: %d, WSAGLE = %d (%s)", res, err, evutil_socket_error_to_string(err));
			exit(1);
		}
	#endif  // _WIN32

	// Initialize LibEvent logging:
	event_set_log_callback(LogCallback);

	// Initialize threading:
	#if defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
		evthread_use_windows_threads();
	#elif defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
		evthread_use_pthreads();
	#else
		#error No threading implemented for EVTHREAD
	#endif

	// Create the main event_base:
	m_EventBase = event_base_new();
	if (m_EventBase == nullptr)
	{
		LOGERROR("Failed to initialize LibEvent. The server will now terminate.");
		abort();
	}

	// Create the DNS lookup helper:
	m_DNSBase = evdns_base_new(m_EventBase, 1);
	if (m_DNSBase == nullptr)
	{
		LOGERROR("Failed to initialize LibEvent's DNS subsystem. The server will now terminate.");
		abort();
	}

	// Create the event loop thread:
	m_EventLoopThread = std::thread(RunEventLoop, this);
}

cNetworkSingleton::~cNetworkSingleton()
{
	// Check that Terminate has been called already:
	ASSERT(m_HasTerminated);
}

cNetworkSingleton & cNetworkSingleton::Get(void)
{
	static cNetworkSingleton Instance;
	return Instance;
}

void cNetworkSingleton::Terminate(void)
{
	ASSERT(!m_HasTerminated);
	m_HasTerminated = true;

	// Wait for the LibEvent event loop to terminate:
	event_base_loopbreak(m_EventBase);
	m_EventLoopThread.join();

	// Remove all objects:
	{
		cCSLock Lock(m_CS);
		m_Connections.clear();
		m_Servers.clear();
		m_HostnameLookups.clear();
		m_IPLookups.clear();
	}

	// Free the underlying LibEvent objects:
	evdns_base_free(m_DNSBase, true);
	event_base_free(m_EventBase);

	libevent_global_shutdown();
}

void cNetworkSingleton::LogCallback(int a_Severity, const char * a_Msg)
{
	switch (a_Severity)
	{
		case _EVENT_LOG_DEBUG: LOGD      ("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_MSG:   LOG       ("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_WARN:  LOGWARNING("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_ERR:   LOGERROR  ("LibEvent: %s", a_Msg); break;
		default:
		{
			LOGWARNING("LibEvent: Unknown log severity (%d): %s", a_Severity, a_Msg);
			break;
		}
	}
}

void cNetworkSingleton::RunEventLoop(cNetworkSingleton * a_Self)
{
	event_base_loop(a_Self->m_EventBase, EVLOOP_NO_EXIT_ON_EMPTY);
}

void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_HostnameLookups.push_back(a_HostnameLookup);
}

void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_HostnameLookups.begin(), end = m_HostnameLookups.end(); itr != end; ++itr)
	{
		if (itr->get() == a_HostnameLookup)
		{
			m_HostnameLookups.erase(itr);
			return;
		}
	}  // for itr - m_HostnameLookups[]
}

void cNetworkSingleton::AddIPLookup(cIPLookupPtr a_IPLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_IPLookups.push_back(a_IPLookup);
}

void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_IPLookups.begin(), end = m_IPLookups.end(); itr != end; ++itr)
	{
		if (itr->get() == a_IPLookup)
		{
			m_IPLookups.erase(itr);
			return;
		}
	}  // for itr - m_IPLookups[]
}

void cNetworkSingleton::AddLink(cTCPLinkImplPtr a_Link)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_Connections.push_back(a_Link);
}

void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
	{
		if (itr->get() == a_Link)
		{
			m_Connections.erase(itr);
			return;
		}
	}  // for itr - m_Connections[]
}

void cNetworkSingleton::AddServer(cServerHandleImplPtr a_Server)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_Servers.push_back(a_Server);
}

void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_Servers.begin(), end = m_Servers.end(); itr != end; ++itr)
	{
		if (itr->get() == a_Server)
		{
			m_Servers.erase(itr);
			return;
		}
	}  // for itr - m_Servers[]
}

<commit_msg>Fixed cNetworkSingleton's HasTerminated flag.<commit_after>
// NetworkSingleton.cpp

// Implements the cNetworkSingleton class representing the storage for global data pertaining to network API
// such as a list of all connections, all listening sockets and the LibEvent dispatch thread.

#include "Globals.h"
#include "NetworkSingleton.h"
#include <event2/event.h>
#include <event2/thread.h>
#include <event2/bufferevent.h>
#include <event2/dns.h>
#include <event2/listener.h>
#include "IPLookup.h"
#include "HostnameLookup.h"

cNetworkSingleton::cNetworkSingleton(void):
	m_HasTerminated(false)
{
	// Windows: initialize networking:
	#ifdef _WIN32
		WSADATA wsaData;
		memset(&wsaData, 0, sizeof(wsaData));
		int res = WSAStartup (MAKEWORD(2, 2), &wsaData);
		if (res != 0)
		{
			int err = WSAGetLastError();
			LOGWARNING("WSAStartup failed: %d, WSAGLE = %d (%s)", res, err, evutil_socket_error_to_string(err));
			exit(1);
		}
	#endif  // _WIN32

	// Initialize LibEvent logging:
	event_set_log_callback(LogCallback);

	// Initialize threading:
	#if defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
		evthread_use_windows_threads();
	#elif defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
		evthread_use_pthreads();
	#else
		#error No threading implemented for EVTHREAD
	#endif

	// Create the main event_base:
	m_EventBase = event_base_new();
	if (m_EventBase == nullptr)
	{
		LOGERROR("Failed to initialize LibEvent. The server will now terminate.");
		abort();
	}

	// Create the DNS lookup helper:
	m_DNSBase = evdns_base_new(m_EventBase, 1);
	if (m_DNSBase == nullptr)
	{
		LOGERROR("Failed to initialize LibEvent's DNS subsystem. The server will now terminate.");
		abort();
	}

	// Create the event loop thread:
	m_EventLoopThread = std::thread(RunEventLoop, this);
}

cNetworkSingleton::~cNetworkSingleton()
{
	// Check that Terminate has been called already:
	ASSERT(m_HasTerminated);
}

cNetworkSingleton & cNetworkSingleton::Get(void)
{
	static cNetworkSingleton Instance;
	return Instance;
}

void cNetworkSingleton::Terminate(void)
{
	ASSERT(!m_HasTerminated);

	// Wait for the LibEvent event loop to terminate:
	event_base_loopbreak(m_EventBase);
	m_EventLoopThread.join();

	// Remove all objects:
	{
		cCSLock Lock(m_CS);
		m_Connections.clear();
		m_Servers.clear();
		m_HostnameLookups.clear();
		m_IPLookups.clear();
	}

	// Free the underlying LibEvent objects:
	evdns_base_free(m_DNSBase, true);
	event_base_free(m_EventBase);

	libevent_global_shutdown();

	// Set the HasTerminated flag:
	// (Only set the flag after everything has been removed, to avoid the random failures in the Google-test, caused by links terminating after this flag was set)
	m_HasTerminated = true;
}

void cNetworkSingleton::LogCallback(int a_Severity, const char * a_Msg)
{
	switch (a_Severity)
	{
		case _EVENT_LOG_DEBUG: LOGD      ("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_MSG:   LOG       ("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_WARN:  LOGWARNING("LibEvent: %s", a_Msg); break;
		case _EVENT_LOG_ERR:   LOGERROR  ("LibEvent: %s", a_Msg); break;
		default:
		{
			LOGWARNING("LibEvent: Unknown log severity (%d): %s", a_Severity, a_Msg);
			break;
		}
	}
}

void cNetworkSingleton::RunEventLoop(cNetworkSingleton * a_Self)
{
	event_base_loop(a_Self->m_EventBase, EVLOOP_NO_EXIT_ON_EMPTY);
}

void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_HostnameLookups.push_back(a_HostnameLookup);
}

void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_HostnameLookups.begin(), end = m_HostnameLookups.end(); itr != end; ++itr)
	{
		if (itr->get() == a_HostnameLookup)
		{
			m_HostnameLookups.erase(itr);
			return;
		}
	}  // for itr - m_HostnameLookups[]
}

void cNetworkSingleton::AddIPLookup(cIPLookupPtr a_IPLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_IPLookups.push_back(a_IPLookup);
}

void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_IPLookups.begin(), end = m_IPLookups.end(); itr != end; ++itr)
	{
		if (itr->get() == a_IPLookup)
		{
			m_IPLookups.erase(itr);
			return;
		}
	}  // for itr - m_IPLookups[]
}

void cNetworkSingleton::AddLink(cTCPLinkImplPtr a_Link)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_Connections.push_back(a_Link);
}

void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
	{
		if (itr->get() == a_Link)
		{
			m_Connections.erase(itr);
			return;
		}
	}  // for itr - m_Connections[]
}

void cNetworkSingleton::AddServer(cServerHandleImplPtr a_Server)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	m_Servers.push_back(a_Server);
}

void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
{
	ASSERT(!m_HasTerminated);
	cCSLock Lock(m_CS);
	for (auto itr = m_Servers.begin(), end = m_Servers.end(); itr != end; ++itr)
	{
		if (itr->get() == a_Server)
		{
			m_Servers.erase(itr);
			return;
		}
	}  // for itr - m_Servers[]
}

<|endoftext|>


<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "GpuSubmissionTrack.h"

#include <absl/time/time.h>

#include <memory>

#include "App.h"
#include "Batcher.h"
#include "ClientData/TimerChain.h"
#include "DisplayFormats/DisplayFormats.h"
#include "GlUtils.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/ThreadConstants.h"
#include "TimeGraph.h"
#include "TimeGraphLayout.h"
#include "TriangleToggle.h"
#include "absl/strings/str_format.h"
#include "capture_data.pb.h"

using orbit_client_data::TimerChain;
using orbit_client_protos::TimerInfo;

constexpr const char* kSwQueueString = "sw queue";
constexpr const char* kHwQueueString = "hw queue";
constexpr const char* kHwExecutionString = "hw execution";
constexpr const char* kCmdBufferString = "command buffer";

GpuSubmissionTrack::GpuSubmissionTrack(Track* parent, TimeGraph* time_graph,
                                       orbit_gl::Viewport* viewport, TimeGraphLayout* layout,
                                       uint64_t timeline_hash, OrbitApp* app,
                                       const orbit_client_data::CaptureData* capture_data)
    : TimerTrack(parent, time_graph, viewport, layout, app, capture_data) {
  draw_background_ = false;
  text_renderer_ = time_graph->GetTextRenderer();
  timeline_hash_ = timeline_hash;
  string_manager_ = app->GetStringManager();
  parent_ = parent;
}

std::string GpuSubmissionTrack::GetName() const {
  return absl::StrFormat(
      "%s_submissions",
      string_manager_->Get(timeline_hash_).value_or(std::to_string(timeline_hash_)));
}

std::string GpuSubmissionTrack::GetTooltip() const {
  return "Shows scheduling and execution times for selected GPU job "
         "submissions";
}

void GpuSubmissionTrack::OnTimer(const orbit_client_protos::TimerInfo& timer_info) {
  // In case of having command buffer timers, we need to double the depth of the GPU timers (as we
  // are drawing the corresponding command buffer timers below them). Therefore, we watch out for
  // those timers.
  if (timer_info.type() == TimerInfo::kGpuCommandBuffer) {
    has_vulkan_layer_command_buffer_timers_ = true;
  }
  TimerTrack::OnTimer(timer_info);
}

bool GpuSubmissionTrack::IsTimerActive(const TimerInfo& timer_info) const {
  bool is_same_tid_as_selected = timer_info.thread_id() == app_->selected_thread_id();
  // We do not properly track the PID for GPU jobs and we still want to show
  // all jobs as active when no thread is selected, so this logic is a bit
  // different than SchedulerTrack::IsTimerActive.
  bool no_thread_selected = app_->selected_thread_id() == orbit_base::kAllProcessThreadsTid;

  return is_same_tid_as_selected || no_thread_selected;
}

Color GpuSubmissionTrack::GetTimerColor(const TimerInfo& timer_info, bool is_selected,
                                        bool is_highlighted) const {
  const Color kInactiveColor(100, 100, 100, 255);
  const Color kSelectionColor(0, 128, 255, 255);
  if (is_highlighted) {
    return TimerTrack::kHighlightColor;
  }
  if (is_selected) {
    return kSelectionColor;
  }
  if (!IsTimerActive(timer_info)) {
    return kInactiveColor;
  }
  if (timer_info.has_color()) {
    CHECK(timer_info.color().red() < 256);
    CHECK(timer_info.color().green() < 256);
    CHECK(timer_info.color().blue() < 256);
    CHECK(timer_info.color().alpha() < 256);
    return Color(static_cast<uint8_t>(timer_info.color().red()),
                 static_cast<uint8_t>(timer_info.color().green()),
                 static_cast<uint8_t>(timer_info.color().blue()),
                 static_cast<uint8_t>(timer_info.color().alpha()));
  }

  // We color code the timeslices for GPU activity using the color
  // of the CPU thread track that submitted the job.
  Color color = TimeGraph::GetThreadColor(timer_info.thread_id());

  // We disambiguate the different types of GPU activity based on the
  // string that is displayed on their timeslice.
  float coeff = 1.0f;
  std::string gpu_stage = string_manager_->Get(timer_info.user_data_key()).value_or("");
  if (gpu_stage == kSwQueueString) {
    coeff = 0.5f;
  } else if (gpu_stage == kHwQueueString) {
    coeff = 0.75f;
  } else if (gpu_stage == kHwExecutionString) {
    coeff = 1.0f;
  }

  color[0] = static_cast<uint8_t>(coeff * color[0]);
  color[1] = static_cast<uint8_t>(coeff * color[1]);
  color[2] = static_cast<uint8_t>(coeff * color[2]);

  constexpr uint8_t kOddAlpha = 210;
  if ((timer_info.depth() & 0x1) == 0u) {
    color[3] = kOddAlpha;
  }

  return color;
}

float GpuSubmissionTrack::GetYFromTimer(const TimerInfo& timer_info) const {
  auto adjusted_depth = static_cast<float>(timer_info.depth());
  if (IsCollapsed()) {
    adjusted_depth = 0.f;
  }
  CHECK(timer_info.type() == TimerInfo::kGpuActivity ||
        timer_info.type() == TimerInfo::kGpuCommandBuffer);

  // We are drawing a small gap between each depth, for visualization purposes.
  // There won't be a gap between "hw execution"timers and command buffer timers, which
  // is why the gap space needs to be calculated before adjusting the depth further (see below).
  float gap_space = adjusted_depth * layout_->GetSpaceBetweenGpuDepths();

  // Command buffer timers are drawn underneath the matching "hw execution" timer, which has the
  // same depth value as the command buffer timer. Therefore, we need to double the depth in the
  // case that we have command buffer timers.
  if (has_vulkan_layer_command_buffer_timers_) {
    adjusted_depth *= 2.f;
  }

  // Command buffer timers have the same depth value as their matching "hw execution" timer.
  // As we want to draw command buffers underneath the hw execution timers, we need to increase
  // the depth by one.
  if (timer_info.type() == TimerInfo::kGpuCommandBuffer) {
    adjusted_depth += 1.f;
  }
  return pos_[1] - layout_->GetTrackTabHeight() -
         layout_->GetTextBoxHeight() * (adjusted_depth + 1.f) - gap_space;
}

// When track or its parent is collapsed, only draw "hardware execution" timers.
bool GpuSubmissionTrack::TimerFilter(const TimerInfo& timer_info) const {
  if (IsCollapsed()) {
    std::string gpu_stage = string_manager_->Get(timer_info.user_data_key()).value_or("");
    return gpu_stage == kHwExecutionString;
  }
  return true;
}

std::string GpuSubmissionTrack::GetTimesliceText(const TimerInfo& timer_info) const {
  CHECK(timer_info.type() == TimerInfo::kGpuActivity ||
        timer_info.type() == TimerInfo::kGpuCommandBuffer);
  std::string time = GetDisplayTime(timer_info);

  return absl::StrFormat("%s  %s", string_manager_->Get(timer_info.user_data_key()).value_or(""),
                         time);
}

float GpuSubmissionTrack::GetHeight() const {
  bool collapsed = IsCollapsed();
  uint32_t depth = collapsed ? 1 : GetDepth();
  uint32_t num_gaps = depth > 0 ? depth - 1 : 0;
  if (has_vulkan_layer_command_buffer_timers_ && !collapsed) {
    depth *= 2;
  }
  return layout_->GetTrackTabHeight() + layout_->GetTextBoxHeight() * depth +
         (num_gaps * layout_->GetSpaceBetweenGpuDepths()) + layout_->GetTrackBottomMargin();
}

const TimerInfo* GpuSubmissionTrack::GetLeft(const TimerInfo& timer_info) const {
  uint64_t timeline_hash = timer_info.user_data_key();
  if (timeline_hash == timeline_hash_) {
    const TimerChain* chain = track_data_->GetChain(timer_info.depth());
    if (chain != nullptr) return chain->GetElementBefore(timer_info);
  }
  return nullptr;
}

const TimerInfo* GpuSubmissionTrack::GetRight(const TimerInfo& timer_info) const {
  uint64_t timeline_hash = timer_info.user_data_key();
  if (timeline_hash == timeline_hash_) {
    const TimerChain* chain = track_data_->GetChain(timer_info.depth());
    if (chain != nullptr) return chain->GetElementAfter(timer_info);
  }
  return nullptr;
}

std::string GpuSubmissionTrack::GetBoxTooltip(const Batcher& batcher, PickingId id) const {
  const TimerInfo* timer_info = batcher.GetTimerInfo(id);
  if ((timer_info == nullptr) || timer_info->type() == TimerInfo::kCoreActivity) {
    return "";
  }

  std::string gpu_stage = string_manager_->Get(timer_info->user_data_key()).value_or("");
  if (gpu_stage == kSwQueueString) {
    return GetSwQueueTooltip(*timer_info);
  }
  if (gpu_stage == kHwQueueString) {
    return GetHwQueueTooltip(*timer_info);
  }
  if (gpu_stage == kHwExecutionString) {
    return GetHwExecutionTooltip(*timer_info);
  }
  if (gpu_stage == kCmdBufferString) {
    return GetCommandBufferTooltip(*timer_info);
  }

  return "";
}

std::string GpuSubmissionTrack::GetSwQueueTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Software Queue
"
      "Time between amdgpu_cs_ioctl (job submitted) and "
      "amdgpu_sched_run_job (job scheduled)"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetHwQueueTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Hardware Queue
Time between amdgpu_sched_run_job "
      "(job scheduled) and start of GPU execution"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetHwExecutionTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Harware Execution
"
      "End is marked by \"dma_fence_signaled\" event for this command "
      "buffer submission"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetCommandBufferTooltip(
    const orbit_client_protos::TimerInfo& timer_info) const {
  return absl::StrFormat(
      "Command Buffer Execution
"
      "At `vkBeginCommandBuffer` and `vkEndCommandBuffer` `vkCmdWriteTimestamp`s have been "
      "inserted. The GPU timestamps get aligned with the corresponding hardware execution of the "
      "submission."
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}
<commit_msg>Fix GetLeft/Right in GPUSubmissionTrack<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "GpuSubmissionTrack.h"

#include <absl/time/time.h>

#include <memory>

#include "App.h"
#include "Batcher.h"
#include "ClientData/TimerChain.h"
#include "DisplayFormats/DisplayFormats.h"
#include "GlUtils.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/ThreadConstants.h"
#include "TimeGraph.h"
#include "TimeGraphLayout.h"
#include "TriangleToggle.h"
#include "absl/strings/str_format.h"
#include "capture_data.pb.h"

using orbit_client_data::TimerChain;
using orbit_client_protos::TimerInfo;

constexpr const char* kSwQueueString = "sw queue";
constexpr const char* kHwQueueString = "hw queue";
constexpr const char* kHwExecutionString = "hw execution";
constexpr const char* kCmdBufferString = "command buffer";

GpuSubmissionTrack::GpuSubmissionTrack(Track* parent, TimeGraph* time_graph,
                                       orbit_gl::Viewport* viewport, TimeGraphLayout* layout,
                                       uint64_t timeline_hash, OrbitApp* app,
                                       const orbit_client_data::CaptureData* capture_data)
    : TimerTrack(parent, time_graph, viewport, layout, app, capture_data) {
  draw_background_ = false;
  text_renderer_ = time_graph->GetTextRenderer();
  timeline_hash_ = timeline_hash;
  string_manager_ = app->GetStringManager();
  parent_ = parent;
}

std::string GpuSubmissionTrack::GetName() const {
  return absl::StrFormat(
      "%s_submissions",
      string_manager_->Get(timeline_hash_).value_or(std::to_string(timeline_hash_)));
}

std::string GpuSubmissionTrack::GetTooltip() const {
  return "Shows scheduling and execution times for selected GPU job "
         "submissions";
}

void GpuSubmissionTrack::OnTimer(const orbit_client_protos::TimerInfo& timer_info) {
  // In case of having command buffer timers, we need to double the depth of the GPU timers (as we
  // are drawing the corresponding command buffer timers below them). Therefore, we watch out for
  // those timers.
  if (timer_info.type() == TimerInfo::kGpuCommandBuffer) {
    has_vulkan_layer_command_buffer_timers_ = true;
  }
  TimerTrack::OnTimer(timer_info);
}

bool GpuSubmissionTrack::IsTimerActive(const TimerInfo& timer_info) const {
  bool is_same_tid_as_selected = timer_info.thread_id() == app_->selected_thread_id();
  // We do not properly track the PID for GPU jobs and we still want to show
  // all jobs as active when no thread is selected, so this logic is a bit
  // different than SchedulerTrack::IsTimerActive.
  bool no_thread_selected = app_->selected_thread_id() == orbit_base::kAllProcessThreadsTid;

  return is_same_tid_as_selected || no_thread_selected;
}

Color GpuSubmissionTrack::GetTimerColor(const TimerInfo& timer_info, bool is_selected,
                                        bool is_highlighted) const {
  const Color kInactiveColor(100, 100, 100, 255);
  const Color kSelectionColor(0, 128, 255, 255);
  if (is_highlighted) {
    return TimerTrack::kHighlightColor;
  }
  if (is_selected) {
    return kSelectionColor;
  }
  if (!IsTimerActive(timer_info)) {
    return kInactiveColor;
  }
  if (timer_info.has_color()) {
    CHECK(timer_info.color().red() < 256);
    CHECK(timer_info.color().green() < 256);
    CHECK(timer_info.color().blue() < 256);
    CHECK(timer_info.color().alpha() < 256);
    return Color(static_cast<uint8_t>(timer_info.color().red()),
                 static_cast<uint8_t>(timer_info.color().green()),
                 static_cast<uint8_t>(timer_info.color().blue()),
                 static_cast<uint8_t>(timer_info.color().alpha()));
  }

  // We color code the timeslices for GPU activity using the color
  // of the CPU thread track that submitted the job.
  Color color = TimeGraph::GetThreadColor(timer_info.thread_id());

  // We disambiguate the different types of GPU activity based on the
  // string that is displayed on their timeslice.
  float coeff = 1.0f;
  std::string gpu_stage = string_manager_->Get(timer_info.user_data_key()).value_or("");
  if (gpu_stage == kSwQueueString) {
    coeff = 0.5f;
  } else if (gpu_stage == kHwQueueString) {
    coeff = 0.75f;
  } else if (gpu_stage == kHwExecutionString) {
    coeff = 1.0f;
  }

  color[0] = static_cast<uint8_t>(coeff * color[0]);
  color[1] = static_cast<uint8_t>(coeff * color[1]);
  color[2] = static_cast<uint8_t>(coeff * color[2]);

  constexpr uint8_t kOddAlpha = 210;
  if ((timer_info.depth() & 0x1) == 0u) {
    color[3] = kOddAlpha;
  }

  return color;
}

float GpuSubmissionTrack::GetYFromTimer(const TimerInfo& timer_info) const {
  auto adjusted_depth = static_cast<float>(timer_info.depth());
  if (IsCollapsed()) {
    adjusted_depth = 0.f;
  }
  CHECK(timer_info.type() == TimerInfo::kGpuActivity ||
        timer_info.type() == TimerInfo::kGpuCommandBuffer);

  // We are drawing a small gap between each depth, for visualization purposes.
  // There won't be a gap between "hw execution"timers and command buffer timers, which
  // is why the gap space needs to be calculated before adjusting the depth further (see below).
  float gap_space = adjusted_depth * layout_->GetSpaceBetweenGpuDepths();

  // Command buffer timers are drawn underneath the matching "hw execution" timer, which has the
  // same depth value as the command buffer timer. Therefore, we need to double the depth in the
  // case that we have command buffer timers.
  if (has_vulkan_layer_command_buffer_timers_) {
    adjusted_depth *= 2.f;
  }

  // Command buffer timers have the same depth value as their matching "hw execution" timer.
  // As we want to draw command buffers underneath the hw execution timers, we need to increase
  // the depth by one.
  if (timer_info.type() == TimerInfo::kGpuCommandBuffer) {
    adjusted_depth += 1.f;
  }
  return pos_[1] - layout_->GetTrackTabHeight() -
         layout_->GetTextBoxHeight() * (adjusted_depth + 1.f) - gap_space;
}

// When track or its parent is collapsed, only draw "hardware execution" timers.
bool GpuSubmissionTrack::TimerFilter(const TimerInfo& timer_info) const {
  if (IsCollapsed()) {
    std::string gpu_stage = string_manager_->Get(timer_info.user_data_key()).value_or("");
    return gpu_stage == kHwExecutionString;
  }
  return true;
}

std::string GpuSubmissionTrack::GetTimesliceText(const TimerInfo& timer_info) const {
  CHECK(timer_info.type() == TimerInfo::kGpuActivity ||
        timer_info.type() == TimerInfo::kGpuCommandBuffer);
  std::string time = GetDisplayTime(timer_info);

  return absl::StrFormat("%s  %s", string_manager_->Get(timer_info.user_data_key()).value_or(""),
                         time);
}

float GpuSubmissionTrack::GetHeight() const {
  bool collapsed = IsCollapsed();
  uint32_t depth = collapsed ? 1 : GetDepth();
  uint32_t num_gaps = depth > 0 ? depth - 1 : 0;
  if (has_vulkan_layer_command_buffer_timers_ && !collapsed) {
    depth *= 2;
  }
  return layout_->GetTrackTabHeight() + layout_->GetTextBoxHeight() * depth +
         (num_gaps * layout_->GetSpaceBetweenGpuDepths()) + layout_->GetTrackBottomMargin();
}

const TimerInfo* GpuSubmissionTrack::GetLeft(const TimerInfo& timer_info) const {
  if (timer_info.timeline_hash() == timeline_hash_) {
    const TimerChain* chain = track_data_->GetChain(timer_info.depth());
    if (chain != nullptr) return chain->GetElementBefore(timer_info);
  }
  return nullptr;
}

const TimerInfo* GpuSubmissionTrack::GetRight(const TimerInfo& timer_info) const {
  if (timer_info.timeline_hash() == timeline_hash_) {
    const TimerChain* chain = track_data_->GetChain(timer_info.depth());
    if (chain != nullptr) return chain->GetElementAfter(timer_info);
  }
  return nullptr;
}

std::string GpuSubmissionTrack::GetBoxTooltip(const Batcher& batcher, PickingId id) const {
  const TimerInfo* timer_info = batcher.GetTimerInfo(id);
  if ((timer_info == nullptr) || timer_info->type() == TimerInfo::kCoreActivity) {
    return "";
  }

  std::string gpu_stage = string_manager_->Get(timer_info->user_data_key()).value_or("");
  if (gpu_stage == kSwQueueString) {
    return GetSwQueueTooltip(*timer_info);
  }
  if (gpu_stage == kHwQueueString) {
    return GetHwQueueTooltip(*timer_info);
  }
  if (gpu_stage == kHwExecutionString) {
    return GetHwExecutionTooltip(*timer_info);
  }
  if (gpu_stage == kCmdBufferString) {
    return GetCommandBufferTooltip(*timer_info);
  }

  return "";
}

std::string GpuSubmissionTrack::GetSwQueueTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Software Queue
"
      "Time between amdgpu_cs_ioctl (job submitted) and "
      "amdgpu_sched_run_job (job scheduled)"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetHwQueueTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Hardware Queue
Time between amdgpu_sched_run_job "
      "(job scheduled) and start of GPU execution"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetHwExecutionTooltip(const TimerInfo& timer_info) const {
  CHECK(capture_data_ != nullptr);
  return absl::StrFormat(
      "Harware Execution
"
      "End is marked by \"dma_fence_signaled\" event for this command "
      "buffer submission"
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}

std::string GpuSubmissionTrack::GetCommandBufferTooltip(
    const orbit_client_protos::TimerInfo& timer_info) const {
  return absl::StrFormat(
      "Command Buffer Execution
"
      "At `vkBeginCommandBuffer` and `vkEndCommandBuffer` `vkCmdWriteTimestamp`s have been "
      "inserted. The GPU timestamps get aligned with the corresponding hardware execution of the "
      "submission."
      "
"
      "
"
      "Submitted from process: %s [%d]
"
      "Submitted from thread: %s [%d]
"
      "Time: %s",
      capture_data_->GetThreadName(timer_info.process_id()), timer_info.process_id(),
      capture_data_->GetThreadName(timer_info.thread_id()), timer_info.thread_id(),
      orbit_display_formats::GetDisplayTime(TicksToDuration(timer_info.start(), timer_info.end()))
          .c_str());
}
<|endoftext|>


<commit_before>// https://oj.leetcode.com/problems/word-break/
namespace WordBreak {
    class Solution {
    public:
        bool wordBreak(string s, unordered_set<string> &dict) {

            if (s.length() == 0) {
                return true;
            }

            if (dict.size() == 0) {
                return false;
            }

            // 1. find the words in dict with min and max length
            unordered_set<string>::const_iterator it = dict.begin();
            int minLen = INT_MAX;
            int maxLen = INT_MIN;
            for (; it != dict.end(); it++) {
                int len = (*it).length();
                if (len < minLen) {
                    minLen = len;
                }

                if (len > maxLen) {
                    maxLen = len;
                }
            }

            // 2. run dp
            bool * dp = new bool[s.length() + 1];
            memset(dp, 0, sizeof(bool) * (s.length() + 1));
            dp[0] = true;
            for (int i = 1; i <= s.length() - minLen + 1; i++) {

                if (dp[i - 1]) {
                    for (int len = minLen; len <= maxLen; len++) {
                        int endPos = i + len - 1;
                        if (endPos > s.length()) {
                            break;
                        }

                        if (dp[endPos] == true) {
                            continue;
                        }

                        string str = s.substr(i - 1, len);
                        if (dict.find(str) != dict.end()) {
                            dp[endPos] = true;
                            continue;
                        }
                    }
                }
            }

            return dp[s.length()];
        }
    };
}
<commit_msg>Update WordBreak.cc<commit_after>// https://oj.leetcode.com/problems/word-break/
namespace WordBreak {
    class Solution {
    public:
        pair<int, int> findMinLenAndMaxLen(unordered_set<string> &dict) {
            int minLen = INT_MAX;
            int maxLen = INT_MIN;
            for (unordered_set<string>::iterator it = dict.begin(); it != dict.end(); it++) {
                const string & cur = *it;
                minLen = min((int)cur.size(), minLen);
                maxLen = max((int)cur.size(), maxLen);
            }
            return make_pair(minLen, maxLen);
        }

        bool wordBreak(string s, unordered_set<string> &dict) {
            if (s.empty()) return false;
            if (dict.empty()) return false;

            pair<int, int> m = findMinLenAndMaxLen(dict);
            int minLen = m.first;
            int maxLen = m.second;
            vector<bool> dp = vector<bool>(s.size() + 1, false);
            dp[0] = true;
            for (int i = 1; i <= s.size(); i++) {
                if (!dp[i - 1]) continue;
                for (int len = minLen; len <= maxLen; len++) {
                    if (i + len - 1 > s.size()) break;
                    string cur = s.substr(i - 1, len);
                    if (dict.find(cur) != dict.end()) {
                        dp[i + len - 1] = true;
                    }
                }
            }

            return dp[s.size()];
        }
    };
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/
#include "modules/common/math/mpc_solver.h"

#include <algorithm>
#include <memory>

#include "modules/common/log.h"
#include "modules/common/math/qp_solver/active_set_qp_solver.h"
#include "modules/common/math/qp_solver/qp_solver.h"

namespace apollo {
namespace common {
namespace math {

using Matrix = Eigen::MatrixXd;

// discrete linear predictive control solver, with control format
// x(i + 1) = A * x(i) + B * u (i) + C
bool SolveLinearMPC(const Matrix &matrix_a, const Matrix &matrix_b,
                    const Matrix &matrix_c, const Matrix &matrix_q,
                    const Matrix &matrix_r, const Matrix &matrix_lower,
                    const Matrix &matrix_upper,
                    const Matrix &matrix_initial_state,
                    const std::vector<Matrix> &reference, const double eps,
                    const int max_iter, std::vector<Matrix> *control) {
  if (matrix_a.rows() != matrix_a.cols() ||
      matrix_b.rows() != matrix_a.rows() ||
      matrix_lower.rows() != matrix_upper.rows()) {
    AERROR << "One or more matrices have incompatible dimensions. Aborting.";
    return false;
  }

  unsigned int horizon = reference.size();

  // Update augment reference matrix_t
  Matrix matrix_t = Matrix::Zero(matrix_b.rows() * horizon, 1);
  for (unsigned int j = 0; j < horizon; ++j) {
    matrix_t.block(j * reference[0].size(), 0, reference[0].size(), 1) =
        reference[j];
  }

  // Update augment control matrix_v
  Matrix matrix_v = Matrix::Zero((*control)[0].rows() * horizon, 1);
  for (unsigned int j = 0; j < horizon; ++j) {
    matrix_v.block(j * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        (*control)[j];
  }

  std::vector<Matrix> matrix_a_power(horizon);
  matrix_a_power[0] = matrix_a;
  for (unsigned int i = 1; i < matrix_a_power.size(); ++i) {
    matrix_a_power[i] = matrix_a * matrix_a_power[i - 1];
  }

  Matrix matrix_k =
      Matrix::Zero(matrix_b.rows() * horizon, matrix_b.cols() * horizon);
  for (unsigned int r = 0; r < horizon; ++r) {
    for (unsigned int c = 0; c <= r; ++c) {
      matrix_k.block(r * matrix_b.rows(), c * matrix_b.cols(), matrix_b.rows(),
                     matrix_b.cols()) = matrix_a_power[r - c] * matrix_b;
    }
  }
  // Initialize matrix_k, matrix_m, matrix_t and matrix_v, matrix_qq, matrix_rr,
  // vector of matrix A power
  Matrix matrix_m = Matrix::Zero(matrix_b.rows() * horizon, 1);
  Matrix matrix_qq = Matrix::Zero(matrix_k.rows(), matrix_k.rows());
  Matrix matrix_rr = Matrix::Zero(matrix_k.cols(), matrix_k.cols());
  Matrix matrix_ll = Matrix::Zero(horizon * matrix_lower.rows(), 1);
  Matrix matrix_uu = Matrix::Zero(horizon * matrix_upper.rows(), 1);

  // Compute matrix_m
  matrix_m.block(0, 0, matrix_a.rows(), 1) =
      matrix_a * matrix_initial_state + matrix_c;
  for (unsigned int i = 1; i < horizon; ++i) {
    matrix_m.block(i * matrix_a.rows(), 0, matrix_a.rows(), 1) =
        matrix_a *
            matrix_m.block((i - 1) * matrix_a.rows(), 0, matrix_a.rows(), 1) +
        matrix_c;
  }

  // Compute matrix_ll, matrix_uu, matrix_qq, matrix_rr
  for (unsigned int i = 0; i < horizon; ++i) {
    matrix_ll.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        matrix_lower;
    matrix_uu.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        matrix_upper;
    matrix_qq.block(i * matrix_q.rows(), i * matrix_q.rows(), matrix_q.rows(),
                    matrix_q.rows()) = matrix_q;
    matrix_rr.block(i * matrix_r.rows(), i * matrix_r.rows(), matrix_r.cols(),
                    matrix_r.cols()) = matrix_r;
  }

  // Update matrix_m1, matrix_m2, convert MPC problem to QP problem done
  Matrix matrix_m1 = matrix_k.transpose() * matrix_qq * matrix_k + matrix_rr;
  Matrix matrix_m2 = matrix_k.transpose() * matrix_qq * (matrix_m - matrix_t);

  // Format in qp_solver
  /**
   * *           min_x  : q(x) = 0.5 * x^T * Q * x  + x^T c
   * *           with respect to:  A * x = b (equality constraint)
   * *                             C * x >= d (inequality constraint)
   * **/

  // TODO(QiL) : change qp solver to box constraint or substitue QPOAESE
  // Method 1: QPOASES
  Matrix matrix_inequality_constrain_ll =
      Matrix::Identity(matrix_ll.rows(), matrix_ll.rows());
  Matrix matrix_inequality_constrain_uu =
      Matrix::Identity(matrix_uu.rows(), matrix_uu.rows());
  Matrix matrix_inequality_constrain =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.rows());
  matrix_inequality_constrain << matrix_inequality_constrain_ll,
      -matrix_inequality_constrain_uu;
  Matrix matrix_inequality_boundary =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.cols());
  matrix_inequality_boundary << matrix_ll, -matrix_uu;
  Matrix matrix_equality_constrain =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.rows());
  Matrix matrix_equality_boundary =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.cols());

  std::unique_ptr<QpSolver> qp_solver(new ActiveSetQpSolver(
      matrix_m1, matrix_m2, matrix_inequality_constrain,
      matrix_inequality_boundary, matrix_equality_constrain,
      matrix_equality_boundary));
  auto result = qp_solver->Solve();
  if (!result) {
    AERROR << "Linear MPC solver failed";
    return false;
  }
  matrix_v = qp_solver->params();

  for (unsigned int i = 0; i < horizon; ++i) {
    (*control)[i] =
        matrix_v.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1);
  }
  return true;
}

}  // namespace math
}  // namespace common
}  // namespace apollo
<commit_msg>Common : Fix typo<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/
#include "modules/common/math/mpc_solver.h"

#include <algorithm>
#include <memory>

#include "modules/common/log.h"
#include "modules/common/math/qp_solver/active_set_qp_solver.h"
#include "modules/common/math/qp_solver/qp_solver.h"

namespace apollo {
namespace common {
namespace math {

using Matrix = Eigen::MatrixXd;

// discrete linear predictive control solver, with control format
// x(i + 1) = A * x(i) + B * u (i) + C
bool SolveLinearMPC(const Matrix &matrix_a, const Matrix &matrix_b,
                    const Matrix &matrix_c, const Matrix &matrix_q,
                    const Matrix &matrix_r, const Matrix &matrix_lower,
                    const Matrix &matrix_upper,
                    const Matrix &matrix_initial_state,
                    const std::vector<Matrix> &reference, const double eps,
                    const int max_iter, std::vector<Matrix> *control) {
  if (matrix_a.rows() != matrix_a.cols() ||
      matrix_b.rows() != matrix_a.rows() ||
      matrix_lower.rows() != matrix_upper.rows()) {
    AERROR << "One or more matrices have incompatible dimensions. Aborting.";
    return false;
  }

  unsigned int horizon = reference.size();

  // Update augment reference matrix_t
  Matrix matrix_t = Matrix::Zero(matrix_b.rows() * horizon, 1);
  for (unsigned int j = 0; j < horizon; ++j) {
    matrix_t.block(j * reference[0].size(), 0, reference[0].size(), 1) =
        reference[j];
  }

  // Update augment control matrix_v
  Matrix matrix_v = Matrix::Zero((*control)[0].rows() * horizon, 1);
  for (unsigned int j = 0; j < horizon; ++j) {
    matrix_v.block(j * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        (*control)[j];
  }

  std::vector<Matrix> matrix_a_power(horizon);
  matrix_a_power[0] = matrix_a;
  for (unsigned int i = 1; i < matrix_a_power.size(); ++i) {
    matrix_a_power[i] = matrix_a * matrix_a_power[i - 1];
  }

  Matrix matrix_k =
      Matrix::Zero(matrix_b.rows() * horizon, matrix_b.cols() * horizon);
  for (unsigned int r = 0; r < horizon; ++r) {
    for (unsigned int c = 0; c <= r; ++c) {
      matrix_k.block(r * matrix_b.rows(), c * matrix_b.cols(), matrix_b.rows(),
                     matrix_b.cols()) = matrix_a_power[r - c] * matrix_b;
    }
  }
  // Initialize matrix_k, matrix_m, matrix_t and matrix_v, matrix_qq, matrix_rr,
  // vector of matrix A power
  Matrix matrix_m = Matrix::Zero(matrix_b.rows() * horizon, 1);
  Matrix matrix_qq = Matrix::Zero(matrix_k.rows(), matrix_k.rows());
  Matrix matrix_rr = Matrix::Zero(matrix_k.cols(), matrix_k.cols());
  Matrix matrix_ll = Matrix::Zero(horizon * matrix_lower.rows(), 1);
  Matrix matrix_uu = Matrix::Zero(horizon * matrix_upper.rows(), 1);

  // Compute matrix_m
  matrix_m.block(0, 0, matrix_a.rows(), 1) =
      matrix_a * matrix_initial_state + matrix_c;
  for (unsigned int i = 1; i < horizon; ++i) {
    matrix_m.block(i * matrix_a.rows(), 0, matrix_a.rows(), 1) =
        matrix_a *
            matrix_m.block((i - 1) * matrix_a.rows(), 0, matrix_a.rows(), 1) +
        matrix_c;
  }

  // Compute matrix_ll, matrix_uu, matrix_qq, matrix_rr
  for (unsigned int i = 0; i < horizon; ++i) {
    matrix_ll.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        matrix_lower;
    matrix_uu.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1) =
        matrix_upper;
    matrix_qq.block(i * matrix_q.rows(), i * matrix_q.rows(), matrix_q.rows(),
                    matrix_q.rows()) = matrix_q;
    matrix_rr.block(i * matrix_r.rows(), i * matrix_r.rows(), matrix_r.cols(),
                    matrix_r.cols()) = matrix_r;
  }

  // Update matrix_m1, matrix_m2, convert MPC problem to QP problem done
  Matrix matrix_m1 = matrix_k.transpose() * matrix_qq * matrix_k + matrix_rr;
  Matrix matrix_m2 = matrix_k.transpose() * matrix_qq * (matrix_m - matrix_t);

  // Format in qp_solver
  /**
   * *           min_x  : q(x) = 0.5 * x^T * Q * x  + x^T c
   * *           with respect to:  A * x = b (equality constraint)
   * *                             C * x >= d (inequality constraint)
   * **/

  // TODO(QiL) : change qp solver to box constraint or substitute QPOASES
  // Method 1: QPOASES
  Matrix matrix_inequality_constrain_ll =
      Matrix::Identity(matrix_ll.rows(), matrix_ll.rows());
  Matrix matrix_inequality_constrain_uu =
      Matrix::Identity(matrix_uu.rows(), matrix_uu.rows());
  Matrix matrix_inequality_constrain =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.rows());
  matrix_inequality_constrain << matrix_inequality_constrain_ll,
      -matrix_inequality_constrain_uu;
  Matrix matrix_inequality_boundary =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.cols());
  matrix_inequality_boundary << matrix_ll, -matrix_uu;
  Matrix matrix_equality_constrain =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.rows());
  Matrix matrix_equality_boundary =
      Matrix::Zero(matrix_ll.rows() + matrix_uu.rows(), matrix_ll.cols());

  std::unique_ptr<QpSolver> qp_solver(new ActiveSetQpSolver(
      matrix_m1, matrix_m2, matrix_inequality_constrain,
      matrix_inequality_boundary, matrix_equality_constrain,
      matrix_equality_boundary));
  auto result = qp_solver->Solve();
  if (!result) {
    AERROR << "Linear MPC solver failed";
    return false;
  }
  matrix_v = qp_solver->params();

  for (unsigned int i = 0; i < horizon; ++i) {
    (*control)[i] =
        matrix_v.block(i * (*control)[0].rows(), 0, (*control)[0].rows(), 1);
  }
  return true;
}

}  // namespace math
}  // namespace common
}  // namespace apollo
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//                       Copyright (c) 2011 - 2012 by                        //
//                                Simon Pratt                                //
//                           (All rights reserved)                           //
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// FILE:    test_pst.cpp                                                     //
//                                                                           //
// MODULE:  Priority Search Tree                                             //
//                                                                           //
// NOTES:   None.                                                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <time.h>
#include <assert.h>
#include "PSTPoint.h"
#include "InPlacePST.h"
#include "array_utilities.h"
#include "control_utilities.h"

using namespace std;
using namespace PrioritySearchTree;

// Dirty hack, but hey: it's c++!
PSTPoint* vectorPointerToArray(vector<PSTPoint>* v) {
  return &(*v)[0];
}

int main(int argv, char** argc) {
  const int MAX_POINTS_DISPLAY = 16;
  bool QUIET_MODE = false;
  time_t before, after;
  int n, qi;
  /////////////////////////////////////////////////////////////////////////////
  // Seed the PRNG                                                           //
  /////////////////////////////////////////////////////////////////////////////
  srand( time(0) );
  /////////////////////////////////////////////////////////////////////////////
  // Ensure the user has entered required parameters, otherwise print        //
  // a helpful message.                                                      //
  /////////////////////////////////////////////////////////////////////////////
  if(argv < 3) {
    cout << "Usage: test_pst [number of points] [query iterations] [quiet]"
	 << endl;
    return 1;
  }
  // parse number of points
  n = atoi(argc[1]);
  // parse query iterations
  qi = atoi(argc[2]);
  // check for quiet mode
  if(argv > 3)
    QUIET_MODE = true;
  /////////////////////////////////////////////////////////////////////////////
  // Create Points                                                           //
  /////////////////////////////////////////////////////////////////////////////
  cout << "Creating " << n << " points..." << flush;
  before = time(0);
  PSTPoint *points = new PSTPoint[n]; // allocate on the heap
  for(int i = 1; i < n; i++) {
    PSTPoint p(i,i); // allocate on the stack
    points[i] = p;
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  if(n <= MAX_POINTS_DISPLAY) {
    cout << "Points: ";
    PSTArray::print(points,n);
  }
  /////////////////////////////////////////////////////////////////////////////
  // Build tree                                                              //
  /////////////////////////////////////////////////////////////////////////////
  cout << "Building tree..." << flush;
  before = time(0);
  InPlacePST ippst(points,n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  delete points;
  /////////////////////////////////////////////////////////////////////////////
  // Check memory - quietly or manually                                      //
  /////////////////////////////////////////////////////////////////////////////
  if(QUIET_MODE) {
    cout << "Memory usage(%): " << flush;
    // this next line is system-specific, but should work on any
    // reasonable unix compatible system.  Procedure:
    //   1. Ask for detailed information on processes
    //   2. filter out all lines which don't have the name of the program
    //   3. filter out all lines which have the word grep
    //   4. filter out all lines which have the word "ps "
    //   5. print the 4th column (memory usage)
    assert(system("ps auxww | grep test_pst | grep -v grep | grep -v ps\\ | awk '{print $4}'") == 0);
  } else {
    control_utilities::waitForAnyKey();
  }
  /////////////////////////////////////////////////////////////////////////////
  // Print the structure if the number of points is small                    //
  /////////////////////////////////////////////////////////////////////////////
  if(n <= MAX_POINTS_DISPLAY) {
    cout << "Tree: " << endl;
    ippst.printTree();
  }
  /////////////////////////////////////////////////////////////////////////////
  // leftMostNE                                                              //
  /////////////////////////////////////////////////////////////////////////////
  PSTPoint result;
  cout << qi << " iterations of ";
  cout << "leftMostNE..." << flush;
  before = time(0);
  for(int i = 0; i < qi; i++)
    result = ippst.leftMostNE(rand() % n, rand() % n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // highestNE                                                               //
  /////////////////////////////////////////////////////////////////////////////
  cout << qi << " iterations of ";
  cout << "highestNE..." << flush;
  before = time(0);
  for(int i = 0; i < qi; i++)
    result = ippst.highestNE(rand() % n, rand() % n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // highest3Sided                                                           //
  /////////////////////////////////////////////////////////////////////////////
  cout << qi << " iterations of ";
  cout << "highest3Sided..." << flush;
  int xmin = 0, xmax = 0, ymin = 0;
  before = time(0);
  for(int i = 0; i < qi; i++) {
    xmin = rand() % n;
    xmax = xmin + (rand() % (n - xmin));
    ymin = rand() % n;
    result = ippst.highest3Sided(xmin,xmax,ymin);
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // enumerate3Sided                                                         //
  /////////////////////////////////////////////////////////////////////////////
  vector<PSTPoint>* results;
  cout << qi << " iterations of ";
  cout << "enumerate3Sided..." << flush;
  before = time(0);
  for(int i = 0; i < qi; i++) {
    xmin = rand() % n;
    xmax = xmin + (rand() % (n - xmin));
    results = ippst.enumerate3Sided(xmin,xmax,rand() % n);
    delete results;
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  return 0;
}
<commit_msg>Now able to specify how many enumeration iterations<commit_after>///////////////////////////////////////////////////////////////////////////////
//                       Copyright (c) 2011 - 2012 by                        //
//                                Simon Pratt                                //
//                           (All rights reserved)                           //
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// FILE:    test_pst.cpp                                                     //
//                                                                           //
// MODULE:  Priority Search Tree                                             //
//                                                                           //
// NOTES:   None.                                                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <time.h>
#include <assert.h>
#include "PSTPoint.h"
#include "InPlacePST.h"
#include "array_utilities.h"
#include "control_utilities.h"

using namespace std;
using namespace PrioritySearchTree;

// Dirty hack, but hey: it's c++!
PSTPoint* vectorPointerToArray(vector<PSTPoint>* v) {
  return &(*v)[0];
}

int main(int argv, char** argc) {
  const int MAX_POINTS_DISPLAY = 16;
  bool QUIET_MODE = false;
  time_t before, after;
  int n, qi, ei;
  /////////////////////////////////////////////////////////////////////////////
  // Seed the PRNG                                                           //
  /////////////////////////////////////////////////////////////////////////////
  srand( time(0) );
  /////////////////////////////////////////////////////////////////////////////
  // Ensure the user has entered required parameters, otherwise print        //
  // a helpful message.                                                      //
  /////////////////////////////////////////////////////////////////////////////
  if(argv < 3) {
    cout << "Usage: test_pst [number of points] [query iterations] "
	 << "[enumerate iterations] [quiet]" << endl;
    return 1;
  }
  // parse number of points
  n = atoi(argc[1]);
  // parse query iterations
  qi = atoi(argc[2]);
  // parse enumerate iterations
  ei = atoi(argc[3]);
  // check for quiet mode
  if(argv > 4)
    QUIET_MODE = true;
  /////////////////////////////////////////////////////////////////////////////
  // Create Points                                                           //
  /////////////////////////////////////////////////////////////////////////////
  cout << "Creating " << n << " points..." << flush;
  before = time(0);
  PSTPoint *points = new PSTPoint[n]; // allocate on the heap
  for(int i = 1; i < n; i++) {
    PSTPoint p(i,i); // allocate on the stack
    points[i] = p;
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  if(n <= MAX_POINTS_DISPLAY) {
    cout << "Points: ";
    PSTArray::print(points,n);
  }
  /////////////////////////////////////////////////////////////////////////////
  // Build tree                                                              //
  /////////////////////////////////////////////////////////////////////////////
  cout << "Building tree..." << flush;
  before = time(0);
  InPlacePST ippst(points,n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  delete points;
  /////////////////////////////////////////////////////////////////////////////
  // Check memory - quietly or manually                                      //
  /////////////////////////////////////////////////////////////////////////////
  if(QUIET_MODE) {
    cout << "Memory usage(%): " << flush;
    // this next line is system-specific, but should work on any
    // reasonable unix compatible system.  Procedure:
    //   1. Ask for detailed information on processes
    //   2. filter out all lines which don't have the name of the program
    //   3. filter out all lines which have the word grep
    //   4. filter out all lines which have the word "ps "
    //   5. print the 4th column (memory usage)
    assert(system("ps auxww | grep test_pst | grep -v grep | grep -v ps\\ | awk '{print $4}'") == 0);
  } else {
    control_utilities::waitForAnyKey();
  }
  /////////////////////////////////////////////////////////////////////////////
  // Print the structure if the number of points is small                    //
  /////////////////////////////////////////////////////////////////////////////
  if(n <= MAX_POINTS_DISPLAY) {
    cout << "Tree: " << endl;
    ippst.printTree();
  }
  /////////////////////////////////////////////////////////////////////////////
  // leftMostNE                                                              //
  /////////////////////////////////////////////////////////////////////////////
  PSTPoint result;
  cout << qi << " iterations of ";
  cout << "leftMostNE..." << flush;
  before = time(0);
  for(int i = 0; i < qi; i++)
    result = ippst.leftMostNE(rand() % n, rand() % n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // highestNE                                                               //
  /////////////////////////////////////////////////////////////////////////////
  cout << qi << " iterations of ";
  cout << "highestNE..." << flush;
  before = time(0);
  for(int i = 0; i < qi; i++)
    result = ippst.highestNE(rand() % n, rand() % n);
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // highest3Sided                                                           //
  /////////////////////////////////////////////////////////////////////////////
  cout << qi << " iterations of ";
  cout << "highest3Sided..." << flush;
  int xmin = 0, xmax = 0, ymin = 0;
  before = time(0);
  for(int i = 0; i < qi; i++) {
    xmin = rand() % n;
    xmax = xmin + (rand() % (n - xmin));
    ymin = rand() % n;
    result = ippst.highest3Sided(xmin,xmax,ymin);
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  /////////////////////////////////////////////////////////////////////////////
  // enumerate3Sided                                                         //
  /////////////////////////////////////////////////////////////////////////////
  vector<PSTPoint>* results;
  cout << ei << " iterations of ";
  cout << "enumerate3Sided..." << flush;
  before = time(0);
  for(int i = 0; i < ei; i++) {
    xmin = rand() % n;
    xmax = xmin + (rand() % (n - xmin));
    results = ippst.enumerate3Sided(xmin,xmax,rand() % n);
    delete results;
  }
  after = time(0);
  cout << "took: " << (after - before) << endl;
  return 0;
}
<|endoftext|>


<commit_before>{
	cout << "rootlogon.C for UCNSIM" << endl;
	cout << "-------------------------------------" << endl;
  	if ( gSystem->Load("libPhysics") == 0 ) {
    cout << "Successfully loaded libPhysics.so" << endl;
  	}
	if ( gSystem->Load("libGeom.so") == 0 ) {
    cout << "Successfully loaded libGeom.so" << endl;
  	}
  	if ( gSystem->Load("libGeomPainter.so") == 0 ) {
    cout << "Successfully loaded libGeomPainter.so" << endl;
  	}
 	if ( gSystem->Load("libTree.so") == 0 ) {
	    cout << "Successfully loaded libTree.so" << endl;
	}
 	if ( gSystem->Load("libEG.so") == 0 ) {
	    cout << "Successfully loaded libEG.so" << endl;
	}
	if ( gSystem->Load("libMathCore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	if ( gSystem->Load("libMathMore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	TString ucnsim = gSystem->Getenv("UCN_DIR");
	if ( ucnsim.Length() == 0 ) {
		cerr << "-------------------------------------" << endl;
		cerr << "Warning: Failed to find env. variable UCNSIM" << endl;
		cerr << "-------------------------------------" << endl;
	}
	else {
		TString ucnlib = ucnsim + "/lib/libUCN.so";
		cerr << ucnlib.Data() << endl;
		if ( gSystem->Load(ucnlib.Data()) == 0 ) {
		   cout << "Successfully loaded libUCN.so" << endl;
  	   }
	}

   TString magdir = gSystem->Getenv("MAGDIR");
	if ( magdir.Length() == 0 ) {
		cerr << "-------------------------------------" << endl;
		cerr << "Warning: Failed to find env. variable MAGDIR" << endl;
		cerr << "-------------------------------------" << endl;
	}
	else {
		TString maglib = magdir + "/lib/libEDM.so";
		cerr << maglib.Data() << endl;
		if ( gSystem->Load(maglib.Data()) == 0 ) {
		   cout << "Successfully loaded libEDM.so" << endl;
  	   }
   }
	cout << "-------------------------------------" << endl;
	set_my_style();
}
<commit_msg>Cleaned up some garbage in rootlogon<commit_after>{
   cout << "rootlogon.C for UCNSIM" << endl;
   cout << "-------------------------------------" << endl;
   if ( gSystem->Load("libPhysics") == 0 ) {
      cout << "Successfully loaded libPhysics.so" << endl;
   }
   if ( gSystem->Load("libGeom.so") == 0 ) {
      cout << "Successfully loaded libGeom.so" << endl;
   }
   if ( gSystem->Load("libGeomPainter.so") == 0 ) {
      cout << "Successfully loaded libGeomPainter.so" << endl;
   }
   if ( gSystem->Load("libTree.so") == 0 ) {
      cout << "Successfully loaded libTree.so" << endl;
   }
   if ( gSystem->Load("libEG.so") == 0 ) {
      cout << "Successfully loaded libEG.so" << endl;
   }
   if ( gSystem->Load("libMathCore.so") == 0 ) {
       cout << "Successfully loaded libMathCore.so" << endl;
   }
   if ( gSystem->Load("libMathMore.so") == 0 ) {
       cout << "Successfully loaded libMathCore.so" << endl;
   }
   TString ucnsim = gSystem->Getenv("UCN_DIR");
   if ( ucnsim.Length() == 0 ) {
      cerr << "-------------------------------------" << endl;
      cerr << "Warning: Failed to find env. variable UCNSIM" << endl;
      cerr << "-------------------------------------" << endl;
   }
   else {
      TString ucnlib = ucnsim + "/lib/libUCN.so";
      cerr << ucnlib.Data() << endl;
      if ( gSystem->Load(ucnlib.Data()) == 0 ) {
         cout << "Successfully loaded libUCN.so" << endl;
      }
   }
   cout << "-------------------------------------" << endl;
   set_my_style();
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if !defined(ARENABLOCK_INCLUDE_GUARD_1357924680)
#define ARENABLOCK_INCLUDE_GUARD_1357924680

#include <algorithm>
#include <cassert>
#include <set>
#include <memory>

#if defined(XALAN_NO_STD_ALLOCATORS) && !defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)
#include <PlatformSupport/XalanAllocator.hpp>
#endif

#if defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)

template <class Type>
class ArenaBlockAllocator
{
public:

	typedef size_t			size_type;
	typedef ptrdiff_t		difference_type;
	typedef Type*			pointer;
	typedef const Type*		const_pointer;
	typedef Type&			reference;
	typedef const Type&		const_reference;
	typedef Type			value_type;

	ArenaBlockAllocator()
	{
	}

	ArenaBlockAllocator(const ArenaBlockAllocator<Type>&)
	{
	};

	~ArenaBlockAllocator()
	{
	}

	pointer
	allocate(
			size_type		size,
			const void*		/* hint */ = 0)
	{
		return (pointer)operator new(size * sizeof(Type));
	}

	void
	deallocate(
				pointer		p,
				size_type	/* n */)
	{
		operator delete(p);
	}
};
#endif

template<class ObjectType>
class ArenaBlockDestroy
{
public:

	void
	operator()(ObjectType&	theObject) const
	{
		theObject.ObjectType::~ObjectType();
	}
};

template<class ObjectType>
class ArenaBlock
{
public:

#if defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)
	typedef ArenaBlockAllocator<ObjectType>		AllocatorType;
#elif defined(XALAN_NO_STD_ALLOCATORS)
	typedef XalanAllocator<ObjectType>			AllocatorType;
#else
	typedef std::allocator<ObjectType>			AllocatorType;
#endif

	typedef ArenaBlockDestroy<ObjectType>		DestroyFunctionType;

	typedef typename AllocatorType::size_type	size_type;

	/*
	 * Construct an ArenaBlock of the specified size
	 * of objects.
	 *
	 * @param theBlockSize The size of the block (the number of objects it can contain).
	 */
	ArenaBlock(size_type	theBlockSize) :
		m_destroyFunction(DestroyFunctionType()),
		m_objectCount(0),
		m_blockSize(theBlockSize),
		m_objectBlock(0),
		m_allocator()
	{
		assert(theBlockSize > 0);
	}

	virtual
	~ArenaBlock()
	{
		destroyAll();

		// Release the memory...
		m_allocator.deallocate(m_objectBlock, 0);
	}

	/*
	 * Allocate a block.  Once the object is constructed, you must call
	 * commitAllocation().
	 *
	 * @return a pointer to the new block.
	 */
	virtual ObjectType*
	allocateBlock()
	{
		// Any space left?
		if (m_objectCount == m_blockSize)
		{
			return 0;
		}
		else
		{
			// If no memory has yet been allocated, then allocate it...
			if (m_objectBlock == 0)
			{
#if defined(XALAN_NEW_STD_ALLOCATOR)
				m_objectBlock = m_allocator.allocate(m_blockSize);
#else
				m_objectBlock = m_allocator.allocate(m_blockSize, 0);
#endif
			}
			assert(m_objectBlock != 0);

			return m_objectBlock + m_objectCount;
		}
	}

	/*
	 * Commit the previous allocation.
	 *
	 * @param theBlock the address that was returned by allocateBlock()
	 */
	virtual void
#if defined (NDEBUG)
	commitAllocation(ObjectType*	/* theBlock */)
#else
	commitAllocation(ObjectType*	theBlock)
#endif
	{
		assert(theBlock == m_objectBlock + m_objectCount);
		assert(m_objectCount < m_blockSize);

		m_objectCount++;
	}

	/*
	 * Find out if there is a block available.
	 *
	 * @return true if one is available, false if not.
	 */
	virtual bool
	blockAvailable() const
	{
		return m_objectCount < m_blockSize ? true : false;
	}

	/*
	 * Get the number of objects currently allocated in the
	 * block.
	 *
	 * @return The number of objects allocated.
	 */
	virtual size_type
	getCountAllocated() const
	{
		return m_objectCount;
	}

	/*
	 * Get the block size, that is, the number
	 * of objects in each block.
	 *
	 * @return The size of the block
	 */
	size_type
	getBlockSize() const
	{
		return m_blockSize;
	}

	/*
	 * Determine if this block owns the specified object.  Note
	 * that even if the object address is within our block, this
	 * call will return false if no object currently occupies the
	 * block.  See also ownsBlock().
	 *
	 * @param theObject the address of the object.
	 * @return true if we own the object, false if not.
	 */
	virtual bool
	ownsObject(const ObjectType*	theObject) const
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::less;
#endif

		// Use less<>, since it's guaranteed to do pointer
		// comparisons correctly...
		less<const ObjectType*>		functor;

		if (functor(theObject, m_objectBlock) == false &&
			functor(theObject, m_objectBlock + m_objectCount) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/*
	 * Determine if this block owns the specified object block.
	 * Note that, unlike ownsObject(), there does not need to
	 * be an object at the address.
	 *
	 * @param theObject the address of the object
	 * @return true if we own the object block, false if not.
	 */
	bool
	ownsBlock(const ObjectType*		theObject) const
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::less;
#endif

		// Use less<>, since it's guaranteed to do pointer
		// comparisons correctly...
		less<const ObjectType*>		functor;

		if (functor(theObject, m_objectBlock) == false &&
			functor(theObject, m_objectBlock + m_blockSize) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/*
	 * Destroy all objects in the block.  You can then reuse the
	 * block.
	 */
	void
	destroyAll()
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::for_each;
#endif

		// Destroy all existing objects...
		for_each(m_objectBlock,
				 m_objectBlock + m_objectCount,
				 DeleteFunctor(*this, m_destroyFunction));

		m_objectCount = 0;
	}

protected:

	/*
	 * Determine if the block should be destroyed.  Called by
	 * an instance of DeleteFunctor, this function is for
	 * deriving classes that might want to control the destruction
	 * of things.
	 *
	 * @param theObject the address of the object
	 * @return true if block should be destroyed, false if not.
	 */
	virtual bool
	shouldDestroyBlock(const ObjectType*	/* theObject */) const
	{
		return true;
	}

	/*
	 * Determine the offset into the block for the given address.
	 * Behavior is undefined if the address is not within our
	 * block
	 *
	 * @param theObject the address of the object
	 * @return the offset
	 */
	size_type
	getBlockOffset(const ObjectType*	theObject) const
	{
		assert(size_type(theObject - m_objectBlock) < m_blockSize);

		return theObject - m_objectBlock;
	}

	/*
	 * Determine the address within our block of the object
	 * at the specified offset.
	 * Behavior is undefined if the offset is greater than the
	 * block size.
	 *
	 * @param theObject the address of the object
	 * @return the offset
	 */
	ObjectType*
	getBlockAddress(size_type	theOffset) const
	{
		assert(theOffset < m_blockSize);

		return m_objectBlock + theOffset;
	}

	struct DeleteFunctor
	{
		DeleteFunctor(
				const ArenaBlock<ObjectType>&	theArenaBlock,
				const DestroyFunctionType&		theDestroyFunction) :
			m_arenaBlock(theArenaBlock),
			m_destroyFunction(theDestroyFunction)
		{
		}

		void
		operator()(ObjectType&	theObject) const
		{
			if (m_arenaBlock.shouldDestroyBlock(&theObject) == true)
			{
				m_destroyFunction(theObject);
			}
		}

	private:

		const ArenaBlock<ObjectType>&	m_arenaBlock;
		const DestroyFunctionType&		m_destroyFunction;
	};

	friend struct DeleteFunctor;

	const DestroyFunctionType	m_destroyFunction;

private:

	// Not implemented...
	ArenaBlock(const ArenaBlock<ObjectType>&);

	ArenaBlock<ObjectType>&
	operator=(const ArenaBlock<ObjectType>&);

	bool
	operator==(const ArenaBlock<ObjectType>&) const;

	// data members...
	size_type			m_objectCount;

	const size_type		m_blockSize;

	ObjectType*			m_objectBlock;

	AllocatorType		m_allocator;
};

#endif	// !defined(ARENABLOCK_INCLUDE_GUARD_1357924680)
<commit_msg>Added workaround for broken IBM compiler.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if !defined(ARENABLOCK_INCLUDE_GUARD_1357924680)
#define ARENABLOCK_INCLUDE_GUARD_1357924680

#include <algorithm>
#include <cassert>
#include <set>
#include <memory>

#if defined(XALAN_NO_STD_ALLOCATORS) && !defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)
#include <PlatformSupport/XalanAllocator.hpp>
#endif

#if defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)

template <class Type>
class ArenaBlockAllocator
{
public:

	typedef size_t			size_type;
	typedef ptrdiff_t		difference_type;
	typedef Type*			pointer;
	typedef const Type*		const_pointer;
	typedef Type&			reference;
	typedef const Type&		const_reference;
	typedef Type			value_type;

	ArenaBlockAllocator()
	{
	}

	ArenaBlockAllocator(const ArenaBlockAllocator<Type>&)
	{
	};

	~ArenaBlockAllocator()
	{
	}

	pointer
	allocate(
			size_type		size,
			const void*		/* hint */ = 0)
	{
		return (pointer)operator new(size * sizeof(Type));
	}

	void
	deallocate(
				pointer		p,
				size_type	/* n */)
	{
		operator delete(p);
	}
};
#endif

template<class ObjectType>
class ArenaBlockDestroy
{
public:

	void
	operator()(ObjectType&	theObject) const
	{
#if defined(XALAN_EXPLICIT_SCOPE_IN_TEMPLATE_BUG)
		theObject.~ObjectType();
#else
		theObject.ObjectType::~ObjectType();
#endif
	}
};

template<class ObjectType>
class ArenaBlock
{
public:

#if defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)
	typedef ArenaBlockAllocator<ObjectType>		AllocatorType;
#elif defined(XALAN_NO_STD_ALLOCATORS)
	typedef XalanAllocator<ObjectType>			AllocatorType;
#else
	typedef std::allocator<ObjectType>			AllocatorType;
#endif

	typedef ArenaBlockDestroy<ObjectType>		DestroyFunctionType;

	typedef typename AllocatorType::size_type	size_type;

	/*
	 * Construct an ArenaBlock of the specified size
	 * of objects.
	 *
	 * @param theBlockSize The size of the block (the number of objects it can contain).
	 */
	ArenaBlock(size_type	theBlockSize) :
		m_destroyFunction(DestroyFunctionType()),
		m_objectCount(0),
		m_blockSize(theBlockSize),
		m_objectBlock(0),
		m_allocator()
	{
		assert(theBlockSize > 0);
	}

	virtual
	~ArenaBlock()
	{
		destroyAll();

		// Release the memory...
		m_allocator.deallocate(m_objectBlock, 0);
	}

	/*
	 * Allocate a block.  Once the object is constructed, you must call
	 * commitAllocation().
	 *
	 * @return a pointer to the new block.
	 */
	virtual ObjectType*
	allocateBlock()
	{
		// Any space left?
		if (m_objectCount == m_blockSize)
		{
			return 0;
		}
		else
		{
			// If no memory has yet been allocated, then allocate it...
			if (m_objectBlock == 0)
			{
#if defined(XALAN_NEW_STD_ALLOCATOR)
				m_objectBlock = m_allocator.allocate(m_blockSize);
#else
				m_objectBlock = m_allocator.allocate(m_blockSize, 0);
#endif
			}
			assert(m_objectBlock != 0);

			return m_objectBlock + m_objectCount;
		}
	}

	/*
	 * Commit the previous allocation.
	 *
	 * @param theBlock the address that was returned by allocateBlock()
	 */
	virtual void
#if defined (NDEBUG)
	commitAllocation(ObjectType*	/* theBlock */)
#else
	commitAllocation(ObjectType*	theBlock)
#endif
	{
		assert(theBlock == m_objectBlock + m_objectCount);
		assert(m_objectCount < m_blockSize);

		m_objectCount++;
	}

	/*
	 * Find out if there is a block available.
	 *
	 * @return true if one is available, false if not.
	 */
	virtual bool
	blockAvailable() const
	{
		return m_objectCount < m_blockSize ? true : false;
	}

	/*
	 * Get the number of objects currently allocated in the
	 * block.
	 *
	 * @return The number of objects allocated.
	 */
	virtual size_type
	getCountAllocated() const
	{
		return m_objectCount;
	}

	/*
	 * Get the block size, that is, the number
	 * of objects in each block.
	 *
	 * @return The size of the block
	 */
	size_type
	getBlockSize() const
	{
		return m_blockSize;
	}

	/*
	 * Determine if this block owns the specified object.  Note
	 * that even if the object address is within our block, this
	 * call will return false if no object currently occupies the
	 * block.  See also ownsBlock().
	 *
	 * @param theObject the address of the object.
	 * @return true if we own the object, false if not.
	 */
	virtual bool
	ownsObject(const ObjectType*	theObject) const
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::less;
#endif

		// Use less<>, since it's guaranteed to do pointer
		// comparisons correctly...
		less<const ObjectType*>		functor;

		if (functor(theObject, m_objectBlock) == false &&
			functor(theObject, m_objectBlock + m_objectCount) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/*
	 * Determine if this block owns the specified object block.
	 * Note that, unlike ownsObject(), there does not need to
	 * be an object at the address.
	 *
	 * @param theObject the address of the object
	 * @return true if we own the object block, false if not.
	 */
	bool
	ownsBlock(const ObjectType*		theObject) const
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::less;
#endif

		// Use less<>, since it's guaranteed to do pointer
		// comparisons correctly...
		less<const ObjectType*>		functor;

		if (functor(theObject, m_objectBlock) == false &&
			functor(theObject, m_objectBlock + m_blockSize) == true)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/*
	 * Destroy all objects in the block.  You can then reuse the
	 * block.
	 */
	void
	destroyAll()
	{
#if !defined(XALAN_NO_NAMESPACES)
		using std::for_each;
#endif

		// Destroy all existing objects...
		for_each(m_objectBlock,
				 m_objectBlock + m_objectCount,
				 DeleteFunctor(*this, m_destroyFunction));

		m_objectCount = 0;
	}

protected:

	/*
	 * Determine if the block should be destroyed.  Called by
	 * an instance of DeleteFunctor, this function is for
	 * deriving classes that might want to control the destruction
	 * of things.
	 *
	 * @param theObject the address of the object
	 * @return true if block should be destroyed, false if not.
	 */
	virtual bool
	shouldDestroyBlock(const ObjectType*	/* theObject */) const
	{
		return true;
	}

	/*
	 * Determine the offset into the block for the given address.
	 * Behavior is undefined if the address is not within our
	 * block
	 *
	 * @param theObject the address of the object
	 * @return the offset
	 */
	size_type
	getBlockOffset(const ObjectType*	theObject) const
	{
		assert(size_type(theObject - m_objectBlock) < m_blockSize);

		return theObject - m_objectBlock;
	}

	/*
	 * Determine the address within our block of the object
	 * at the specified offset.
	 * Behavior is undefined if the offset is greater than the
	 * block size.
	 *
	 * @param theObject the address of the object
	 * @return the offset
	 */
	ObjectType*
	getBlockAddress(size_type	theOffset) const
	{
		assert(theOffset < m_blockSize);

		return m_objectBlock + theOffset;
	}

	struct DeleteFunctor
	{
		DeleteFunctor(
				const ArenaBlock<ObjectType>&	theArenaBlock,
				const DestroyFunctionType&		theDestroyFunction) :
			m_arenaBlock(theArenaBlock),
			m_destroyFunction(theDestroyFunction)
		{
		}

		void
		operator()(ObjectType&	theObject) const
		{
			if (m_arenaBlock.shouldDestroyBlock(&theObject) == true)
			{
				m_destroyFunction(theObject);
			}
		}

	private:

		const ArenaBlock<ObjectType>&	m_arenaBlock;
		const DestroyFunctionType&		m_destroyFunction;
	};

	friend struct DeleteFunctor;

	const DestroyFunctionType	m_destroyFunction;

private:

	// Not implemented...
	ArenaBlock(const ArenaBlock<ObjectType>&);

	ArenaBlock<ObjectType>&
	operator=(const ArenaBlock<ObjectType>&);

	bool
	operator==(const ArenaBlock<ObjectType>&) const;

	// data members...
	size_type			m_objectCount;

	const size_type		m_blockSize;

	ObjectType*			m_objectBlock;

	AllocatorType		m_allocator;
};

#endif	// !defined(ARENABLOCK_INCLUDE_GUARD_1357924680)
<|endoftext|>