<commit_before>#include <boost/cstdint.hpp>
#include <cassert>
#include <cerrno>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>

namespace utility {

::std::string last_error(virConnectPtr conn)
{
	assert( conn );

	::std::string err_str;
	virErrorPtr err = new virError();

	int ret = virConnCopyLastError(conn, err);
	switch (ret)
	{
		case 0:
			// No error found
			break;
		case -1:
			err_str = "Parameter error when attempting to get last error";
			break;
		default:
			err_str = err->message;
			break;
	}

	virResetError(err);
	delete err;

	return err_str;
}

virConnectPtr connect(::std::string const& uri)
{
	// Connect to libvirtd daemons
	//
	// virConnectOpenAuth is called here with all default parameters,
	// except, possibly, the URI of the hypervisor.
	//
	virConnectPtr conn = virConnectOpenAuth((!uri.empty() ? uri.c_str() : 0), virConnectAuthPtrDefault, 0);
	if (0 == conn)
	{
		::std::ostringstream oss;
		oss << "No connection to hypervisor with URI '" << uri << "': " << last_error(0);
		throw ::std::runtime_error(oss.str());
	}

	return conn;
}

virDomainPtr connect_domain(virConnectPtr conn, ::std::string const& name)
{
	assert( conn );

	virDomainPtr dom = virDomainLookupByName(conn, name.c_str());
	if (0 == dom)
	{
		::std::ostringstream oss;
		oss << "Failed to get Domain for \"" << name << "\": " << last_error(conn);
		throw ::std::runtime_error(oss.str());
	}

	return dom;
}

std::string domain_hostname(virConnectPtr conn, virDomainPtr dom)
{
	const char* hn = virDomainGetHostname(dom, 0);
	if (0 == hn)
	{
		::std::ostringstream oss;
		oss << "Failed to get hostname for domain \"" << virDomainGetName(dom) << "\": " << last_error(conn);
		throw ::std::runtime_error(oss.str());
	}

	return hn;
}

} // Namespace utility

class dom_stats
{
	public: dom_stats(virConnectPtr conn, virDomainPtr dom)
	: conn_(conn),
	  dom_(dom),
	  first_(true),
	  pct_cpu_(0)
	{
		try
		{
			hname_ = utility::domain_hostname(conn_, dom_);
		}
		catch (...)
		{
			hname_ = "<NA>";
		}
	}

	public: int num_cpus(int flags)
	{
		assert( conn_ );
		assert( dom_ );

		int ret = 0;

		virDomainInfo info;
		ret = virDomainGetInfo(dom_, &info);
		if (0 > ret)
		{
			::std::ostringstream oss;
			oss << "Failed to query information for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
			throw ::std::runtime_error(oss.str());
		}

		const int nvcpus = info.nrVirtCpu;
		const int maxncpus = this->max_num_cpus();

		const ::std::size_t cpumaplen = VIR_CPU_MAPLEN(maxncpus);
		unsigned char* cpumaps = new unsigned char[nvcpus*cpumaplen];

		ret = virDomainGetVcpuPinInfo(dom_, info.nrVirtCpu, cpumaps, cpumaplen, flags);
		if (0 > ret)
		{
			ret = virDomainGetVcpusFlags(dom_, flags | VIR_DOMAIN_VCPU_MAXIMUM);

			if (0 > ret)
			{
				::std::ostringstream oss;
				oss << "Failed to query the number of vCPUs for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
				throw ::std::runtime_error(oss.str());
			}
		}

		int ncpu = 0;
		for (int cpu = 0; cpu < maxncpus; ++cpu)
		{
			for (int vcpu = 0; vcpu < cpumaplen; ++vcpu)
			{
				//if (VIR_CPU_USED(VIR_GET_CPUMAP(cpumaps, cpumaplen, vcpu), cpu))
				if (VIR_CPU_USABLE(cpumaps, cpumaplen, vcpu, cpu))
				{
					++ncpu;
					break;
				}
			}
		}

		delete[] cpumaps;

		return ncpu;
	}

	public: void collect()
	{
		int ret;

		if (!first_)
		{
			prev_time_ = cur_time_;
			prev_node_info_ = cur_node_info_;
		}

		ret = ::clock_gettime(CLOCK_REALTIME, &cur_time_);
		if (-1 == ret)
		{
			::std::ostringstream oss;
			oss << "Failed to get clock time info: " << ::std::strerror(errno);

			throw ::std::runtime_error(oss.str());
		}

		// Get the CPU time used (in ns)
		ret = ::virDomainGetInfo(dom_, &cur_node_info_);
		if (-1 == ret)
		{
			::std::ostringstream oss;
			oss << "Failed to get domain info: " << utility::last_error(conn_);

			throw ::std::runtime_error(oss.str());
		}

		if (first_)
		{
			first_ = false;

			prev_time_ = cur_time_;
			prev_node_info_ = cur_node_info_;
			pct_cpu_ = 0;
			pct_ram_ = 0;
		}
		else
		{
			::boost::uint64_t ns_elapsed = (cur_time_.tv_sec-prev_time_.tv_sec)*1.0e9+(cur_time_.tv_nsec-prev_time_.tv_nsec);
			::boost::uint64_t ns_used = cur_node_info_.cpuTime-prev_node_info_.cpuTime;
//	::std::cerr << "DEBUG> %CPU: " << (ns_used/ns_elapsed) << ::std::endl;
			pct_cpu_ = static_cast<double>(ns_used/static_cast<long double>(ns_elapsed))*100.0;
//	::std::cerr << "DEBUG> %RAM: " << (cur_node_info_.memory/cur_node_info_.maxMem) << ::std::endl;
			virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR];
			int nr_stats = virDomainMemoryStats(dom_, stats, VIR_DOMAIN_MEMORY_STAT_NR, VIR_DOMAIN_AFFECT_CURRENT);
			if (0 <= nr_stats)
			{
				long double mem_avail_MB = 0;
				for (int i = 0; i < nr_stats; ++i)
				{
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
					{
						std::cerr << "DEBUG> MEM swap_in " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
					{
						std::cerr << "DEBUG> MEM swap_out " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
					{
						std::cerr << "DEBUG> MEM major_fault " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
					{
						std::cerr << "DEBUG> MEM minor_fault " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
					{
						std::cerr << "DEBUG> MEM unused " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
					{
						std::cerr << "DEBUG> MEM available " << stats[i].val << std::endl;
						mem_avail_MB = stats[i].val/1024.0;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON)
					{
						std::cerr << "DEBUG> MEM actual " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS)
					{
						std::cerr << "DEBUG> MEM rss " << stats[i].val << std::endl;
					}

					pct_ram_ = static_cast<double>(mem_avail_MB/cur_node_info_.maxMem)*100.0;
				}
			}
			else
			{
				//::std::ostringstream oss;
				//oss << "Failed to get domain memory stats: " << utility::last_error(conn_);
				//throw ::std::runtime_error(oss.str());

				std::clog << "[warning] Failed to get precise domain memory stats: " << utility::last_error(conn_) << std::endl;

				std::cerr << "DEBUG> MEM current (from node info): " << cur_node_info_.memory << std::endl;
				std::cerr << "DEBUG> MEM max (from node info): " << cur_node_info_.maxMem << std::endl;
				std::cerr << "DEBUG> MEM max (from API): " << virDomainGetMaxMemory(dom_) << std::endl;

				pct_ram_ = static_cast<double>(cur_node_info_.memory/static_cast<long double>(cur_node_info_.maxMem))*100.0;
			}
		}
	}

	public: double percent_cpu() const
	{
		return pct_cpu_;
	}

	public: double percent_ram() const
	{
		return pct_ram_;
	}

	public: std::string hostname() const
	{
		return hname_;
	}

	private: int max_num_cpus()
	{
		assert( conn_ );

		int ret;

		// First try to use virNodeGetCPUMap since it is the lightest way
		ret = virNodeGetCPUMap(conn_, 0, 0, 0);
		if (-1 == ret)
		{
			// Fall back to virNodeGetInfo
			virNodeInfo info;

			ret = virNodeGetInfo(conn_, &info);
			if (-1 == ret)
			{
				::std::ostringstream oss;
				oss << "Failed to get node info: " << utility::last_error(conn_);

				throw ::std::runtime_error(oss.str());
			}

			ret = VIR_NODEINFO_MAXCPUS(info);
		}

		return ret;
	}

	private: ::virConnectPtr conn_;
	private: ::virDomainPtr dom_;
	private: bool first_;
	private: ::timespec prev_time_;
	private: ::virDomainInfo prev_node_info_;
	private: ::timespec cur_time_;
	private: ::virDomainInfo cur_node_info_;
	private: double pct_cpu_;
	private: double pct_ram_;
	private: std::string hname_; ///< The domain host name
}; // dom_stats

int main(int argc, char* argv[])
{
	std::string uri = "xen:///";
	std::string dom_name = "rubis-c63_64";

	if (argc > 1)
	{
		uri = argv[1];
		if (argc > 2)
		{
			dom_name = argv[2];
		}
	}

	try
	{
		virConnectPtr conn = utility::connect(uri);

		virDomainPtr dom = utility::connect_domain(conn, dom_name);

		dom_stats stats(conn, dom);

		std::cout << "DOMAIN: " << dom_name << " (hostname: " << stats.hostname() << ")" << std::endl;

		std::cout << "#CPUs: " << stats.num_cpus(VIR_DOMAIN_AFFECT_CURRENT) << std::endl;

		for (std::size_t i = 0; /*i < n*/true; ++i)
		{
			::sleep(5);
			stats.collect();
			std::cout << "#" << i << " STATS:" << std::endl;
			std::cout << "  %CPU: " << std::fixed << stats.percent_cpu() << "%" << std::endl;
			std::cout << "  %RAM: " << std::fixed << stats.percent_ram() << "%" << std::endl;
		}
	}
	catch (std::exception const& e)
	{
		std::cerr << "Caught error: " << e.what() << std::endl;
	}
	catch (...)
	{
		std::cerr << "Unknown error." << std::endl;
	}
}
<commit_msg>dom_stats tool: added information about the number of vCPUs<commit_after>#include <boost/cstdint.hpp>
#include <cassert>
#include <cerrno>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unistd.h>

namespace utility {

::std::string last_error(virConnectPtr conn)
{
	assert( conn );

	::std::string err_str;
	virErrorPtr err = new virError();

	int ret = virConnCopyLastError(conn, err);
	switch (ret)
	{
		case 0:
			// No error found
			break;
		case -1:
			err_str = "Parameter error when attempting to get last error";
			break;
		default:
			err_str = err->message;
			break;
	}

	virResetError(err);
	delete err;

	return err_str;
}

virConnectPtr connect(::std::string const& uri)
{
	// Connect to libvirtd daemons
	//
	// virConnectOpenAuth is called here with all default parameters,
	// except, possibly, the URI of the hypervisor.
	//
	virConnectPtr conn = virConnectOpenAuth((!uri.empty() ? uri.c_str() : 0), virConnectAuthPtrDefault, 0);
	if (0 == conn)
	{
		::std::ostringstream oss;
		oss << "No connection to hypervisor with URI '" << uri << "': " << last_error(0);
		throw ::std::runtime_error(oss.str());
	}

	return conn;
}

virDomainPtr connect_domain(virConnectPtr conn, ::std::string const& name)
{
	assert( conn );

	virDomainPtr dom = virDomainLookupByName(conn, name.c_str());
	if (0 == dom)
	{
		::std::ostringstream oss;
		oss << "Failed to get Domain for \"" << name << "\": " << last_error(conn);
		throw ::std::runtime_error(oss.str());
	}

	return dom;
}

std::string domain_hostname(virConnectPtr conn, virDomainPtr dom)
{
	const char* hn = virDomainGetHostname(dom, 0);
	if (0 == hn)
	{
		::std::ostringstream oss;
		oss << "Failed to get hostname for domain \"" << virDomainGetName(dom) << "\": " << last_error(conn);
		throw ::std::runtime_error(oss.str());
	}

	return hn;
}

} // Namespace utility

class dom_stats
{
	public: dom_stats(virConnectPtr conn, virDomainPtr dom)
	: conn_(conn),
	  dom_(dom),
	  first_(true),
	  pct_cpu_(0)
	{
		try
		{
			hname_ = utility::domain_hostname(conn_, dom_);
		}
		catch (...)
		{
			hname_ = "<NA>";
		}
	}

	public: int num_vcpus(int flags)
	{
		assert( conn_ );
		assert( dom_ );

		int ret = 0;

		//if (checkState &&
		//  ((flags & VIR_DOMAIN_AFFECT_LIVE && virDomainIsActive(dom) < 1) ||
		//   (flags & VIR_DOMAIN_AFFECT_CONFIG && virDomainIsPersistent(dom) < 1)))
		//  return -1;

		// In all cases, try the new API first; if it fails because we are talking
		// to an older daemon, generally we try a fallback API before giving up.
		// The flag VIR_DOMAIN_AFFECT_CURRENT requires the new API, since we don't
		// know whether the domain is running or inactive.
		ret = virDomainGetVcpusFlags(dom_, flags);
		if (ret < 0)
		{
			if (flags & VIR_DOMAIN_VCPU_GUEST)
			{
				::std::ostringstream oss;
				oss << "Failed to retrieve vCPU count from \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
				throw ::std::runtime_error(oss.str());
			}

			if (!(flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) && virDomainIsActive(dom_) == 1)
			{
				 flags |= VIR_DOMAIN_AFFECT_LIVE;
			}

			if (flags & VIR_DOMAIN_AFFECT_LIVE)
			{
				if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
				{
					ret = virDomainGetMaxVcpus(dom_);
				}
				else
				{
					virDomainInfo info;
					ret = virDomainGetInfo(dom_, &info);
					if (ret < 0)
					{
						::std::ostringstream oss;
						oss << "Failed to query information for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
						throw ::std::runtime_error(oss.str());
					}

					ret = info.nrVirtCpu;
				}
			}
			else
			{
/*TODO
				char *def = NULL;
				xmlDocPtr xml = NULL;
				xmlXPathContextPtr ctxt = NULL;

				def = virDomainGetXMLDesc(dom_, VIR_DOMAIN_XML_INACTIVE);
				if (def == 0)
				{
					::std::ostringstream oss;
					oss << "Failed to query XML for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
					throw ::std::runtime_error(oss.str());
				}

				xml = virXMLParseStringCtxt(def, _("(domain_definition)"), &ctxt);
				if (xml == 0)
				{
					::std::ostringstream oss;
					oss << "Failed to parse XML for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
					throw ::std::runtime_error(oss.str());
				}

				if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
				{
					if (virXPathInt("string(/domain/vcpus)", ctxt, &count) < 0)
					{
						::std::ostringstream oss;
						oss << "Failed to query retrieve maximum vcpu count for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
						throw ::std::runtime_error(oss.str());
					}
				}
				else
				{
					if (virXPathInt("string(/domain/vcpus/@current)", ctxt, &count) < 0)
					{
						::std::ostringstream oss;
						oss << "Failed to query retrieve current vcpu count for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
						throw ::std::runtime_error(oss.str());
					}
				}
*/
				::std::ostringstream oss;
				oss << "Failed to query retrieve vCPU count for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
				throw ::std::runtime_error(oss.str());
			}
		}

		return ret;
	}

	public: int num_cpus(int flags)
	{
		assert( conn_ );
		assert( dom_ );

		int ret = 0;

		virDomainInfo info;
		ret = virDomainGetInfo(dom_, &info);
		if (0 > ret)
		{
			::std::ostringstream oss;
			oss << "Failed to query information for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
			throw ::std::runtime_error(oss.str());
		}

		const int nvcpus = info.nrVirtCpu;
		const int maxncpus = this->max_num_cpus();

		const ::std::size_t cpumaplen = VIR_CPU_MAPLEN(maxncpus);
		unsigned char* cpumaps = new unsigned char[nvcpus*cpumaplen];

		ret = virDomainGetVcpuPinInfo(dom_, info.nrVirtCpu, cpumaps, cpumaplen, flags);
		if (0 > ret)
		{
			ret = virDomainGetVcpusFlags(dom_, flags | VIR_DOMAIN_VCPU_MAXIMUM);

			if (0 > ret)
			{
				::std::ostringstream oss;
				oss << "Failed to query the number of vCPUs for domain \"" << virDomainGetName(dom_) << "\": " << utility::last_error(conn_);
				throw ::std::runtime_error(oss.str());
			}
		}

		int ncpu = 0;
		for (int cpu = 0; cpu < maxncpus; ++cpu)
		{
			for (int vcpu = 0; vcpu < cpumaplen; ++vcpu)
			{
				//if (VIR_CPU_USED(VIR_GET_CPUMAP(cpumaps, cpumaplen, vcpu), cpu))
				if (VIR_CPU_USABLE(cpumaps, cpumaplen, vcpu, cpu))
				{
					++ncpu;
					break;
				}
			}
		}

		delete[] cpumaps;

		return ncpu;
	}

	public: void collect()
	{
		int ret;

		if (!first_)
		{
			prev_time_ = cur_time_;
			prev_node_info_ = cur_node_info_;
		}

		ret = ::clock_gettime(CLOCK_REALTIME, &cur_time_);
		if (-1 == ret)
		{
			::std::ostringstream oss;
			oss << "Failed to get clock time info: " << ::std::strerror(errno);

			throw ::std::runtime_error(oss.str());
		}

		// Get the CPU time used (in ns)
		ret = ::virDomainGetInfo(dom_, &cur_node_info_);
		if (-1 == ret)
		{
			::std::ostringstream oss;
			oss << "Failed to get domain info: " << utility::last_error(conn_);

			throw ::std::runtime_error(oss.str());
		}

		if (first_)
		{
			first_ = false;

			prev_time_ = cur_time_;
			prev_node_info_ = cur_node_info_;
			pct_cpu_ = 0;
			pct_ram_ = 0;
		}
		else
		{
			::boost::uint64_t ns_elapsed = (cur_time_.tv_sec-prev_time_.tv_sec)*1.0e9+(cur_time_.tv_nsec-prev_time_.tv_nsec);
			::boost::uint64_t ns_used = cur_node_info_.cpuTime-prev_node_info_.cpuTime;
//	::std::cerr << "DEBUG> %CPU: " << (ns_used/ns_elapsed) << ::std::endl;
			pct_cpu_ = static_cast<double>(ns_used/static_cast<long double>(ns_elapsed))*100.0;
//	::std::cerr << "DEBUG> %RAM: " << (cur_node_info_.memory/cur_node_info_.maxMem) << ::std::endl;
			virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR];
			int nr_stats = virDomainMemoryStats(dom_, stats, VIR_DOMAIN_MEMORY_STAT_NR, VIR_DOMAIN_AFFECT_CURRENT);
			if (0 <= nr_stats)
			{
				long double mem_avail_MB = 0;
				for (int i = 0; i < nr_stats; ++i)
				{
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
					{
						std::cerr << "DEBUG> MEM swap_in " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
					{
						std::cerr << "DEBUG> MEM swap_out " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
					{
						std::cerr << "DEBUG> MEM major_fault " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
					{
						std::cerr << "DEBUG> MEM minor_fault " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
					{
						std::cerr << "DEBUG> MEM unused " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
					{
						std::cerr << "DEBUG> MEM available " << stats[i].val << std::endl;
						mem_avail_MB = stats[i].val/1024.0;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON)
					{
						std::cerr << "DEBUG> MEM actual " << stats[i].val << std::endl;
					}
					if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS)
					{
						std::cerr << "DEBUG> MEM rss " << stats[i].val << std::endl;
					}

					pct_ram_ = static_cast<double>(mem_avail_MB/cur_node_info_.maxMem)*100.0;
				}
			}
			else
			{
				//::std::ostringstream oss;
				//oss << "Failed to get domain memory stats: " << utility::last_error(conn_);
				//throw ::std::runtime_error(oss.str());

				std::clog << "[warning] Failed to get precise domain memory stats: " << utility::last_error(conn_) << std::endl;

				std::cerr << "DEBUG> MEM current (from node info): " << cur_node_info_.memory << std::endl;
				std::cerr << "DEBUG> MEM max (from node info): " << cur_node_info_.maxMem << std::endl;
				std::cerr << "DEBUG> MEM max (from API): " << virDomainGetMaxMemory(dom_) << std::endl;

				pct_ram_ = static_cast<double>(cur_node_info_.memory/static_cast<long double>(cur_node_info_.maxMem))*100.0;
			}
		}
	}

	public: double percent_cpu() const
	{
		return pct_cpu_;
	}

	public: double percent_ram() const
	{
		return pct_ram_;
	}

	public: std::string hostname() const
	{
		return hname_;
	}

	private: int max_num_cpus()
	{
		assert( conn_ );

		int ret;

		// First try to use virNodeGetCPUMap since it is the lightest way
		ret = virNodeGetCPUMap(conn_, 0, 0, 0);
		if (-1 == ret)
		{
			// Fall back to virNodeGetInfo
			virNodeInfo info;

			ret = virNodeGetInfo(conn_, &info);
			if (-1 == ret)
			{
				::std::ostringstream oss;
				oss << "Failed to get node info: " << utility::last_error(conn_);

				throw ::std::runtime_error(oss.str());
			}

			ret = VIR_NODEINFO_MAXCPUS(info);
		}

		return ret;
	}

	private: ::virConnectPtr conn_;
	private: ::virDomainPtr dom_;
	private: bool first_;
	private: ::timespec prev_time_;
	private: ::virDomainInfo prev_node_info_;
	private: ::timespec cur_time_;
	private: ::virDomainInfo cur_node_info_;
	private: double pct_cpu_;
	private: double pct_ram_;
	private: std::string hname_; ///< The domain host name
}; // dom_stats

int main(int argc, char* argv[])
{
	std::string uri = "xen:///";
	std::string dom_name = "rubis-c63_64";

	if (argc > 1)
	{
		uri = argv[1];
		if (argc > 2)
		{
			dom_name = argv[2];
		}
	}

	try
	{
		virConnectPtr conn = utility::connect(uri);

		virDomainPtr dom = utility::connect_domain(conn, dom_name);

		dom_stats stats(conn, dom);

		std::cout << "DOMAIN: " << dom_name << " (hostname: " << stats.hostname() << ")" << std::endl;

		std::cout << "#vCPUs: " << stats.num_vcpus(VIR_DOMAIN_AFFECT_CURRENT) << std::endl;
		std::cout << "#CPUs: " << stats.num_cpus(VIR_DOMAIN_AFFECT_CURRENT) << std::endl;

		for (std::size_t i = 0; /*i < n*/true; ++i)
		{
			::sleep(5);
			stats.collect();
			std::cout << "#" << i << " STATS:" << std::endl;
			std::cout << "  %vCPU: " << std::fixed << stats.percent_cpu() << "%" << std::endl;
			std::cout << "  %RAM: " << std::fixed << stats.percent_ram() << "%" << std::endl;
		}
	}
	catch (std::exception const& e)
	{
		std::cerr << "Caught error: " << e.what() << std::endl;
	}
	catch (...)
	{
		std::cerr << "Unknown error." << std::endl;
	}
}
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "searchview.h"
#include <vespa/searchcore/proton/docsummary/docsumcontext.h>
#include <vespa/searchlib/engine/searchreply.h>
#include <vespa/log/log.h>
LOG_SETUP(".proton.server.searchview");

using proton::matching::MatchContext;
using search::AttributeGuard;
using search::AttributeVector;
using search::attribute::IAttributeContext;
using search::docsummary::IDocsumStore;
using search::docsummary::ResultConfig;
using search::engine::DocsumReply;
using search::engine::DocsumRequest;
using search::engine::SearchReply;
using vespalib::ThreadBundle;

namespace proton {

using matching::ISearchContext;
using matching::Matcher;

namespace {

/**
 * Maps the gids in the request to lids using the given document meta store.
 * A reader guard must be taken before calling this function.
 **/
void
convertGidsToLids(const DocsumRequest & request,
                  const search::IDocumentMetaStore &metaStore,
                  uint32_t docIdLimit)
{
    document::GlobalId empty;
    uint32_t lid = 0;
    for (size_t i = 0; i < request.hits.size(); ++i) {
        const DocsumRequest::Hit & h = request.hits[i];
        if (metaStore.getLid(h.gid, lid) && lid < docIdLimit) {
            h.docid = lid;
        } else {
            h.docid = search::endDocId;
            LOG(debug, "Document with global id '%s' is not in the document db, will return empty docsum", h.gid.toString().c_str());
        }
        LOG(spam, "convertGidToLid(DocsumRequest): hit[%zu]: gid(%s) -> lid(%u)", i, h.gid.toString().c_str(), h.docid);
    }
}

bool
requestHasLidAbove(const DocsumRequest & request, uint32_t docIdLimit)
{
    for (const DocsumRequest::Hit & h : request.hits) {
        if (h.docid >= docIdLimit) {
            return true;
        }
    }
    return false;
}

bool
hasAnyLidsMoved(const DocsumRequest & request,
                const search::IDocumentMetaStore &metaStore)
{
    for (const DocsumRequest::Hit & h : request.hits) {
        uint32_t lid = 0;
        if (h.docid != search::endDocId) {
            if (!metaStore.getLid(h.gid, lid) || (lid != h.docid)) {
                LOG(debug, "lid = %d moved to %d", h.docid, lid);
                return true;
            }
        }
    }
    return false;
}

/**
 * Maps the lids in the reply to gids using the original request.
 **/
void
convertLidsToGids(DocsumReply &reply, const DocsumRequest &request)
{
    LOG_ASSERT(reply.docsums.size() == request.hits.size());
    for (size_t i = 0; i < reply.docsums.size(); ++i) {
        const DocsumRequest::Hit & h = request.hits[i];
        DocsumReply::Docsum & d = reply.docsums[i];
        d.gid = h.gid;
        LOG(spam, "convertLidToGid(DocsumReply): docsum[%zu]: lid(%u) -> gid(%s)", i, h.docid, d.gid.toString().c_str());
    }
}

/**
 * Create empty docsum reply
 **/
DocsumReply::UP
createEmptyReply(const DocsumRequest & request)
{
    auto reply = std::make_unique<DocsumReply>();
    for (size_t i = 0; i < request.hits.size(); ++i) {
        reply->docsums.push_back(DocsumReply::Docsum());
        reply->docsums.back().gid = request.hits[i].gid;
    }
    return reply;
}

}

std::shared_ptr<SearchView>
SearchView::create(ISummaryManager::ISummarySetup::SP summarySetup, MatchView::SP matchView) {
    return std::shared_ptr<SearchView>( new SearchView(std::move(summarySetup), std::move(matchView)));
}
SearchView::SearchView(ISummaryManager::ISummarySetup::SP summarySetup, MatchView::SP matchView)
    : ISearchHandler(),
      _summarySetup(std::move(summarySetup)),
      _matchView(std::move(matchView))
{ }

SearchView::~SearchView() = default;

DocsumReply::UP
SearchView::getDocsums(const DocsumRequest & req)
{
    LOG(spam, "getDocsums(): resultClass(%s), numHits(%zu)", req.resultClassName.c_str(), req.hits.size());
    if (_summarySetup->getResultConfig().  LookupResultClassId(req.resultClassName.c_str()) == ResultConfig::NoClassID()) {
        LOG(warning, "There is no summary class with name '%s' in the summary config. Returning empty document summary for %zu hit(s)",
                     req.resultClassName.c_str(), req.hits.size());
        return createEmptyReply(req);
    }
    SearchView::InternalDocsumReply reply = getDocsumsInternal(req);
    while ( ! reply.second ) {
        LOG(debug, "Must refetch docsums since the lids have moved.");
        reply = getDocsumsInternal(req);
    }
    if ( ! req.useRootSlime()) {
        convertLidsToGids(*reply.first, req);
    }
    return std::move(reply.first);
}

SearchView::InternalDocsumReply
SearchView::getDocsumsInternal(const DocsumRequest & req)
{
    IDocumentMetaStoreContext::IReadGuard::UP readGuard = _matchView->getDocumentMetaStore()->getReadGuard();
    const search::IDocumentMetaStore & metaStore = readGuard->get();
    uint32_t numUsedLids = metaStore.getNumUsedLids();
    uint64_t startGeneration = readGuard->get().getCurrentGeneration();

    convertGidsToLids(req, metaStore, _matchView->getDocIdLimit().get());
    IDocsumStore::UP store(_summarySetup->createDocsumStore(req.resultClassName));
    MatchContext::UP mctx = _matchView->createContext();
    auto ctx = std::make_unique<DocsumContext>(req, _summarySetup->getDocsumWriter(), *store, _matchView->getMatcher(req.ranking),
                                               mctx->getSearchContext(), mctx->getAttributeContext(),
                                               *_summarySetup->getAttributeManager(), *getSessionManager());
    SearchView::InternalDocsumReply reply(ctx->getDocsums(), true);
    uint64_t endGeneration = readGuard->get().getCurrentGeneration();
    if (startGeneration != endGeneration) {
        if (requestHasLidAbove(req, std::min(numUsedLids, metaStore.getNumUsedLids()))) {
            if (hasAnyLidsMoved(req, metaStore)) {
                reply.second = false;
            }
        }
    }
    return reply;
}

std::unique_ptr<SearchReply>
SearchView::match(const SearchRequest &req, ThreadBundle &threadBundle) const {
    return _matchView->match(shared_from_this(), req, threadBundle);
}

} // namespace proton
<commit_msg>just make empty DocsumReply<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "searchview.h"
#include <vespa/searchcore/proton/docsummary/docsumcontext.h>
#include <vespa/searchlib/engine/searchreply.h>
#include <vespa/vespalib/data/slime/slime.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.server.searchview");

using proton::matching::MatchContext;
using search::AttributeGuard;
using search::AttributeVector;
using search::attribute::IAttributeContext;
using search::docsummary::IDocsumStore;
using search::docsummary::ResultConfig;
using search::engine::DocsumReply;
using search::engine::DocsumRequest;
using search::engine::SearchReply;
using vespalib::ThreadBundle;

namespace proton {

using matching::ISearchContext;
using matching::Matcher;

namespace {

/**
 * Maps the gids in the request to lids using the given document meta store.
 * A reader guard must be taken before calling this function.
 **/
void
convertGidsToLids(const DocsumRequest & request,
                  const search::IDocumentMetaStore &metaStore,
                  uint32_t docIdLimit)
{
    document::GlobalId empty;
    uint32_t lid = 0;
    for (size_t i = 0; i < request.hits.size(); ++i) {
        const DocsumRequest::Hit & h = request.hits[i];
        if (metaStore.getLid(h.gid, lid) && lid < docIdLimit) {
            h.docid = lid;
        } else {
            h.docid = search::endDocId;
            LOG(debug, "Document with global id '%s' is not in the document db, will return empty docsum", h.gid.toString().c_str());
        }
        LOG(spam, "convertGidToLid(DocsumRequest): hit[%zu]: gid(%s) -> lid(%u)", i, h.gid.toString().c_str(), h.docid);
    }
}

bool
requestHasLidAbove(const DocsumRequest & request, uint32_t docIdLimit)
{
    for (const DocsumRequest::Hit & h : request.hits) {
        if (h.docid >= docIdLimit) {
            return true;
        }
    }
    return false;
}

bool
hasAnyLidsMoved(const DocsumRequest & request,
                const search::IDocumentMetaStore &metaStore)
{
    for (const DocsumRequest::Hit & h : request.hits) {
        uint32_t lid = 0;
        if (h.docid != search::endDocId) {
            if (!metaStore.getLid(h.gid, lid) || (lid != h.docid)) {
                LOG(debug, "lid = %d moved to %d", h.docid, lid);
                return true;
            }
        }
    }
    return false;
}

/**
 * Create empty docsum reply
 **/
DocsumReply::UP
createEmptyReply(const DocsumRequest &)
{
    return std::make_unique<DocsumReply>();
}

}

std::shared_ptr<SearchView>
SearchView::create(ISummaryManager::ISummarySetup::SP summarySetup, MatchView::SP matchView) {
    return std::shared_ptr<SearchView>( new SearchView(std::move(summarySetup), std::move(matchView)));
}
SearchView::SearchView(ISummaryManager::ISummarySetup::SP summarySetup, MatchView::SP matchView)
    : ISearchHandler(),
      _summarySetup(std::move(summarySetup)),
      _matchView(std::move(matchView))
{ }

SearchView::~SearchView() = default;

DocsumReply::UP
SearchView::getDocsums(const DocsumRequest & req)
{
    LOG(spam, "getDocsums(): resultClass(%s), numHits(%zu)", req.resultClassName.c_str(), req.hits.size());
    if (_summarySetup->getResultConfig().  LookupResultClassId(req.resultClassName.c_str()) == ResultConfig::NoClassID()) {
        LOG(warning, "There is no summary class with name '%s' in the summary config. Returning empty document summary for %zu hit(s)",
                     req.resultClassName.c_str(), req.hits.size());
        return createEmptyReply(req);
    }
    SearchView::InternalDocsumReply reply = getDocsumsInternal(req);
    while ( ! reply.second ) {
        LOG(debug, "Must refetch docsums since the lids have moved.");
        reply = getDocsumsInternal(req);
    }
    return std::move(reply.first);
}

SearchView::InternalDocsumReply
SearchView::getDocsumsInternal(const DocsumRequest & req)
{
    IDocumentMetaStoreContext::IReadGuard::UP readGuard = _matchView->getDocumentMetaStore()->getReadGuard();
    const search::IDocumentMetaStore & metaStore = readGuard->get();
    uint32_t numUsedLids = metaStore.getNumUsedLids();
    uint64_t startGeneration = readGuard->get().getCurrentGeneration();

    convertGidsToLids(req, metaStore, _matchView->getDocIdLimit().get());
    IDocsumStore::UP store(_summarySetup->createDocsumStore(req.resultClassName));
    MatchContext::UP mctx = _matchView->createContext();
    auto ctx = std::make_unique<DocsumContext>(req, _summarySetup->getDocsumWriter(), *store, _matchView->getMatcher(req.ranking),
                                               mctx->getSearchContext(), mctx->getAttributeContext(),
                                               *_summarySetup->getAttributeManager(), *getSessionManager());
    SearchView::InternalDocsumReply reply(ctx->getDocsums(), true);
    uint64_t endGeneration = readGuard->get().getCurrentGeneration();
    if (startGeneration != endGeneration) {
        if (requestHasLidAbove(req, std::min(numUsedLids, metaStore.getNumUsedLids()))) {
            if (hasAnyLidsMoved(req, metaStore)) {
                reply.second = false;
            }
        }
    }
    return reply;
}

std::unique_ptr<SearchReply>
SearchView::match(const SearchRequest &req, ThreadBundle &threadBundle) const {
    return _matchView->match(shared_from_this(), req, threadBundle);
}

} // namespace proton
<|endoftext|>


<commit_before>#ifndef SKETCH_H__
#define SKETCH_H__

#include "Pages.hh"
#include "Stack.h"

class Sketch {
public:

  Stack<Page *, 4> pageStack;
  char *name;

  Sketch(char *_name = NULL) {
    name = _name;
  }

  void setPage(Page *page) {
    pageStack.reset();
    pushPage(page);
  }

  void pushPage(Page *page) {
    page->redisplayPage();
    pageStack.push(page);
  }

  void popPage() {
    pageStack.pop(NULL);
    Page *page = currentPage();
    if (page != NULL)
      page->redisplayPage();
  }

  Page *currentPage() {
    Page *page = NULL;
    pageStack.peek(&page);
    return page;
  }

  virtual void setup() {
  }

  virtual bool handleEvent(gui_event_t *event) {
    return false;
  }

  bool handleTopEvent(gui_event_t *event) {
    Page *curPage = currentPage();
    if (curPage != NULL) {
      if (curPage->handleEvent(event)) {
	return true;
      }
    }
    return handleEvent(event);
  }

  virtual void loop() {
  }
  virtual void close() {
  }
};

#endif /* SKETCH_H__ */
<commit_msg>rename close to destroy, and hide / show pages on push/pop<commit_after>#ifndef SKETCH_H__
#define SKETCH_H__

#include "Pages.hh"
#include "Stack.h"

class Sketch {
public:

  Stack<Page *, 4> pageStack;
  char *name;

  Sketch(char *_name = NULL) {
    name = _name;
  }

  void setPage(Page *page) {
    pageStack.reset();
    pushPage(page);
  }

  void pushPage(Page *page) {
    page->sketch = this;
    page->redisplayPage();
    page->show();
    pageStack.push(page);
  }

  void popPage() {
    Page *page;
    pageStack.pop(&page);
    if (page != NULL) {
      page->sketch = NULL;
      page->hide();
    }

    page = currentPage();
    if (page != NULL) {
      page->redisplayPage();
    }
  }

  Page *currentPage() {
    Page *page = NULL;
    pageStack.peek(&page);
    return page;
  }

  virtual void setup() {
  }

  virtual bool handleEvent(gui_event_t *event) {
    return false;
  }

  bool handleTopEvent(gui_event_t *event) {
    Page *curPage = currentPage();
    if (curPage != NULL) {
      if (curPage->handleEvent(event)) {
	return true;
      }
    }
    return handleEvent(event);
  }

  virtual void loop() {
  }
  virtual void destroy() {
  }
};

#endif /* SKETCH_H__ */
<|endoftext|>


<commit_before>/*
  Q Light Controller
  aboutbox.cpp

  Copyright (C) Heikki Junnila

  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.txt

  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 <QDebug>
#include <QLabel>
#include <QTimer>
#include <QDesktopServices>
#include <QUrl>

#include "qlcconfig.h"
#include "aboutbox.h"

AboutBox::AboutBox(QWidget* parent) : QDialog (parent)
{
    setupUi(this);

    QAction* action = new QAction(this);
    action->setShortcut(QKeySequence(QKeySequence::Close));
    connect(action, SIGNAL(triggered(bool)), this, SLOT(reject()));
    addAction(action);

    m_titleLabel->setText(APPNAME);
    m_versionLabel->setText(APPVERSION);
    m_copyrightLabel->setText(QString("Copyright © Heikki Junnila, Massimo Callegari %1")
                              .arg(tr("and contributors:")));
    m_websiteLabel->setText(tr("Website: %1").arg("http://qlcplus.sourceforge.net/"));
    connect(m_websiteLabel, SIGNAL(itemClicked(m_websiteLabel)),
            this, SLOT(QDesktopServices::openUrl(QUrl("http://qlcplus.sourceforge.net/"))));

    connect(m_contributors, SIGNAL(itemClicked(QListWidgetItem*)),
            this, SLOT(slotItemClicked()));
    m_contributors->clear();
    m_contributors->addItem("Contributors:");
    m_contributors->addItem("Jano Svitok");
    m_contributors->addItem("Thomas Achtner");
    m_contributors->addItem("Joep Admiraal");
    m_contributors->addItem("Oliver Ruempelein");
    m_contributors->addItem("Jannis Achstetter");
    m_contributors->addItem("Stefan Riemens");
    m_contributors->addItem("NiKoyes");
    m_contributors->addItem("Raymond Van Laake");
    m_contributors->addItem(QString::fromUtf8("Luis García Tornel"));
    m_contributors->addItem("Jan Lachman");
    m_contributors->addItem("Klaus Weidenbach");
    m_contributors->addItem("Stefan Krumm");
    m_contributors->addItem(QString::fromUtf8("Christian Sühs"));
    m_contributors->addItem("Simon Newton");
    m_contributors->addItem("Christopher Staite");
    m_contributors->addItem("Lutz Hillebrand");
    m_contributors->addItem("Matthew Jaggard");
    m_contributors->addItem("Ptit Vachon");
    m_contributors->addItem("Tolmino");

    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
    m_row = -1;
    m_increment = 1;
    m_timer->start(500);
}

AboutBox::~AboutBox()
{
}

void AboutBox::slotTimeout()
{
    if (m_row <= 0)
        m_increment = 1;
    else if (m_row >= m_contributors->count())
        m_increment = -1;

    m_row += m_increment;
    m_contributors->scrollToItem(m_contributors->item(m_row));
}

void AboutBox::slotItemClicked()
{
    if (m_timer != NULL)
    {
        m_timer->stop();
        delete m_timer;
        m_timer = NULL;
    }
}
<commit_msg>Error in AboutBox<commit_after>/*
  Q Light Controller
  aboutbox.cpp

  Copyright (C) Heikki Junnila

  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.txt

  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 <QDebug>
#include <QLabel>
#include <QTimer>
#include <QDesktopServices>
#include <QUrl>

#include "qlcconfig.h"
#include "aboutbox.h"

AboutBox::AboutBox(QWidget* parent) : QDialog (parent)
{
    setupUi(this);

    QAction* action = new QAction(this);
    action->setShortcut(QKeySequence(QKeySequence::Close));
    connect(action, SIGNAL(triggered(bool)), this, SLOT(reject()));
    addAction(action);

    m_titleLabel->setText(APPNAME);
    m_versionLabel->setText(APPVERSION);
    m_copyrightLabel->setText(QString("Copyright © Heikki Junnila, Massimo Callegari %1")
                              .arg(tr("and contributors:")));
    m_websiteLabel->setText(tr("Website: %1").arg("http://qlcplus.sourceforge.net/"));
    connect(m_websiteLabel, SIGNAL(itemClicked(m_websiteLabel)),
            this, SLOT(QDesktopServices::openUrl(QUrl("http://qlcplus.sourceforge.net/"))));

    connect(m_contributors, SIGNAL(itemClicked(QListWidgetItem*)),
            this, SLOT(slotItemClicked()));
    m_contributors->clear();
    m_contributors->addItem("Contributors:");
    m_contributors->addItem("Jano Svitok");
    m_contributors->addItem("Thomas Achtner");
    m_contributors->addItem("Joep Admiraal");
    m_contributors->addItem("Oliver Ruempelein");
    m_contributors->addItem("Jannis Achstetter");
    m_contributors->addItem("Stefan Riemens");
    m_contributors->addItem("NiKoyes");
    m_contributors->addItem("Raymond Van Laake");
    m_contributors->addItem(QString::fromUtf8("Luis García Tornel"));
    m_contributors->addItem("Jan Lachman");
    m_contributors->addItem("Klaus Weidenbach");
    m_contributors->addItem("Stefan Krumm");
    m_contributors->addItem(QString::fromUtf8("Christian Sühs"));
    m_contributors->addItem("Simon Newton");
    m_contributors->addItem("Christopher Staite");
    m_contributors->addItem("Lutz Hillebrand");
    m_contributors->addItem("Matthew Jaggard");
    m_contributors->addItem("Ptit Vachon");
    m_contributors->addItem("Tolmino");

    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
    m_row = -1;
    m_increment = 1;
    m_timer->start(500);
}

AboutBox::~AboutBox()
{
}

void AboutBox::slotTimeout()
{
    if (m_row <= 0)
        m_increment = 1;
    else if (m_row >= m_contributors->count())
        m_increment = -1;

    m_row += m_increment;
    m_contributors->scrollToItem(m_contributors->item(m_row));
}

void AboutBox::slotItemClicked()
{
    if (m_timer != NULL)
    {
        m_timer->stop();
        delete m_timer;
        m_timer = NULL;
    }
}
<|endoftext|>


<commit_before>/**
 * @file packed_data.cpp
 *
 */

#include "packed_data.h"

#ifdef HAVE_CUDA

using namespace himan;

void packed_data::Set(unsigned char* newData, size_t newPackedLength, size_t newUnpackedLength)
{
	if (packedLength)
	{
		CUDA_CHECK(cudaFreeHost(data));
	}

	packedLength = newPackedLength;
	unpackedLength = newUnpackedLength;
	data = newData;
}

void packed_data::Bitmap(int* newBitmap, size_t newBitmapLength)
{
	if (newBitmapLength)
	{
		CUDA_CHECK(cudaFreeHost(bitmap));
	}

	bitmapLength = newBitmapLength;
	bitmap = newBitmap;
}

void packed_data::Resize(size_t newPackedLength, size_t newUnpackedLength)
{
	assert(newPackedLength > packedLength);

	packedLength = newPackedLength;
	unpackedLength = newUnpackedLength;

	unsigned char* newData = 0;

	CUDA_CHECK(
	    cudaHostAlloc(reinterpret_cast<void**>(&newData), packedLength * sizeof(unsigned char), cudaHostAllocMapped));

	memcpy(newData, data, packedLength * sizeof(unsigned char));

	CUDA_CHECK(cudaFreeHost(data));

	data = newData;
}

packed_data::packed_data(const packed_data& other)
    : packedLength(other.packedLength), unpackedLength(other.unpackedLength), packingType(other.packingType)
{
	data = 0;
	bitmap = 0;

	if (other.packedLength)
	{
		CUDA_CHECK(
		    cudaHostAlloc(reinterpret_cast<void**>(&data), packedLength * sizeof(unsigned char), cudaHostAllocMapped));

		memcpy(data, other.data, packedLength * sizeof(unsigned char));
	}

	if (other.bitmapLength)
	{
		cudaHostAlloc(reinterpret_cast<void**>(&bitmap), bitmapLength * sizeof(int), cudaHostAllocMapped);

		memcpy(bitmap, other.bitmap, bitmapLength * sizeof(int));
	}
}

void packed_data::Clear()
{
	if (packedLength)
	{
		assert(data);
		CUDA_CHECK(cudaFreeHost(data));
		packedLength = 0;
	}

	if (bitmapLength)
	{
		assert(bitmap);
		CUDA_CHECK(cudaFreeHost(bitmap));
		bitmapLength = 0;
	}

	unpackedLength = 0;
}

#endif
<commit_msg>Initialize bitmapLength in copy constructor<commit_after>/**
 * @file packed_data.cpp
 *
 */

#include "packed_data.h"

#ifdef HAVE_CUDA

using namespace himan;

void packed_data::Set(unsigned char* newData, size_t newPackedLength, size_t newUnpackedLength)
{
	if (packedLength)
	{
		assert(data);
		CUDA_CHECK(cudaFreeHost(data));
	}

	packedLength = newPackedLength;
	unpackedLength = newUnpackedLength;
	data = newData;
}

void packed_data::Bitmap(int* newBitmap, size_t newBitmapLength)
{
	if (newBitmapLength)
	{
		assert(bitmap);
		CUDA_CHECK(cudaFreeHost(bitmap));
	}

	bitmapLength = newBitmapLength;
	bitmap = newBitmap;
}

void packed_data::Resize(size_t newPackedLength, size_t newUnpackedLength)
{
	assert(newPackedLength > packedLength);

	packedLength = newPackedLength;
	unpackedLength = newUnpackedLength;

	unsigned char* newData = 0;

	CUDA_CHECK(
	    cudaHostAlloc(reinterpret_cast<void**>(&newData), packedLength * sizeof(unsigned char), cudaHostAllocMapped));

	memcpy(newData, data, packedLength * sizeof(unsigned char));

	CUDA_CHECK(cudaFreeHost(data));

	data = newData;
}

packed_data::packed_data(const packed_data& other)
    : packedLength(other.packedLength),
      unpackedLength(other.unpackedLength),
      bitmapLength(other.bitmapLength),
      packingType(other.packingType)
{
	data = 0;
	bitmap = 0;

	if (other.packedLength)
	{
		CUDA_CHECK(
		    cudaHostAlloc(reinterpret_cast<void**>(&data), packedLength * sizeof(unsigned char), cudaHostAllocMapped));

		memcpy(data, other.data, packedLength * sizeof(unsigned char));
	}

	if (other.bitmapLength)
	{
		cudaHostAlloc(reinterpret_cast<void**>(&bitmap), bitmapLength * sizeof(int), cudaHostAllocMapped);

		memcpy(bitmap, other.bitmap, bitmapLength * sizeof(int));
	}
}

void packed_data::Clear()
{
	if (packedLength)
	{
		assert(data);
		CUDA_CHECK(cudaFreeHost(data));
		packedLength = 0;
		data = 0;
	}

	if (bitmapLength)
	{
		assert(bitmap);
		CUDA_CHECK(cudaFreeHost(bitmap));
		bitmapLength = 0;
		bitmap = 0;
	}

	unpackedLength = 0;
}

#endif
<|endoftext|>


<commit_before>/**
 * @file density.cpp
 *
 * Computes desity for dry air from pressure and temperature using the ideal gas law.
 *
 * @date Mar 11, 2014
 * @author Tack
 */

#include "density.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("density");

density::density()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName));

}

void density::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter to ???
	 * - name PARM_NAME
	 * - univ_id UNIV_ID
	 * - grib2 descriptor X'Y'Z
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> theParams;

	param theRequestedParam("RHO-KGM3", 9999);

	// GRIB 2

	theRequestedParam.GribDiscipline(0);
	theRequestedParam.GribCategory(3);
	theRequestedParam.GribParameter(10);

	// GRIB 1

	/*
	 * GRIB 1 parameters go here
	 *
	 */

	theParams.push_back(theRequestedParam);

	SetParams(theParams);

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void density::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	// Required source parameters

	/*
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	params PParam = { param("P-PA"), param("P-HPA") };
	param TParam("T-K");
	// ----

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	while (AdjustNonLeadingDimension(myTargetInfo))
	{
		myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
								" level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
		double PScale = 1;

		shared_ptr<info> PInfo;
		shared_ptr<info> TInfo;

		shared_ptr<NFmiGrid> PGrid;
		bool isPressureLevel = (myTargetInfo->Level().Type() == kPressure);

		try
		{
			if(!isPressureLevel)
			{
			// Source info for PParam and TParam
				PInfo = theFetcher->Fetch(itsConfiguration,
								myTargetInfo->Time(),
								myTargetInfo->Level(),
								PParam);

				if (PInfo->Param().Unit() == kHPa || PInfo->Param().Name() == "P-HPA")
				{
					PScale = 100;
				}

				PGrid = shared_ptr<NFmiGrid> (PInfo->Grid()->ToNewbaseGrid());
			}
			TInfo = theFetcher->Fetch(itsConfiguration,
							myTargetInfo->Time(),
							myTargetInfo->Level(),
							TParam);

			// ----
		}
		catch (HPExceptionType e)
		{
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);

					if (itsConfiguration->StatisticsEnabled())
					{
						itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
						itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
					}

					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
		}

		unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Start();
		}

		size_t missingCount = 0;
		size_t count = 0;

		/*
		 * Converting original grid-data to newbase grid
		 *
		 */

		shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> TGrid(TInfo->Grid()->ToNewbaseGrid());

		bool equalGrids = ((isPressureLevel || *myTargetInfo->Grid() == *PInfo->Grid()) && *myTargetInfo->Grid() == *TInfo->Grid());

		string deviceType;

		{

			deviceType = "CPU";

			assert(targetGrid->Size() == myTargetInfo->Data()->Size());

			myTargetInfo->ResetLocation();

			targetGrid->Reset();

			while (myTargetInfo->NextLocation() && targetGrid->Next())
			{

				count++;

				/*
				 * interpolation happens here
				 *
				 */
				double P = kFloatMissing;
				double T = kFloatMissing;

				if (isPressureLevel)
				{
					P = 100 * myTargetInfo->Level().Value();
				}
				else
				{
				 	InterpolateToPoint(targetGrid, PGrid, equalGrids, P);
				}

				InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

				if (P == kFloatMissing || T == kFloatMissing )
				{
					missingCount++;

					myTargetInfo->Value(kFloatMissing);
					continue;
				}

				// actual calculation of the density using the ideal gas law
				double rho;

				rho = P * PScale / (constants::kRd * T);

				if (!myTargetInfo->Value(rho))
				{
					throw runtime_error(ClassName() + ": Failed to set value to matrix");
				}
			}

		}

		/*
		 * Newbase normalizes scanning mode to bottom left -- if that's not what
		 * the target scanning mode is, we have to swap the data back.
		 */

		SwapTo(myTargetInfo, kBottomLeft);

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Stop();
			itsConfiguration->Statistics()->AddToProcessingTime(processTimer->GetTime());

#ifdef DEBUG
			itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (processTimer->GetTime()) + " microseconds on "  + deviceType);
#endif

			itsConfiguration->Statistics()->AddToMissingCount(missingCount);
			itsConfiguration->Statistics()->AddToValueCount(count);

		}

		/*
		 * Now we are done for this level
		 *
		 * Clone info-instance to writer since it might change our descriptor places
		 * */

		myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		if (itsConfiguration->FileWriteOption() != kSingleFile)
		{
			WriteToFile(myTargetInfo);
		}
	}
}
<commit_msg>Universal ID for density set to 63<commit_after>/**
 * @file density.cpp
 *
 * Computes desity for dry air from pressure and temperature using the ideal gas law.
 *
 * @date Mar 11, 2014
 * @author Tack
 */

#include "density.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("density");

density::density()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName));

}

void density::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter to ???
	 * - name PARM_NAME
	 * - univ_id UNIV_ID
	 * - grib2 descriptor X'Y'Z
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> theParams;

	param theRequestedParam("RHO-KGM3", 63);

	// GRIB 2

	theRequestedParam.GribDiscipline(0);
	theRequestedParam.GribCategory(3);
	theRequestedParam.GribParameter(10);

	// GRIB 1

	/*
	 * GRIB 1 parameters go here
	 *
	 */

	theParams.push_back(theRequestedParam);

	SetParams(theParams);

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void density::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	// Required source parameters

	/*
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	params PParam = { param("P-PA"), param("P-HPA") };
	param TParam("T-K");
	// ----

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	while (AdjustNonLeadingDimension(myTargetInfo))
	{
		myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
								" level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
		double PScale = 1;

		shared_ptr<info> PInfo;
		shared_ptr<info> TInfo;

		shared_ptr<NFmiGrid> PGrid;
		bool isPressureLevel = (myTargetInfo->Level().Type() == kPressure);

		try
		{
			if(!isPressureLevel)
			{
			// Source info for PParam and TParam
				PInfo = theFetcher->Fetch(itsConfiguration,
								myTargetInfo->Time(),
								myTargetInfo->Level(),
								PParam);

				if (PInfo->Param().Unit() == kHPa || PInfo->Param().Name() == "P-HPA")
				{
					PScale = 100;
				}

				PGrid = shared_ptr<NFmiGrid> (PInfo->Grid()->ToNewbaseGrid());
			}
			TInfo = theFetcher->Fetch(itsConfiguration,
							myTargetInfo->Time(),
							myTargetInfo->Level(),
							TParam);

			// ----
		}
		catch (HPExceptionType e)
		{
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);

					if (itsConfiguration->StatisticsEnabled())
					{
						itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
						itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
					}

					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
		}

		unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Start();
		}

		size_t missingCount = 0;
		size_t count = 0;

		/*
		 * Converting original grid-data to newbase grid
		 *
		 */

		shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> TGrid(TInfo->Grid()->ToNewbaseGrid());

		bool equalGrids = ((isPressureLevel || *myTargetInfo->Grid() == *PInfo->Grid()) && *myTargetInfo->Grid() == *TInfo->Grid());

		string deviceType;

		{

			deviceType = "CPU";

			assert(targetGrid->Size() == myTargetInfo->Data()->Size());

			myTargetInfo->ResetLocation();

			targetGrid->Reset();

			while (myTargetInfo->NextLocation() && targetGrid->Next())
			{

				count++;

				/*
				 * interpolation happens here
				 *
				 */
				double P = kFloatMissing;
				double T = kFloatMissing;

				if (isPressureLevel)
				{
					P = 100 * myTargetInfo->Level().Value();
				}
				else
				{
				 	InterpolateToPoint(targetGrid, PGrid, equalGrids, P);
				}

				InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

				if (P == kFloatMissing || T == kFloatMissing )
				{
					missingCount++;

					myTargetInfo->Value(kFloatMissing);
					continue;
				}

				// actual calculation of the density using the ideal gas law
				double rho;

				rho = P * PScale / (constants::kRd * T);

				if (!myTargetInfo->Value(rho))
				{
					throw runtime_error(ClassName() + ": Failed to set value to matrix");
				}
			}

		}

		/*
		 * Newbase normalizes scanning mode to bottom left -- if that's not what
		 * the target scanning mode is, we have to swap the data back.
		 */

		SwapTo(myTargetInfo, kBottomLeft);

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Stop();
			itsConfiguration->Statistics()->AddToProcessingTime(processTimer->GetTime());

#ifdef DEBUG
			itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (processTimer->GetTime()) + " microseconds on "  + deviceType);
#endif

			itsConfiguration->Statistics()->AddToMissingCount(missingCount);
			itsConfiguration->Statistics()->AddToValueCount(count);

		}

		/*
		 * Now we are done for this level
		 *
		 * Clone info-instance to writer since it might change our descriptor places
		 * */

		myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		if (itsConfiguration->FileWriteOption() != kSingleFile)
		{
			WriteToFile(myTargetInfo);
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file fetcher.cpp
 *
 * @date Nov 21, 2012
 * @author partio
 */

#include "fetcher.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/operations.hpp>
#include "timer_factory.h"
#include "util.h"

#define HIMAN_AUXILIARY_INCLUDE

#include "grib.h"
#include "neons.h"
#include "param.h"
#include "cache.h"
#include "querydata.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace himan::plugin;
using namespace std;

const unsigned int sleepSeconds = 10;

shared_ptr<cache> itsCache;

fetcher::fetcher()
{
	itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("fetcher"));
}

shared_ptr<himan::info> fetcher::Fetch(shared_ptr<const plugin_configuration> config,
										const forecast_time& requestedTime,
										const level& requestedLevel,
										const param& requestedParam,
										bool readPackedData)
{

	unique_ptr<timer> t = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

	if (config->StatisticsEnabled())
	{
		t->Start();
	}

	const search_options opts (requestedTime, requestedParam, requestedLevel, config) ;

	vector<shared_ptr<info>> theInfos;
	unsigned int waitedSeconds = 0;

	do
	{
		// Loop over all source producers if more than one specified

		config->FirstSourceProducer();

		do
		{

			itsLogger->Debug("Current producer: " + config->SourceProducer().Name());

			if (config->UseCache())
			{

				// 1. Fetch data from cache

				itsCache = dynamic_pointer_cast<plugin::cache> (plugin_factory::Instance()->Plugin("cache"));

				theInfos = FromCache(opts);

				if (theInfos.size())
				{
					itsLogger->Debug("Data found from cache");

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheHitCount(1);
					}

					break;
				}
			}

			/*
			 *  2. Fetch data from auxiliary files specified at command line
			 *
			 *  Even if file_wait_timeout is specified, auxiliary files is searched
			 *  only once.
			 */

			if (config->AuxiliaryFiles().size() && waitedSeconds == 0)
			{
				theInfos = FromFile(config->AuxiliaryFiles(), opts, true, readPackedData);

				if (theInfos.size())
				{
					itsLogger->Debug("Data found from auxiliary file(s)");

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheMissCount(1);
					}

					break;
				}
				else
				{
					itsLogger->Warning("Data not found from auxiliary file(s)");
				}
			}

			// 3. Fetch data from Neons

			vector<string> files;

			if (config->ReadDataFromDatabase())
			{
				shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

				files = n->Files(opts);

				if (!files.empty())
				{
					theInfos = FromFile(files, opts, true, readPackedData);

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheMissCount(1);
					}

					break;
				}
				else
				{
					itsLogger->Debug("Could not find file(s) from Neons matching requested parameters");
				}
			}
		} while (config->NextSourceProducer());

		if (config->FileWaitTimeout() > 0)
		{
			itsLogger->Debug("Sleeping for " + boost::lexical_cast<string> (sleepSeconds) + " seconds (cumulative: " + boost::lexical_cast<string> (waitedSeconds) + ")");

			if (!config->ReadDataFromDatabase())
			{
				itsLogger->Warning("file_wait_timeout specified but file read from Neons is disabled");
			}

			sleep(sleepSeconds);
		}

		waitedSeconds += sleepSeconds;
	}
	while (waitedSeconds < config->FileWaitTimeout() * 60);

	if (config->StatisticsEnabled())
	{
		t->Stop();

		config->Statistics()->AddToFetchingTime(t->GetTime());
	}
	/*
	 *  Safeguard; later in the code we do not check whether the data requested
	 *  was actually what was requested.
	 */

	if (theInfos.size() == 0)
	{
		string optsStr = "producer: " + boost::lexical_cast<string> (config->SourceProducer().Id());
		optsStr += " origintime: " + requestedTime.OriginDateTime()->String() + ", step: " + boost::lexical_cast<string> (requestedTime.Step());
		optsStr += " param: " + requestedParam.Name();
		optsStr += " level: " + string(himan::HPLevelTypeToString.at(requestedLevel.Type())) + " " + boost::lexical_cast<string> (requestedLevel.Value());

		itsLogger->Warning("No valid data found with given search options " + optsStr);

		throw kFileDataNotFound;
	}

	// assert(theConfiguration->SourceProducer() == theInfos[0]->Producer());

	assert((theInfos[0]->Level()) == requestedLevel);

	assert((theInfos[0]->Time()) == requestedTime);

	assert((theInfos[0]->Param()) == requestedParam);

	return theInfos[0];

}

/*
 * FromFile()
 *
 * Get data and metadata from a file. Returns a vector of infos, mainly because one grib file can
 * contain many grib messages. If read file is querydata, the vector size is always one (or zero if the
 * read fails).
 */

vector<shared_ptr<himan::info>> fetcher::FromFile(const vector<string>& files, const search_options& options, bool readContents, bool readPackedData)
{

	vector<shared_ptr<himan::info>> allInfos ;

	for (size_t i = 0; i < files.size(); i++)
	{
		string inputFile = files[i];

		if (!boost::filesystem::exists(inputFile))
		{
			itsLogger->Error("Input file '" + inputFile + "' does not exist");
			continue;
		}

		vector<shared_ptr<himan::info>> curInfos;

		switch (util::FileType(inputFile))
		{

		case kGRIB:
		case kGRIB1:
		case kGRIB2:
		{

			curInfos = FromGrib(inputFile, options, readContents, readPackedData);
			break;

		}

		case kQueryData:
		{

			curInfos = FromQueryData(inputFile, options, readContents);
			break;
		}

		case kNetCDF:
			cout << "File is NetCDF" << endl;
			break;

		default:
			// Unknown file type, cannot proceed
			throw runtime_error("Input file is neither GRID, NetCDF nor QueryData");
			break;
		}

		allInfos.insert(allInfos.end(), curInfos.begin(), curInfos.end());

		if (curInfos.size())
		{
			if (options.configuration->UseCache())
			{
				itsCache->Insert(allInfos);
			}

			break; // We found what we were looking for
		}

	}

	return allInfos;
}

vector<shared_ptr<himan::info> > fetcher::FromCache(const search_options& options)
{
	vector<shared_ptr<himan::info>> infos = itsCache->GetInfo(options);

	return infos;
}

vector<shared_ptr<himan::info> > fetcher::FromGrib(const string& inputFile, const search_options& options, bool readContents, bool readPackedData)
{

	shared_ptr<grib> g = dynamic_pointer_cast<grib> (plugin_factory::Instance()->Plugin("grib"));

	vector<shared_ptr<info>> infos = g->FromFile(inputFile, options, readContents, readPackedData);

	return infos;
}

vector<shared_ptr<himan::info>> fetcher::FromQueryData(const string& inputFile, const search_options& options, bool readContents)
{

	shared_ptr<querydata> q = dynamic_pointer_cast<querydata> (plugin_factory::Instance()->Plugin("querydata"));

	shared_ptr<info> i = q->FromFile(inputFile, options, readContents);

	vector<shared_ptr<info>> theInfos;

	theInfos.push_back(i);

	return theInfos;
}
<commit_msg>change logging level to trace<commit_after>/**
 * @file fetcher.cpp
 *
 * @date Nov 21, 2012
 * @author partio
 */

#include "fetcher.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/operations.hpp>
#include "timer_factory.h"
#include "util.h"

#define HIMAN_AUXILIARY_INCLUDE

#include "grib.h"
#include "neons.h"
#include "param.h"
#include "cache.h"
#include "querydata.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace himan::plugin;
using namespace std;

const unsigned int sleepSeconds = 10;

shared_ptr<cache> itsCache;

fetcher::fetcher()
{
	itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("fetcher"));
}

shared_ptr<himan::info> fetcher::Fetch(shared_ptr<const plugin_configuration> config,
										const forecast_time& requestedTime,
										const level& requestedLevel,
										const param& requestedParam,
										bool readPackedData)
{

	unique_ptr<timer> t = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

	if (config->StatisticsEnabled())
	{
		t->Start();
	}

	const search_options opts (requestedTime, requestedParam, requestedLevel, config) ;

	vector<shared_ptr<info>> theInfos;
	unsigned int waitedSeconds = 0;

	do
	{
		// Loop over all source producers if more than one specified

		config->FirstSourceProducer();

		do
		{

			itsLogger->Trace("Current producer: " + config->SourceProducer().Name());

			if (config->UseCache())
			{

				// 1. Fetch data from cache

				itsCache = dynamic_pointer_cast<plugin::cache> (plugin_factory::Instance()->Plugin("cache"));

				theInfos = FromCache(opts);

				if (theInfos.size())
				{
					itsLogger->Debug("Data found from cache");

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheHitCount(1);
					}

					break;
				}
			}

			/*
			 *  2. Fetch data from auxiliary files specified at command line
			 *
			 *  Even if file_wait_timeout is specified, auxiliary files is searched
			 *  only once.
			 */

			if (config->AuxiliaryFiles().size() && waitedSeconds == 0)
			{
				theInfos = FromFile(config->AuxiliaryFiles(), opts, true, readPackedData);

				if (theInfos.size())
				{
					itsLogger->Debug("Data found from auxiliary file(s)");

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheMissCount(1);
					}

					break;
				}
				else
				{
					itsLogger->Warning("Data not found from auxiliary file(s)");
				}
			}

			// 3. Fetch data from Neons

			vector<string> files;

			if (config->ReadDataFromDatabase())
			{
				shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

				files = n->Files(opts);

				if (!files.empty())
				{
					theInfos = FromFile(files, opts, true, readPackedData);

					if (config->StatisticsEnabled())
					{
						config->Statistics()->AddToCacheMissCount(1);
					}

					break;
				}
				else
				{
					itsLogger->Debug("Could not find file(s) from Neons matching requested parameters");
				}
			}
		} while (config->NextSourceProducer());

		if (config->FileWaitTimeout() > 0)
		{
			itsLogger->Debug("Sleeping for " + boost::lexical_cast<string> (sleepSeconds) + " seconds (cumulative: " + boost::lexical_cast<string> (waitedSeconds) + ")");

			if (!config->ReadDataFromDatabase())
			{
				itsLogger->Warning("file_wait_timeout specified but file read from Neons is disabled");
			}

			sleep(sleepSeconds);
		}

		waitedSeconds += sleepSeconds;
	}
	while (waitedSeconds < config->FileWaitTimeout() * 60);

	if (config->StatisticsEnabled())
	{
		t->Stop();

		config->Statistics()->AddToFetchingTime(t->GetTime());
	}
	/*
	 *  Safeguard; later in the code we do not check whether the data requested
	 *  was actually what was requested.
	 */

	if (theInfos.size() == 0)
	{
		string optsStr = "producer: " + boost::lexical_cast<string> (config->SourceProducer().Id());
		optsStr += " origintime: " + requestedTime.OriginDateTime()->String() + ", step: " + boost::lexical_cast<string> (requestedTime.Step());
		optsStr += " param: " + requestedParam.Name();
		optsStr += " level: " + string(himan::HPLevelTypeToString.at(requestedLevel.Type())) + " " + boost::lexical_cast<string> (requestedLevel.Value());

		itsLogger->Warning("No valid data found with given search options " + optsStr);

		throw kFileDataNotFound;
	}

	// assert(theConfiguration->SourceProducer() == theInfos[0]->Producer());

	assert((theInfos[0]->Level()) == requestedLevel);

	assert((theInfos[0]->Time()) == requestedTime);

	assert((theInfos[0]->Param()) == requestedParam);

	return theInfos[0];

}

/*
 * FromFile()
 *
 * Get data and metadata from a file. Returns a vector of infos, mainly because one grib file can
 * contain many grib messages. If read file is querydata, the vector size is always one (or zero if the
 * read fails).
 */

vector<shared_ptr<himan::info>> fetcher::FromFile(const vector<string>& files, const search_options& options, bool readContents, bool readPackedData)
{

	vector<shared_ptr<himan::info>> allInfos ;

	for (size_t i = 0; i < files.size(); i++)
	{
		string inputFile = files[i];

		if (!boost::filesystem::exists(inputFile))
		{
			itsLogger->Error("Input file '" + inputFile + "' does not exist");
			continue;
		}

		vector<shared_ptr<himan::info>> curInfos;

		switch (util::FileType(inputFile))
		{

		case kGRIB:
		case kGRIB1:
		case kGRIB2:
		{

			curInfos = FromGrib(inputFile, options, readContents, readPackedData);
			break;

		}

		case kQueryData:
		{

			curInfos = FromQueryData(inputFile, options, readContents);
			break;
		}

		case kNetCDF:
			cout << "File is NetCDF" << endl;
			break;

		default:
			// Unknown file type, cannot proceed
			throw runtime_error("Input file is neither GRID, NetCDF nor QueryData");
			break;
		}

		allInfos.insert(allInfos.end(), curInfos.begin(), curInfos.end());

		if (curInfos.size())
		{
			if (options.configuration->UseCache())
			{
				itsCache->Insert(allInfos);
			}

			break; // We found what we were looking for
		}

	}

	return allInfos;
}

vector<shared_ptr<himan::info> > fetcher::FromCache(const search_options& options)
{
	vector<shared_ptr<himan::info>> infos = itsCache->GetInfo(options);

	return infos;
}

vector<shared_ptr<himan::info> > fetcher::FromGrib(const string& inputFile, const search_options& options, bool readContents, bool readPackedData)
{

	shared_ptr<grib> g = dynamic_pointer_cast<grib> (plugin_factory::Instance()->Plugin("grib"));

	vector<shared_ptr<info>> infos = g->FromFile(inputFile, options, readContents, readPackedData);

	return infos;
}

vector<shared_ptr<himan::info>> fetcher::FromQueryData(const string& inputFile, const search_options& options, bool readContents)
{

	shared_ptr<querydata> q = dynamic_pointer_cast<querydata> (plugin_factory::Instance()->Plugin("querydata"));

	shared_ptr<info> i = q->FromFile(inputFile, options, readContents);

	vector<shared_ptr<info>> theInfos;

	theInfos.push_back(i);

	return theInfos;
}
<|endoftext|>


<commit_before>// Template generated code from trgen <version>

#include \<iostream>
#include \<iomanip>
#include \<string>
#include \<chrono>
#include \<atomic>
#include "ANTLRInputStream.h"
#include "ErrorListener.h"
<tool_grammar_tuples:{x | #include "<x.GeneratedIncludeFileName>"
} >
#include "CaseChangingCharStream.h"

std::string formatDuration(uint64_t duration) {
	std::stringstream oss;
    // duration is in microseconds units.
    long tseconds = duration / 1000000;
    long minutes = tseconds / 60;
    long seconds = tseconds % 60;
    long microseconds = duration % 1000000;
    oss \<\< std::setfill('0')
        \<\< minutes
        \<\< ":"
        \<\< std::setw(2)
        \<\< seconds
        \<\< "."
        \<\< std::setw(6)
        \<\< microseconds;
    return oss.str();
}

int TryParse(std::vector\<std::string>& args)
{
    bool show_tree = false;
    bool show_tokens = false;
    std::string * file_name = nullptr;
    std::string * input = nullptr;
    for (int i = 0; i \< args.size(); ++i)
    {
        if (args[i] == "-tokens")
        {
            show_tokens = true;
            continue;
        }
        else if (args[i] == "-tree")
        {
            show_tree = true;
            continue;
        }
        else if (args[i] == "-input")
            input = & args[++i];
        else if (args[i] == "-file")
            file_name = & args[++i];
    }
    antlr4::CharStream* str = nullptr;
    if (input == nullptr && file_name == nullptr)
    {
        str = new antlr4::ANTLRInputStream(std::cin);
    } else if (input != nullptr)
    {
        str = new antlr4::ANTLRInputStream(*input);
    } else if (file_name != nullptr)
    {
        std::fstream fs(*file_name);
        str = new antlr4::ANTLRInputStream(fs);
    }
    <if (case_insensitive_type)>
    bool up = (new std::string("Upper"))->compare("Upper") == 0;
    str = new antlr4::runtime::CaseChangingCharStream(str, up);
    <endif>
        antlr4::Lexer * lexer = new <lexer_name>(str);
    if (show_tokens)
    {
        for (int i = 0; ; ++i)
        {
            auto token = lexer->nextToken();
            std::cout \<\< token->toString() \<\< std::endl;
            if (token->getType() == antlr4::IntStream::EOF)
                break;
        }
        lexer->reset();
    }
    auto tokens = new antlr4::CommonTokenStream(lexer);
    auto * parser = new <parser_name>(tokens);
    auto listener_lexer = new ErrorListener();
    auto listener_parser = new ErrorListener();
    lexer->removeErrorListeners();
    parser->removeErrorListeners();
    lexer->addErrorListener(listener_lexer);
    parser->addErrorListener(listener_parser);
    auto before = std::chrono::steady_clock::now();
    auto tree = parser-><start_symbol>();
    auto after = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast\<std::chrono::microseconds>(after - before);
    if (listener_parser->had_error || listener_lexer->had_error)
    {
        std::cerr \<\< "Parse failed." \<\< std::endl;
    }
    else
    {
        std::cerr \<\< "Parse succeeded." \<\< std::endl;
    }
    if (show_tree)
    {
        std::out \<\< tree.ToStringTree(parser) \<\< std:end1;
    }
    std::cerr \<\< "Time: " \<\< formatDuration(duration.count()) \<\< std::endl;
    return 0;
}

int main(int argc, const char * argv[])
{
    std::vector \<std::string> args;
    for (int i = 1; i \< argc; ++i)
    {
        args.push_back(argv[i]);
    }
    TryParse(args);
}

<commit_msg>Typo in C++ version of test code.<commit_after>// Template generated code from trgen <version>

#include \<iostream>
#include \<iomanip>
#include \<string>
#include \<chrono>
#include \<atomic>
#include "ANTLRInputStream.h"
#include "ErrorListener.h"
<tool_grammar_tuples:{x | #include "<x.GeneratedIncludeFileName>"
} >
#include "CaseChangingCharStream.h"

std::string formatDuration(uint64_t duration) {
	std::stringstream oss;
    // duration is in microseconds units.
    long tseconds = duration / 1000000;
    long minutes = tseconds / 60;
    long seconds = tseconds % 60;
    long microseconds = duration % 1000000;
    oss \<\< std::setfill('0')
        \<\< minutes
        \<\< ":"
        \<\< std::setw(2)
        \<\< seconds
        \<\< "."
        \<\< std::setw(6)
        \<\< microseconds;
    return oss.str();
}

int TryParse(std::vector\<std::string>& args)
{
    bool show_tree = false;
    bool show_tokens = false;
    std::string * file_name = nullptr;
    std::string * input = nullptr;
    for (int i = 0; i \< args.size(); ++i)
    {
        if (args[i] == "-tokens")
        {
            show_tokens = true;
            continue;
        }
        else if (args[i] == "-tree")
        {
            show_tree = true;
            continue;
        }
        else if (args[i] == "-input")
            input = & args[++i];
        else if (args[i] == "-file")
            file_name = & args[++i];
    }
    antlr4::CharStream* str = nullptr;
    if (input == nullptr && file_name == nullptr)
    {
        str = new antlr4::ANTLRInputStream(std::cin);
    } else if (input != nullptr)
    {
        str = new antlr4::ANTLRInputStream(*input);
    } else if (file_name != nullptr)
    {
        std::fstream fs(*file_name);
        str = new antlr4::ANTLRInputStream(fs);
    }
    <if (case_insensitive_type)>
    bool up = (new std::string("Upper"))->compare("Upper") == 0;
    str = new antlr4::runtime::CaseChangingCharStream(str, up);
    <endif>
        antlr4::Lexer * lexer = new <lexer_name>(str);
    if (show_tokens)
    {
        for (int i = 0; ; ++i)
        {
            auto token = lexer->nextToken();
            std::cout \<\< token->toString() \<\< std::endl;
            if (token->getType() == antlr4::IntStream::EOF)
                break;
        }
        lexer->reset();
    }
    auto tokens = new antlr4::CommonTokenStream(lexer);
    auto * parser = new <parser_name>(tokens);
    auto listener_lexer = new ErrorListener();
    auto listener_parser = new ErrorListener();
    lexer->removeErrorListeners();
    parser->removeErrorListeners();
    lexer->addErrorListener(listener_lexer);
    parser->addErrorListener(listener_parser);
    auto before = std::chrono::steady_clock::now();
    auto tree = parser-><start_symbol>();
    auto after = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast\<std::chrono::microseconds>(after - before);
    if (listener_parser->had_error || listener_lexer->had_error)
    {
        std::cerr \<\< "Parse failed." \<\< std::endl;
    }
    else
    {
        std::cerr \<\< "Parse succeeded." \<\< std::endl;
    }
    if (show_tree)
    {
        std::cout \<\< tree.ToStringTree(parser) \<\< std::endl;
    }
    std::cerr \<\< "Time: " \<\< formatDuration(duration.count()) \<\< std::endl;
    return 0;
}

int main(int argc, const char * argv[])
{
    std::vector \<std::string> args;
    for (int i = 1; i \< argc; ++i)
    {
        args.push_back(argv[i]);
    }
    TryParse(args);
}

<|endoftext|>


<commit_before>// Template generated code from trgen <version>

#include \<iostream>
#include \<iomanip>
#include \<string>
#include \<chrono>
#include \<atomic>
#include "ANTLRInputStream.h"
#include "ErrorListener.h"
<tool_grammar_tuples:{x | #include "<x.GeneratedIncludeFileName>"
} >
#include "CaseChangingCharStream.h"

std::string formatDuration(uint64_t duration) {
	std::stringstream oss;
    // duration is in microseconds units.
    long tseconds = duration / 1000000;
    long minutes = tseconds / 60;
    long seconds = tseconds % 60;
    long microseconds = duration % 1000000;
    oss \<\< std::setfill('0')
        \<\< minutes
        \<\< ":"
        \<\< std::setw(2)
        \<\< seconds
        \<\< "."
        \<\< std::setw(6)
        \<\< microseconds;
    return oss.str();
}

int TryParse(std::vector\<std::string>& args)
{
    bool show_tree = false;
    bool show_tokens = false;
    std::string * file_name = nullptr;
    std::string * input = nullptr;
    for (int i = 0; i \< args.size(); ++i)
    {
        if (args[i] == "-tokens")
        {
            show_tokens = true;
            continue;
        }
        else if (args[i] == "-tree")
        {
            show_tree = true;
            continue;
        }
        else if (args[i] == "-input")
            input = & args[++i];
        else if (args[i] == "-file")
            file_name = & args[++i];
    }
    antlr4::CharStream* str = nullptr;
    if (input == nullptr && file_name == nullptr)
    {
        str = new antlr4::ANTLRInputStream(std::cin);
    } else if (input != nullptr)
    {
        str = new antlr4::ANTLRInputStream(*input);
    } else if (file_name != nullptr)
    {
        std::fstream fs(*file_name);
        str = new antlr4::ANTLRInputStream(fs);
    }
    <if (case_insensitive_type)>
    bool up = (new std::string("Upper"))->compare("Upper") == 0;
    str = new antlr4::runtime::CaseChangingCharStream(str, up);
    <endif>
        antlr4::Lexer * lexer = new <lexer_name>(str);
    if (show_tokens)
    {
        for (int i = 0; ; ++i)
        {
            auto token = lexer->nextToken();
            std::cout \<\< token->toString() \<\< std::endl;
            if (token->getType() == antlr4::IntStream::EOF)
                break;
        }
        lexer->reset();
    }
    auto tokens = new antlr4::CommonTokenStream(lexer);
    auto * parser = new <parser_name>(tokens);
    auto listener_lexer = new ErrorListener();
    auto listener_parser = new ErrorListener();
    lexer->removeErrorListeners();
    parser->removeErrorListeners();
    lexer->addErrorListener(listener_lexer);
    parser->addErrorListener(listener_parser);
    auto before = std::chrono::steady_clock::now();
    auto tree = parser-><start_symbol>();
    auto after = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast\<std::chrono::microseconds>(after - before);
    if (listener_parser->had_error || listener_lexer->had_error)
    {
        std::cerr \<\< "Parse failed." \<\< std::endl;
    }
    else
    {
        std::cerr \<\< "Parse succeeded." \<\< std::endl;
    }
    if (show_tree)
    {
        std::cout \<\< tree.ToStringTree(parser) \<\< std::endl;
    }
    std::cerr \<\< "Time: " \<\< formatDuration(duration.count()) \<\< std::endl;
    return 0;
}

int main(int argc, const char * argv[])
{
    std::vector \<std::string> args;
    for (int i = 1; i \< argc; ++i)
    {
        args.push_back(argv[i]);
    }
    TryParse(args);
}

<commit_msg>Typo in C++ toStringTree() method call.<commit_after>// Template generated code from trgen <version>

#include \<iostream>
#include \<iomanip>
#include \<string>
#include \<chrono>
#include \<atomic>
#include "ANTLRInputStream.h"
#include "ErrorListener.h"
<tool_grammar_tuples:{x | #include "<x.GeneratedIncludeFileName>"
} >
#include "CaseChangingCharStream.h"

std::string formatDuration(uint64_t duration) {
	std::stringstream oss;
    // duration is in microseconds units.
    long tseconds = duration / 1000000;
    long minutes = tseconds / 60;
    long seconds = tseconds % 60;
    long microseconds = duration % 1000000;
    oss \<\< std::setfill('0')
        \<\< minutes
        \<\< ":"
        \<\< std::setw(2)
        \<\< seconds
        \<\< "."
        \<\< std::setw(6)
        \<\< microseconds;
    return oss.str();
}

int TryParse(std::vector\<std::string>& args)
{
    bool show_tree = false;
    bool show_tokens = false;
    std::string * file_name = nullptr;
    std::string * input = nullptr;
    for (int i = 0; i \< args.size(); ++i)
    {
        if (args[i] == "-tokens")
        {
            show_tokens = true;
            continue;
        }
        else if (args[i] == "-tree")
        {
            show_tree = true;
            continue;
        }
        else if (args[i] == "-input")
            input = & args[++i];
        else if (args[i] == "-file")
            file_name = & args[++i];
    }
    antlr4::CharStream* str = nullptr;
    if (input == nullptr && file_name == nullptr)
    {
        str = new antlr4::ANTLRInputStream(std::cin);
    } else if (input != nullptr)
    {
        str = new antlr4::ANTLRInputStream(*input);
    } else if (file_name != nullptr)
    {
        std::fstream fs(*file_name);
        str = new antlr4::ANTLRInputStream(fs);
    }
    <if (case_insensitive_type)>
    bool up = (new std::string("Upper"))->compare("Upper") == 0;
    str = new antlr4::runtime::CaseChangingCharStream(str, up);
    <endif>
        antlr4::Lexer * lexer = new <lexer_name>(str);
    if (show_tokens)
    {
        for (int i = 0; ; ++i)
        {
            auto token = lexer->nextToken();
            std::cout \<\< token->toString() \<\< std::endl;
            if (token->getType() == antlr4::IntStream::EOF)
                break;
        }
        lexer->reset();
    }
    auto tokens = new antlr4::CommonTokenStream(lexer);
    auto * parser = new <parser_name>(tokens);
    auto listener_lexer = new ErrorListener();
    auto listener_parser = new ErrorListener();
    lexer->removeErrorListeners();
    parser->removeErrorListeners();
    lexer->addErrorListener(listener_lexer);
    parser->addErrorListener(listener_parser);
    auto before = std::chrono::steady_clock::now();
    auto tree = parser-><start_symbol>();
    auto after = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast\<std::chrono::microseconds>(after - before);
    if (listener_parser->had_error || listener_lexer->had_error)
    {
        std::cerr \<\< "Parse failed." \<\< std::endl;
    }
    else
    {
        std::cerr \<\< "Parse succeeded." \<\< std::endl;
    }
    if (show_tree)
    {
        std::cout \<\< tree->toStringTree(parser, false) \<\< std::endl;
    }
    std::cerr \<\< "Time: " \<\< formatDuration(duration.count()) \<\< std::endl;
    return 0;
}

int main(int argc, const char * argv[])
{
    std::vector \<std::string> args;
    for (int i = 1; i \< argc; ++i)
    {
        args.push_back(argv[i]);
    }
    TryParse(args);
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 "lldb-eval/context.h"

#include <memory>

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
#include "llvm/Support/FormatVariadic.h"

namespace lldb_eval {

Context::Context(std::string expr, lldb::SBExecutionContext ctx,
                 lldb::SBValue scope)
    : expr_(std::move(expr)), ctx_(ctx), scope_(scope) {
  // This holds a SourceManager and all of its dependencies.
  smff_ = std::make_unique<clang::SourceManagerForFile>("<expr>", expr_);

  // Disable default diagnostics reporting.
  // TODO(werat): Add custom consumer to keep track of errors.
  clang::DiagnosticsEngine& de = smff_->get().getDiagnostics();
  de.setClient(new clang::IgnoringDiagConsumer);
}

lldb::SBType Context::ResolveTypeByName(const char* name) const {
  // TODO(b/163308825): Do scope-aware type lookup. Look for the types defined
  // in the current scope (function, class, namespace) and prioritize them.

  // Internally types don't have global scope qualifier in their names and
  // LLDB doesn't support queries with it too.
  llvm::StringRef name_ref(name);
  bool global_scope = false;

  if (name_ref.startswith("::")) {
    name_ref = name_ref.drop_front(2);
    global_scope = true;
  }

  // SBTarget::FindTypes will return all matched types, including the ones one
  // in different scopes. I.e. if seaching for "myint", this will also return
  // "ns::myint" and "Foo::myint".
  lldb::SBTypeList types = ctx_.GetTarget().FindTypes(name_ref.data());

  // We've found multiple types, try finding the "correct" one.
  lldb::SBType full_match;
  std::vector<lldb::SBType> partial_matches;

  for (uint32_t i = 0; i < types.GetSize(); ++i) {
    lldb::SBType type = types.GetTypeAtIndex(i);
    llvm::StringRef type_name = type.GetName();

    if (type_name == name_ref) {
      full_match = type;
    } else if (type_name.endswith(name_ref)) {
      partial_matches.push_back(type);
    }
  }

  if (global_scope) {
    // Look only for full matches when looking for a globally qualified type.
    if (full_match.IsValid()) {
      return full_match;
    }
  } else {
    // TODO(b/163308825): We're looking for type, but there may be multiple
    // candidates and which one is correct depends on the currect scope. For now
    // just pick the most "probable" type.

    // Full match is always correct if we're currently in the global scope.
    if (full_match.IsValid()) {
      return full_match;
    }

    // If we have partial matches, pick a "random" one.
    if (partial_matches.size() > 0) {
      return partial_matches.back();
    }
  }

  return lldb::SBType();
}

lldb::SBValue Context::LookupIdentifier(const char* name) const {
  // Internally values don't have global scope qualifier in their names and
  // LLDB doesn't support queries with it too.
  llvm::StringRef name_ref(name);
  bool global_scope = false;

  if (name_ref.startswith("::")) {
    name_ref = name_ref.drop_front(2);
    global_scope = true;
  }

  lldb::SBValue value;

  // If the identifier doesn't refer to the global scope and doesn't have any
  // other scope qualifiers, try looking among the local and instance variables.
  if (!global_scope && name_ref.find("::") == llvm::StringRef::npos) {
    if (!scope_) {
      // Lookup in the current frame.
      lldb::SBFrame frame = ctx_.GetFrame();
      // Try looking for a local variable in current scope.
      if (!value) {
        value = frame.FindVariable(name_ref.data());
      }
      // Try looking for an instance variable (class member).
      if (!value) {
        value =
            frame.FindVariable("this").GetChildMemberWithName(name_ref.data());
      }
    } else {
      // Lookup the variable as a member of the current scope value.
      value = scope_.GetChildMemberWithName(name_ref.data());
    }
  }

  // Try looking for a global or static variable.
  if (!value) {
    // TODO(werat): Implement scope-aware lookup. Relative scopes should be
    // resolved relative to the current scope. I.e. if the current frame is in
    // "ns1::ns2::Foo()", then "ns2::x" should resolve to "ns1::ns2::x".

    // List global variable with the same "basename". There can be many matches
    // from other scopes (namespaces, classes), so we do additional filtering
    // later.
    lldb::SBValueList values = ctx_.GetTarget().FindGlobalVariables(
        name_ref.data(), /*max_matches=*/std::numeric_limits<uint32_t>::max());

    // Find the corrent variable by matching the name. lldb::SBValue::GetName()
    // can return strings like "::globarVar", "ns::i" or "int const ns::foo"
    // depending on the version and the platform.
    for (uint32_t i = 0; i < values.GetSize(); ++i) {
      lldb::SBValue val = values.GetValueAtIndex(i);
      llvm::StringRef val_name = val.GetName();

      if (val_name == name_ref ||
          val_name == llvm::formatv("::{0}", name_ref).str() ||
          val_name.endswith(llvm::formatv(" {0}", name_ref).str())) {
        value = val;
        break;
      }
    }
  }

  return value;
}

std::shared_ptr<Context> Context::Create(std::string expr,
                                         lldb::SBFrame frame) {
  return std::shared_ptr<Context>(new Context(
      std::move(expr), lldb::SBExecutionContext(frame), lldb::SBValue()));
}

std::shared_ptr<Context> Context::Create(std::string expr,
                                         lldb::SBValue scope) {
  return std::shared_ptr<Context>(new Context(
      std::move(expr), lldb::SBExecutionContext(scope.GetFrame()), scope));
}

}  // namespace lldb_eval
<commit_msg>Some SBValues don't have an SBFrame<commit_after>// Copyright 2020 Google LLC
//
// 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 "lldb-eval/context.h"

#include <memory>

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
#include "llvm/Support/FormatVariadic.h"

namespace lldb_eval {

Context::Context(std::string expr, lldb::SBExecutionContext ctx,
                 lldb::SBValue scope)
    : expr_(std::move(expr)), ctx_(ctx), scope_(scope) {
  // This holds a SourceManager and all of its dependencies.
  smff_ = std::make_unique<clang::SourceManagerForFile>("<expr>", expr_);

  // Disable default diagnostics reporting.
  // TODO(werat): Add custom consumer to keep track of errors.
  clang::DiagnosticsEngine& de = smff_->get().getDiagnostics();
  de.setClient(new clang::IgnoringDiagConsumer);
}

lldb::SBType Context::ResolveTypeByName(const char* name) const {
  // TODO(b/163308825): Do scope-aware type lookup. Look for the types defined
  // in the current scope (function, class, namespace) and prioritize them.

  // Internally types don't have global scope qualifier in their names and
  // LLDB doesn't support queries with it too.
  llvm::StringRef name_ref(name);
  bool global_scope = false;

  if (name_ref.startswith("::")) {
    name_ref = name_ref.drop_front(2);
    global_scope = true;
  }

  // SBTarget::FindTypes will return all matched types, including the ones one
  // in different scopes. I.e. if seaching for "myint", this will also return
  // "ns::myint" and "Foo::myint".
  lldb::SBTypeList types = ctx_.GetTarget().FindTypes(name_ref.data());

  // We've found multiple types, try finding the "correct" one.
  lldb::SBType full_match;
  std::vector<lldb::SBType> partial_matches;

  for (uint32_t i = 0; i < types.GetSize(); ++i) {
    lldb::SBType type = types.GetTypeAtIndex(i);
    llvm::StringRef type_name = type.GetName();

    if (type_name == name_ref) {
      full_match = type;
    } else if (type_name.endswith(name_ref)) {
      partial_matches.push_back(type);
    }
  }

  if (global_scope) {
    // Look only for full matches when looking for a globally qualified type.
    if (full_match.IsValid()) {
      return full_match;
    }
  } else {
    // TODO(b/163308825): We're looking for type, but there may be multiple
    // candidates and which one is correct depends on the currect scope. For now
    // just pick the most "probable" type.

    // Full match is always correct if we're currently in the global scope.
    if (full_match.IsValid()) {
      return full_match;
    }

    // If we have partial matches, pick a "random" one.
    if (partial_matches.size() > 0) {
      return partial_matches.back();
    }
  }

  return lldb::SBType();
}

lldb::SBValue Context::LookupIdentifier(const char* name) const {
  // Internally values don't have global scope qualifier in their names and
  // LLDB doesn't support queries with it too.
  llvm::StringRef name_ref(name);
  bool global_scope = false;

  if (name_ref.startswith("::")) {
    name_ref = name_ref.drop_front(2);
    global_scope = true;
  }

  lldb::SBValue value;

  // If the identifier doesn't refer to the global scope and doesn't have any
  // other scope qualifiers, try looking among the local and instance variables.
  if (!global_scope && name_ref.find("::") == llvm::StringRef::npos) {
    if (!scope_) {
      // Lookup in the current frame.
      lldb::SBFrame frame = ctx_.GetFrame();
      // Try looking for a local variable in current scope.
      if (!value) {
        value = frame.FindVariable(name_ref.data());
      }
      // Try looking for an instance variable (class member).
      if (!value) {
        value =
            frame.FindVariable("this").GetChildMemberWithName(name_ref.data());
      }
    } else {
      // Lookup the variable as a member of the current scope value.
      value = scope_.GetChildMemberWithName(name_ref.data());
    }
  }

  // Try looking for a global or static variable.
  if (!value) {
    // TODO(werat): Implement scope-aware lookup. Relative scopes should be
    // resolved relative to the current scope. I.e. if the current frame is in
    // "ns1::ns2::Foo()", then "ns2::x" should resolve to "ns1::ns2::x".

    // List global variable with the same "basename". There can be many matches
    // from other scopes (namespaces, classes), so we do additional filtering
    // later.
    lldb::SBValueList values = ctx_.GetTarget().FindGlobalVariables(
        name_ref.data(), /*max_matches=*/std::numeric_limits<uint32_t>::max());

    // Find the corrent variable by matching the name. lldb::SBValue::GetName()
    // can return strings like "::globarVar", "ns::i" or "int const ns::foo"
    // depending on the version and the platform.
    for (uint32_t i = 0; i < values.GetSize(); ++i) {
      lldb::SBValue val = values.GetValueAtIndex(i);
      llvm::StringRef val_name = val.GetName();

      if (val_name == name_ref ||
          val_name == llvm::formatv("::{0}", name_ref).str() ||
          val_name.endswith(llvm::formatv(" {0}", name_ref).str())) {
        value = val;
        break;
      }
    }
  }

  return value;
}

std::shared_ptr<Context> Context::Create(std::string expr,
                                         lldb::SBFrame frame) {
  return std::shared_ptr<Context>(new Context(
      std::move(expr), lldb::SBExecutionContext(frame), lldb::SBValue()));
}

std::shared_ptr<Context> Context::Create(std::string expr,
                                         lldb::SBValue scope) {
  // SBValues created via SBTarget::CreateValueFromData don't have SBFrame
  // associated with them. But they still have a process/target, so use that
  // instead.
  return std::shared_ptr<Context>(new Context(
      std::move(expr),
      lldb::SBExecutionContext(
          scope.GetProcess().GetSelectedThread().GetSelectedFrame()),
      scope));
}

}  // namespace lldb_eval
<|endoftext|>