<commit_before>#include "ofApp.h"

using namespace std;

//--------------------------------------------------------------
void ofApp::setup(){
	ofAddListener(node_.unhandledMessageReceived, this, &ofApp::messageReceived);
	node_.setAllowLoopback(true);
	node_.setup(9000);
	node_.request();

	SEND_MAXSIZE =
	RECV_MAXSIZE = osc::UdpSocket::GetUdpBufferSize() - 128;

	gui_.setup();
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
	gui_.begin();

	if(ImGui::Begin("Hosts")) {
		const auto &members = node_.getNodes();
		for(const auto &member : members) {
			const auto &ip = member.first;
			const auto &name = member.second.name;
			auto &box_info = boxes_[ip];
			ImGui::Checkbox(name.c_str(), &box_info.is_open); ImGui::SameLine();
			ImGui::Text("(%s)", ip.c_str());
			if(box_info.is_open) {
				if(ImGui::Begin(name.c_str(), &box_info.is_open)) {
					if(ImGui::CollapsingHeader("Received Files")) {
						for(auto &info : box_info.recv_files) {
							ImGui::PushID(&info);
							ImGui::Text("%s", info.second.name.c_str()); ImGui::SameLine();
							if(info.second.isCompleted()) {
								if(ImGui::Button("save")) {
									auto result = ofSystemSaveDialog(info.second.name, "");
									if(result.bSuccess) {
										ofBufferToFile(result.getPath(), info.second.buffer);
									}
								}
							}
							else if(info.second.is_receiving) {
								if(ImGui::Button("cancel")) {
									info.second.is_receiving = false;
								}
								else {
									ImGui::Text("%llu/%ld", info.second.received_size, info.second.buffer.size());
									sendRequest(ip, info.first, info.second.received_size);
								}
							}
							else {
								if(ImGui::Button("download")) {
									info.second.is_receiving = true;
								}
							}
							ImGui::PopID();
						}
					}
					if(ImGui::CollapsingHeader("Send Files")) {
						for(auto &info : box_info.send_files) {
							ImGui::Text("%s", info.second.file.path().c_str());
						}
					}
					if(ImGui::IsWindowHovered()) {
						if(!drag_files_.empty()) {
							for(auto &path : drag_files_) {
								ofFile file(path);
								if(file.isFile()) {
									notifyFileIsReady(ip, path);
								}
							}
						}
					}
				}
				ImGui::End();
			}
		}
	}
	ImGui::End();
	gui_.end();

	drag_files_.clear();
}

namespace {
	uint32_t crc_table[256];
	bool crc_table_created=false;
	void createCRC32Table() {
		for (uint32_t i = 0; i < 256; i++) {
			uint32_t c = i;
			for (int j = 0; j < 8; j++) {
				c = (c & 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
			}
			crc_table[i] = c;
		}
		crc_table_created = true;
	};
	uint32_t crc32(const char *buf, size_t len) {
		if(!crc_table_created) { createCRC32Table(); }
		uint32_t c = 0xFFFFFFFF;
		for (size_t i = 0; i < len; i++) {
			c = crc_table[(c ^ buf[i]) & 0xFF] ^ (c >> 8);
		}
		return c ^ 0xFFFFFFFF;
	};
	uint32_t crc32(const std::string &str) {
		return crc32(str.c_str(), str.length());
	}
}

void ofApp::notifyFileIsReady(const std::string &ip, const std::string &filepath)
{
	SendFile info(ip, filepath);
	if(!info.file.exists()) {
		return;
	}
	auto it = boxes_.find(ip);
	if(it == end(boxes_)) { return; }
	auto &send_files = it->second.send_files;
	uint32_t hash = crc32(ip+filepath);
	send_files.insert(std::make_pair(hash, info));
	ofxOscMessage msg;
	msg.setAddress("/file/info");
	msg.addInt32Arg(hash);
	msg.addInt64Arg(info.file.getSize());
	msg.addStringArg(ofFilePath::getFileName(filepath));
	node_.sendMessage(ip, msg);
}

void ofApp::sendRequest(const std::string &ip, unsigned int identifier, uint64_t position)
{
	ofxOscMessage msg;
	msg.setAddress("/file/request");
	msg.addInt32Arg(identifier);
	msg.addInt64Arg(position);
	msg.addInt64Arg(RECV_MAXSIZE);
	node_.sendMessage(ip, msg);
}

void ofApp::messageReceived(ofxOscMessage &msg)
{
	const std::string &address = msg.getAddress();
	if(address == "/file/info") {
		const std::string &ip = msg.getRemoteIp();
		auto &box = boxes_[ip];
		RecvFile file(msg.getArgAsString(2), msg.getArgAsInt64(1));
		auto identifier = msg.getArgAsInt32(0);
		box.recv_files.insert(std::make_pair(identifier, file));
	}
	else if(address == "/file/request"){
		std::string ip = msg.getRemoteIp();
		auto it = boxes_.find(ip);
		if(it == end(boxes_)) { return; }
		auto &send_files = it->second.send_files;
		uint32_t identifier = msg.getArgAsInt32(0);
		auto it2 = send_files.find(identifier);
		if(it2 == end(send_files)) {
			return;
		}
		auto &info = it2->second;
		uint64_t position = msg.getArgAsInt64(1);
		uint64_t maxsize = min<uint64_t>(msg.getArgAsInt64(2), SEND_MAXSIZE);
		uint64_t size = min<uint64_t>(maxsize, info.file.getSize()-position);
		ofBuffer buffer;
		info.file.seekg(position, ios_base::beg);
		buffer.allocate(size);
		info.file.read(buffer.getData(), buffer.size());
		ofxOscMessage msg;
		msg.setAddress("/file/data");
		msg.addInt32Arg(identifier);
		msg.addInt64Arg(position);
		msg.addBlobArg(buffer);
		node_.sendMessage(info.destination, msg);
	}
	else if(address == "/file/data") {
		std::string ip = msg.getRemoteIp();
		uint32_t identifier = msg.getArgAsInt32(0);
		uint64_t position = msg.getArgAsInt64(1);
		const ofBuffer &data = msg.getArgAsBlob(2);
		auto it = boxes_.find(ip);
		if(it == end(boxes_)) { return; }
		auto it2 = it->second.recv_files.find(identifier);
		if(it2 == end(it->second.recv_files)) { return; }
		auto &info = it2->second;
		if(!info.is_receiving) { return; }
		if(info.isCompleted()) { return; }
		auto *ptr = info.buffer.getData();
		auto size = data.size();
		assert(position+size <= info.buffer.size());
		memcpy(ptr+position, data.getData(), size);
		info.received_size = position+size;
	}
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
	drag_files_ = dragInfo.files;
}
<commit_msg>enable to identify hosts of same name<commit_after>#include "ofApp.h"

using namespace std;

//--------------------------------------------------------------
void ofApp::setup(){
	ofAddListener(node_.unhandledMessageReceived, this, &ofApp::messageReceived);
	node_.setAllowLoopback(true);
	node_.setup(9000);
	node_.request();

	SEND_MAXSIZE =
	RECV_MAXSIZE = osc::UdpSocket::GetUdpBufferSize() - 128;

	gui_.setup();
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
	gui_.begin();

	if(ImGui::Begin("Hosts")) {
		const auto &members = node_.getNodes();
		for(const auto &member : members) {
			const auto &ip = member.first;
			const auto &name = member.second.name;
			auto &box_info = boxes_[ip];
			ImGui::PushID(ip.c_str());
			ImGui::Checkbox(name.c_str(), &box_info.is_open); ImGui::SameLine();
			ImGui::Text("(%s)", ip.c_str());
			if(box_info.is_open) {
				if(ImGui::Begin(name.c_str(), &box_info.is_open)) {
					if(ImGui::CollapsingHeader("Received Files")) {
						for(auto &info : box_info.recv_files) {
							ImGui::PushID(&info);
							ImGui::Text("%s", info.second.name.c_str()); ImGui::SameLine();
							if(info.second.isCompleted()) {
								if(ImGui::Button("save")) {
									auto result = ofSystemSaveDialog(info.second.name, "");
									if(result.bSuccess) {
										ofBufferToFile(result.getPath(), info.second.buffer);
									}
								}
							}
							else if(info.second.is_receiving) {
								if(ImGui::Button("cancel")) {
									info.second.is_receiving = false;
								}
								else {
									ImGui::Text("%llu/%ld", info.second.received_size, info.second.buffer.size());
									sendRequest(ip, info.first, info.second.received_size);
								}
							}
							else {
								if(ImGui::Button("download")) {
									info.second.is_receiving = true;
								}
							}
							ImGui::PopID();
						}
					}
					if(ImGui::CollapsingHeader("Send Files")) {
						for(auto &info : box_info.send_files) {
							ImGui::Text("%s", info.second.file.path().c_str());
						}
					}
					if(ImGui::IsWindowHovered()) {
						if(!drag_files_.empty()) {
							for(auto &path : drag_files_) {
								ofFile file(path);
								if(file.isFile()) {
									notifyFileIsReady(ip, path);
								}
							}
						}
					}
				}
				ImGui::End();
			}
			ImGui::PopID();
		}
	}
	ImGui::End();
	gui_.end();

	drag_files_.clear();
}

namespace {
	uint32_t crc_table[256];
	bool crc_table_created=false;
	void createCRC32Table() {
		for (uint32_t i = 0; i < 256; i++) {
			uint32_t c = i;
			for (int j = 0; j < 8; j++) {
				c = (c & 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
			}
			crc_table[i] = c;
		}
		crc_table_created = true;
	};
	uint32_t crc32(const char *buf, size_t len) {
		if(!crc_table_created) { createCRC32Table(); }
		uint32_t c = 0xFFFFFFFF;
		for (size_t i = 0; i < len; i++) {
			c = crc_table[(c ^ buf[i]) & 0xFF] ^ (c >> 8);
		}
		return c ^ 0xFFFFFFFF;
	};
	uint32_t crc32(const std::string &str) {
		return crc32(str.c_str(), str.length());
	}
}

void ofApp::notifyFileIsReady(const std::string &ip, const std::string &filepath)
{
	SendFile info(ip, filepath);
	if(!info.file.exists()) {
		return;
	}
	auto it = boxes_.find(ip);
	if(it == end(boxes_)) { return; }
	auto &send_files = it->second.send_files;
	uint32_t hash = crc32(ip+filepath);
	send_files.insert(std::make_pair(hash, info));
	ofxOscMessage msg;
	msg.setAddress("/file/info");
	msg.addInt32Arg(hash);
	msg.addInt64Arg(info.file.getSize());
	msg.addStringArg(ofFilePath::getFileName(filepath));
	node_.sendMessage(ip, msg);
}

void ofApp::sendRequest(const std::string &ip, unsigned int identifier, uint64_t position)
{
	ofxOscMessage msg;
	msg.setAddress("/file/request");
	msg.addInt32Arg(identifier);
	msg.addInt64Arg(position);
	msg.addInt64Arg(RECV_MAXSIZE);
	node_.sendMessage(ip, msg);
}

void ofApp::messageReceived(ofxOscMessage &msg)
{
	const std::string &address = msg.getAddress();
	if(address == "/file/info") {
		const std::string &ip = msg.getRemoteIp();
		auto &box = boxes_[ip];
		RecvFile file(msg.getArgAsString(2), msg.getArgAsInt64(1));
		auto identifier = msg.getArgAsInt32(0);
		box.recv_files.insert(std::make_pair(identifier, file));
	}
	else if(address == "/file/request"){
		std::string ip = msg.getRemoteIp();
		auto it = boxes_.find(ip);
		if(it == end(boxes_)) { return; }
		auto &send_files = it->second.send_files;
		uint32_t identifier = msg.getArgAsInt32(0);
		auto it2 = send_files.find(identifier);
		if(it2 == end(send_files)) {
			return;
		}
		auto &info = it2->second;
		uint64_t position = msg.getArgAsInt64(1);
		uint64_t maxsize = min<uint64_t>(msg.getArgAsInt64(2), SEND_MAXSIZE);
		uint64_t size = min<uint64_t>(maxsize, info.file.getSize()-position);
		ofBuffer buffer;
		info.file.seekg(position, ios_base::beg);
		buffer.allocate(size);
		info.file.read(buffer.getData(), buffer.size());
		ofxOscMessage msg;
		msg.setAddress("/file/data");
		msg.addInt32Arg(identifier);
		msg.addInt64Arg(position);
		msg.addBlobArg(buffer);
		node_.sendMessage(info.destination, msg);
	}
	else if(address == "/file/data") {
		std::string ip = msg.getRemoteIp();
		uint32_t identifier = msg.getArgAsInt32(0);
		uint64_t position = msg.getArgAsInt64(1);
		const ofBuffer &data = msg.getArgAsBlob(2);
		auto it = boxes_.find(ip);
		if(it == end(boxes_)) { return; }
		auto it2 = it->second.recv_files.find(identifier);
		if(it2 == end(it->second.recv_files)) { return; }
		auto &info = it2->second;
		if(!info.is_receiving) { return; }
		if(info.isCompleted()) { return; }
		auto *ptr = info.buffer.getData();
		auto size = data.size();
		assert(position+size <= info.buffer.size());
		memcpy(ptr+position, data.getData(), size);
		info.received_size = position+size;
	}
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
	drag_files_ = dragInfo.files;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
// A brpc based redis-server. Currently just implement set and
// get, but it's sufficient that you can get the idea how to
// implement brpc::RedisCommandHandler.

#include <brpc/server.h>
#include <brpc/redis.h>
#include <butil/crc32c.h>
#include <butil/strings/string_split.h>
#include <gflags/gflags.h>
#include <unordered_map>

class RedisServiceImpl : public brpc::RedisService {
public:
    bool Set(const std::string& key, const std::string& value) {
        int slot = butil::crc32c::Value(key.c_str(), key.size()) % kHashSlotNum;
        _mutex[slot].lock();
        _map[slot][key] = value;
        _mutex[slot].unlock();
        return true;
    }

    bool Get(const std::string& key, std::string* value) {
        int slot = butil::crc32c::Value(key.c_str(), key.size()) % kHashSlotNum;
        _mutex[slot].lock();
        auto it = _map[slot].find(key);
        if (it == _map[slot].end()) {
            _mutex[slot].unlock();
            return false;
        }
        *value = it->second;
        _mutex[slot].unlock();
        return true;
    }

private:
    const static int kHashSlotNum = 32;
    std::unordered_map<std::string, std::string> _map[kHashSlotNum];
    butil::Mutex _mutex[kHashSlotNum];
};

class GetCommandHandler : public brpc::RedisCommandHandler {
public:
    GetCommandHandler(RedisServiceImpl* rsimpl)
        : _rsimpl(rsimpl) {}

    brpc::RedisCommandHandler::Result Run(const std::vector<std::string>& commands,
                                          brpc::RedisReply* output,
                                          bool is_last) override {
        if ((int)commands.size() <= 1) {
            output->SetError("ERR wrong number of arguments for 'get' command");
            return brpc::RedisCommandHandler::OK;
        }
        const std::string& key = commands[1];
        std::string value;
        if (_rsimpl->Get(key, &value)) {
            output->SetString(value);
        } else {
            output->SetNilString();
        }
        return brpc::RedisCommandHandler::OK;
	}

private:
   	RedisServiceImpl* _rsimpl;
};

class SetCommandHandler : public brpc::RedisCommandHandler {
public:
    SetCommandHandler(RedisServiceImpl* rsimpl)
        : _rsimpl(rsimpl) {}

    brpc::RedisCommandHandler::Result Run(const std::vector<std::string>& commands,
                                          brpc::RedisReply* output,
                                          bool is_last) override {
        if ((int)commands.size() <= 2) {
            output->SetError("ERR wrong number of arguments for 'set' command");
            return brpc::RedisCommandHandler::OK;
        }
        const std::string& key = commands[1];
        const std::string& value = commands[2];
        _rsimpl->Set(key, value);
        output->SetStatus("OK");
        return brpc::RedisCommandHandler::OK;
	}

private:
   	RedisServiceImpl* _rsimpl;
};

int main(int argc, char* argv[]) {
    google::ParseCommandLineFlags(&argc, &argv, true);
    RedisServiceImpl* rsimpl = new RedisServiceImpl;
    rsimpl->AddCommandHandler("get", new GetCommandHandler(rsimpl));
    rsimpl->AddCommandHandler("set", new SetCommandHandler(rsimpl));

    brpc::Server server;
    brpc::ServerOptions server_options;
    server_options.redis_service = rsimpl;
    if (server.Start(6379, &server_options) != 0) {
        LOG(ERROR) << "Fail to start server";
        return -1;
    }
    server.RunUntilAskedToQuit();
    return 0;
}
<commit_msg>redis_server_protocol: update redis-server<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
// A brpc based redis-server. Currently just implement set and
// get, but it's sufficient that you can get the idea how to
// implement brpc::RedisCommandHandler.

#include <brpc/server.h>
#include <brpc/redis.h>
#include <butil/crc32c.h>
#include <butil/strings/string_split.h>
#include <gflags/gflags.h>
#include <unordered_map>

class RedisServiceImpl : public brpc::RedisService {
public:
    bool Set(const std::string& key, const std::string& value) {
        int slot = butil::crc32c::Value(key.c_str(), key.size()) % kHashSlotNum;
        _mutex[slot].lock();
        _map[slot][key] = value;
        _mutex[slot].unlock();
        return true;
    }

    bool Get(const std::string& key, std::string* value) {
        int slot = butil::crc32c::Value(key.c_str(), key.size()) % kHashSlotNum;
        _mutex[slot].lock();
        auto it = _map[slot].find(key);
        if (it == _map[slot].end()) {
            _mutex[slot].unlock();
            return false;
        }
        *value = it->second;
        _mutex[slot].unlock();
        return true;
    }

private:
    const static int kHashSlotNum = 32;
    std::unordered_map<std::string, std::string> _map[kHashSlotNum];
    butil::Mutex _mutex[kHashSlotNum];
};

class GetCommandHandler : public brpc::RedisCommandHandler {
public:
    GetCommandHandler(RedisServiceImpl* rsimpl)
        : _rsimpl(rsimpl) {}

    brpc::RedisCommandHandler::Result Run(int size, const char* args[],
                                          brpc::RedisReply* output,
                                          bool is_last) override {
        if (size <= 1) {
            output->SetError("ERR wrong number of arguments for 'get' command");
            return brpc::RedisCommandHandler::OK;
        }
        const std::string key(args[1]);
        std::string value;
        if (_rsimpl->Get(key, &value)) {
            output->SetString(value);
        } else {
            output->SetNullString();
        }
        return brpc::RedisCommandHandler::OK;
	}

private:
   	RedisServiceImpl* _rsimpl;
};

class SetCommandHandler : public brpc::RedisCommandHandler {
public:
    SetCommandHandler(RedisServiceImpl* rsimpl)
        : _rsimpl(rsimpl) {}

    brpc::RedisCommandHandler::Result Run(int size, const char* args[],
                                          brpc::RedisReply* output,
                                          bool is_last) override {
        if (size <= 2) {
            output->SetError("ERR wrong number of arguments for 'set' command");
            return brpc::RedisCommandHandler::OK;
        }
        const std::string key(args[1]);
        const std::string value(args[2]);
        _rsimpl->Set(key, value);
        output->SetStatus("OK");
        return brpc::RedisCommandHandler::OK;
	}

private:
   	RedisServiceImpl* _rsimpl;
};

int main(int argc, char* argv[]) {
    google::ParseCommandLineFlags(&argc, &argv, true);
    RedisServiceImpl* rsimpl = new RedisServiceImpl;
    rsimpl->AddCommandHandler("get", new GetCommandHandler(rsimpl));
    rsimpl->AddCommandHandler("set", new SetCommandHandler(rsimpl));

    brpc::Server server;
    brpc::ServerOptions server_options;
    server_options.redis_service = rsimpl;
    if (server.Start(6379, &server_options) != 0) {
        LOG(ERROR) << "Fail to start server";
        return -1;
    }
    server.RunUntilAskedToQuit();
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>porting to gcc8<commit_after><|endoftext|>


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

#include <dirent.h>
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include "gumbo.h"
#include "macros.h"

static const unsigned int kNumReps = 100;

int main(int argc, char** UNUSED(argv)) {
  if (argc != 1) {
    std::cout << "Usage: benchmarks\n";
    exit(EXIT_FAILURE);
  }

  DIR* dir;
  struct dirent* file;

  if ((dir = opendir("test/benchmark")) == NULL) {
    std::cout <<
      "Couldn't find 'benchmarks' directory. "
      "Run from root of distribution.\n"
    ;
    exit(EXIT_FAILURE);
  }

  while ((file = readdir(dir)) != NULL) {
    std::string filename(file->d_name);
    if (filename.length() > 5 && filename.compare(filename.length() - 5, 5, ".html") == 0) {
      std::string full_filename = "test/benchmark/" + filename;
      std::ifstream in(full_filename.c_str(), std::ios::in | std::ios::binary);
      if (!in) {
        std::cout << "File " << full_filename << " couldn't be read!\n";
        exit(EXIT_FAILURE);
      }

      std::string contents;
      in.seekg(0, std::ios::end);
      contents.resize(in.tellg());
      in.seekg(0, std::ios::beg);
      in.read(&contents[0], contents.size());
      in.close();

      const char *const str = contents.c_str();
      const size_t len = contents.length();
      GumboOptions options = kGumboDefaultOptions;
      options.max_errors = 0;

      const clock_t start_time = clock();
      for (unsigned int i = kNumReps; i != 0; i--) {
        GumboOutput* output = gumbo_parse_with_options(&options, str, len);
        gumbo_destroy_output(output);
      }
      const clock_t end_time = clock();

      std::cout
        << filename
        << ": "
        << (1000000 * (end_time - start_time) / (kNumReps * CLOCKS_PER_SEC))
        << " microseconds.\n";
    }
  }
  closedir(dir);
}
<commit_msg>Use "UNUSED_ARG" macro instead of "UNUSED" in benchmark runner<commit_after>// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: jdtang@google.com (Jonathan Tang)
//

#include <dirent.h>
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include "gumbo.h"
#include "macros.h"

static const unsigned int kNumReps = 100;

int main(int argc, char** UNUSED_ARG(argv)) {
  if (argc != 1) {
    std::cout << "Usage: benchmarks\n";
    exit(EXIT_FAILURE);
  }

  DIR* dir;
  struct dirent* file;

  if ((dir = opendir("test/benchmark")) == NULL) {
    std::cout <<
      "Couldn't find 'benchmarks' directory. "
      "Run from root of distribution.\n"
    ;
    exit(EXIT_FAILURE);
  }

  while ((file = readdir(dir)) != NULL) {
    std::string filename(file->d_name);
    if (filename.length() > 5 && filename.compare(filename.length() - 5, 5, ".html") == 0) {
      std::string full_filename = "test/benchmark/" + filename;
      std::ifstream in(full_filename.c_str(), std::ios::in | std::ios::binary);
      if (!in) {
        std::cout << "File " << full_filename << " couldn't be read!\n";
        exit(EXIT_FAILURE);
      }

      std::string contents;
      in.seekg(0, std::ios::end);
      contents.resize(in.tellg());
      in.seekg(0, std::ios::beg);
      in.read(&contents[0], contents.size());
      in.close();

      const char *const str = contents.c_str();
      const size_t len = contents.length();
      GumboOptions options = kGumboDefaultOptions;
      options.max_errors = 0;

      const clock_t start_time = clock();
      for (unsigned int i = kNumReps; i != 0; i--) {
        GumboOutput* output = gumbo_parse_with_options(&options, str, len);
        gumbo_destroy_output(output);
      }
      const clock_t end_time = clock();

      std::cout
        << filename
        << ": "
        << (1000000 * (end_time - start_time) / (kNumReps * CLOCKS_PER_SEC))
        << " microseconds.\n";
    }
  }
  closedir(dir);
}
<|endoftext|>


<commit_before><commit_msg>Fix bug in SixTestWrapper when printing the last 20 lines<commit_after><|endoftext|>


<commit_before>#include <silicium/tcp_acceptor.hpp>
#include <silicium/coroutine.hpp>
#include <silicium/total_consumer.hpp>
#include <silicium/flatten.hpp>
#include <silicium/socket_observable.hpp>
#include <silicium/sending_observable.hpp>
#include <silicium/received_from_socket_source.hpp>
#include <silicium/transform_if_initialized.hpp>
#include <silicium/observable_source.hpp>
#include <silicium/for_each.hpp>
#include <silicium/optional.hpp>
#include <silicium/file_source.hpp>
#include <silicium/http/http.hpp>
#include <silicium/to_unique.hpp>
#include <silicium/thread.hpp>
#include <silicium/linux/open.hpp>
#include <silicium/read_file.hpp>
#include <fileserver/sha256.hpp>
#include <fileserver/hexadecimal.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
#include <boost/container/string.hpp>
#include <boost/unordered_map.hpp>
#include <boost/filesystem/operations.hpp>

namespace fileserver
{
	using response_part = Si::incoming_bytes;

	boost::iterator_range<char const *> to_range(response_part part)
	{
		return boost::make_iterator_range(part.begin, part.end);
	}

	using digest = boost::container::basic_string<byte>;

	struct content_request
	{
		digest requested_file;
	};

	Si::optional<content_request> parse_request_path(std::string const &path)
	{
		if (path.empty())
		{
			return Si::none;
		}
		auto digest_begin = path.begin();
		if (*digest_begin == '/')
		{
			++digest_begin;
		}
		content_request request;
		auto const rest = decode_ascii_hex_bytes(digest_begin, path.end(), std::back_inserter(request.requested_file));
		if (rest.first != path.end())
		{
			return Si::none;
		}
		return std::move(request);
	}

	struct file_system_location
	{
		//shared_ptr for noexcept-movability and copyability
		std::shared_ptr<boost::filesystem::path> where;
	};

	using location = Si::fast_variant<file_system_location>;

	struct file_repository
	{
		boost::unordered_map<digest, location> available;

		location const *find_location(digest const &key) const
		{
			auto i = available.find(key);
			return (i == end(available)) ? nullptr : &i->second;
		}
	};

	template <class ReceiveObservable, class MakeSender, class Shutdown>
	void serve_client(
		Si::yield_context<Si::nothing> &yield,
		ReceiveObservable &receive,
		MakeSender const &make_sender,
		Shutdown const &shutdown,
		file_repository const &repository)
	{
		auto receive_sync = Si::make_observable_source(Si::ref(receive), yield);
		Si::received_from_socket_source receive_bytes(receive_sync);
		auto header = Si::http::parse_header(receive_bytes);
		if (!header)
		{
			return;
		}

		auto const request = parse_request_path(header->path);
		if (!request)
		{
			//TODO: 404 or sth
			return;
		}

		location const * const found_file = repository.find_location(request->requested_file);
		if (!found_file)
		{
			//TODO: 404
			return;
		}

		std::vector<char> const body = Si::read_file(Si::visit<boost::filesystem::path>(*found_file, [](file_system_location const &location)
		{
			return *location.where;
		}));

		auto const try_send = [&yield, &make_sender](std::vector<char> const &data)
		{
			auto sender = make_sender(Si::incoming_bytes(data.data(), data.data() + data.size()));
			auto error = yield.get_one(sender);
			assert(error);
			return !*error;
		};

		{
			Si::http::response_header response;
			response.http_version = "HTTP/1.0";
			response.status_text = "OK";
			response.status = 200;
			response.arguments["Content-Length"] = boost::lexical_cast<std::string>(body.size());
			response.arguments["Connection"] = "close";

			std::vector<char> response_header;
			auto header_sink = Si::make_container_sink(response_header);
			Si::http::write_header(header_sink, response);

			if (!try_send(response_header))
			{
				return;
			}
		}

		if (!try_send(body))
		{
			return;
		}

		shutdown();

		while (Si::get(receive_bytes))
		{
		}
	}

	//TODO: use unique_observable
	using session_handle = Si::shared_observable<Si::nothing>;

	namespace detail
	{
		void list_files_recursively(Si::yield_context_2<boost::filesystem::path> &yield, boost::filesystem::path const &root)
		{
			for (boost::filesystem::directory_iterator i(root); i != boost::filesystem::directory_iterator(); ++i)
			{
				switch (i->status().type())
				{
				case boost::filesystem::file_type::regular_file:
					yield.push_result(i->path());
					break;

				case boost::filesystem::file_type::directory_file:
					list_files_recursively(yield, i->path());
					break;

				default:
					//ignore
					break;
				}
			}
		}
	}

	Si::unique_observable<boost::filesystem::path> list_files_recursively(boost::filesystem::path const &root)
	{
		return Si::erase_unique(Si::make_thread<boost::filesystem::path, Si::boost_threading>([root](Si::yield_context_2<boost::filesystem::path> &yield)
		{
			return detail::list_files_recursively(yield, root);
		}));
	}

	namespace detail
	{
		boost::optional<std::pair<digest, location>> hash_file(boost::filesystem::path const &file)
		{
			auto opened = Si::linux::open_reading(file);
			std::array<char, 8192> buffer;
			auto content = Si::make_file_source(opened.get().handle, boost::make_iterator_range(buffer.data(), buffer.data() + buffer.size()));
			auto hashable_content = Si::make_transforming_source<boost::iterator_range<char const *>>(
				content,
				[&buffer](Si::file_read_result piece)
			{
				return Si::visit<boost::iterator_range<char const *>>(
					piece,
					[&buffer](std::size_t length) -> boost::iterator_range<char const *>
					{
						assert(length <= buffer.size());
						return boost::make_iterator_range(buffer.data(), buffer.data() + length);
					},
					[](boost::system::error_code error) -> boost::iterator_range<char const *>
					{
						boost::throw_exception(boost::system::system_error(error));
						SILICIUM_UNREACHABLE();
					});
			});
			auto sha256_digest = fileserver::sha256(hashable_content);
			digest resulting_digest;
			resulting_digest.assign(sha256_digest.bytes.begin(), sha256_digest.bytes.end());
			return std::make_pair(resulting_digest, location{file_system_location{std::make_shared<boost::filesystem::path>(file)}});
		}
	}

	template <class PathObservable>
	Si::unique_observable<std::pair<digest, location>> get_locations_by_hash(PathObservable &&paths)
	{
		return Si::erase_unique(Si::transform_if_initialized<std::pair<digest, location>>(std::forward<PathObservable>(paths), detail::hash_file));
	}
}

int main()
{
	using namespace fileserver;

	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	Si::tcp_acceptor clients(acceptor);

	file_repository files;

	auto accept_all = Si::make_coroutine<session_handle>([&clients, &files](Si::yield_context<session_handle> &yield)
	{
		for (;;)
		{
			auto accepted = yield.get_one(clients);
			if (!accepted)
			{
				return;
			}
			Si::visit<void>(
				*accepted,
				[&yield, &files](std::shared_ptr<boost::asio::ip::tcp::socket> socket)
				{
					auto prepare_socket = [socket, &files](Si::yield_context<Si::nothing> &yield)
					{
						std::array<char, 1024> receive_buffer;
						Si::socket_observable received(*socket, boost::make_iterator_range(receive_buffer.data(), receive_buffer.data() + receive_buffer.size()));
						auto make_sender = [socket](Si::incoming_bytes sent)
						{
							return Si::sending_observable(*socket, to_range(sent));
						};
						auto shutdown = [socket]()
						{
							socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
						};
						serve_client(yield, received, make_sender, shutdown, files);
					};
					yield(Si::erase_shared(Si::make_coroutine<Si::nothing>(prepare_socket)));
				},
				[](boost::system::error_code)
				{
					throw std::logic_error("to do");
				}
			);
		}
	});
	auto all_sessions_finished = Si::flatten<boost::interprocess::null_mutex>(std::move(accept_all));
	auto done = Si::make_total_consumer(std::move(all_sessions_finished));
	done.start();

	auto listed = Si::for_each(get_locations_by_hash(list_files_recursively(boost::filesystem::current_path())), [&files, &io](std::pair<digest, location> const &entry)
	{
		auto &out = std::cerr;
		encode_ascii_hex_digits(entry.first.begin(), entry.first.end(), std::ostreambuf_iterator<char>(out));
		out
			<< " "
			<< Si::visit<std::string>(entry.second, [](file_system_location const &location)
			{
				return location.where->string();
			})
			<< '\n';

		io.post([entry, &files]()
		{
			files.available.insert(entry);
		});
	});
	listed.start();

	io.run();
}
<commit_msg>when hashing a file, save the file size for later<commit_after>#include <silicium/tcp_acceptor.hpp>
#include <silicium/coroutine.hpp>
#include <silicium/total_consumer.hpp>
#include <silicium/flatten.hpp>
#include <silicium/socket_observable.hpp>
#include <silicium/sending_observable.hpp>
#include <silicium/received_from_socket_source.hpp>
#include <silicium/transform_if_initialized.hpp>
#include <silicium/observable_source.hpp>
#include <silicium/for_each.hpp>
#include <silicium/optional.hpp>
#include <silicium/file_source.hpp>
#include <silicium/http/http.hpp>
#include <silicium/to_unique.hpp>
#include <silicium/thread.hpp>
#include <silicium/linux/open.hpp>
#include <silicium/read_file.hpp>
#include <fileserver/sha256.hpp>
#include <fileserver/hexadecimal.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
#include <boost/container/string.hpp>
#include <boost/unordered_map.hpp>
#include <boost/filesystem/operations.hpp>
#include <sys/stat.h>

namespace fileserver
{
	using response_part = Si::incoming_bytes;

	boost::iterator_range<char const *> to_range(response_part part)
	{
		return boost::make_iterator_range(part.begin, part.end);
	}

	using digest = boost::container::basic_string<byte>;

	struct content_request
	{
		digest requested_file;
	};

	Si::optional<content_request> parse_request_path(std::string const &path)
	{
		if (path.empty())
		{
			return Si::none;
		}
		auto digest_begin = path.begin();
		if (*digest_begin == '/')
		{
			++digest_begin;
		}
		content_request request;
		auto const rest = decode_ascii_hex_bytes(digest_begin, path.end(), std::back_inserter(request.requested_file));
		if (rest.first != path.end())
		{
			return Si::none;
		}
		return std::move(request);
	}

	struct file_system_location
	{
		//shared_ptr for noexcept-movability and copyability
		std::shared_ptr<boost::filesystem::path> where;
		boost::uint64_t size;
	};

	using location = Si::fast_variant<file_system_location>;

	struct file_repository
	{
		boost::unordered_map<digest, location> available;

		location const *find_location(digest const &key) const
		{
			auto i = available.find(key);
			return (i == end(available)) ? nullptr : &i->second;
		}
	};

	template <class ReceiveObservable, class MakeSender, class Shutdown>
	void serve_client(
		Si::yield_context<Si::nothing> &yield,
		ReceiveObservable &receive,
		MakeSender const &make_sender,
		Shutdown const &shutdown,
		file_repository const &repository)
	{
		auto receive_sync = Si::make_observable_source(Si::ref(receive), yield);
		Si::received_from_socket_source receive_bytes(receive_sync);
		auto header = Si::http::parse_header(receive_bytes);
		if (!header)
		{
			return;
		}

		auto const request = parse_request_path(header->path);
		if (!request)
		{
			//TODO: 404 or sth
			return;
		}

		location const * const found_file = repository.find_location(request->requested_file);
		if (!found_file)
		{
			//TODO: 404
			return;
		}

		std::vector<char> const body = Si::read_file(Si::visit<boost::filesystem::path>(*found_file, [](file_system_location const &location)
		{
			return *location.where;
		}));

		auto const try_send = [&yield, &make_sender](std::vector<char> const &data)
		{
			auto sender = make_sender(Si::incoming_bytes(data.data(), data.data() + data.size()));
			auto error = yield.get_one(sender);
			assert(error);
			return !*error;
		};

		{
			Si::http::response_header response;
			response.http_version = "HTTP/1.0";
			response.status_text = "OK";
			response.status = 200;
			response.arguments["Content-Length"] = boost::lexical_cast<std::string>(body.size());
			response.arguments["Connection"] = "close";

			std::vector<char> response_header;
			auto header_sink = Si::make_container_sink(response_header);
			Si::http::write_header(header_sink, response);

			if (!try_send(response_header))
			{
				return;
			}
		}

		if (!try_send(body))
		{
			return;
		}

		shutdown();

		while (Si::get(receive_bytes))
		{
		}
	}

	//TODO: use unique_observable
	using session_handle = Si::shared_observable<Si::nothing>;

	namespace detail
	{
		void list_files_recursively(Si::yield_context_2<boost::filesystem::path> &yield, boost::filesystem::path const &root)
		{
			for (boost::filesystem::directory_iterator i(root); i != boost::filesystem::directory_iterator(); ++i)
			{
				switch (i->status().type())
				{
				case boost::filesystem::file_type::regular_file:
					yield.push_result(i->path());
					break;

				case boost::filesystem::file_type::directory_file:
					list_files_recursively(yield, i->path());
					break;

				default:
					//ignore
					break;
				}
			}
		}
	}

	Si::unique_observable<boost::filesystem::path> list_files_recursively(boost::filesystem::path const &root)
	{
		return Si::erase_unique(Si::make_thread<boost::filesystem::path, Si::boost_threading>([root](Si::yield_context_2<boost::filesystem::path> &yield)
		{
			return detail::list_files_recursively(yield, root);
		}));
	}

	namespace detail
	{
		Si::error_or<boost::uint64_t> file_size(int file)
		{
			struct stat buffer;
			if (fstat(file, &buffer) < 0)
			{
				return boost::system::error_code(errno, boost::system::system_category());
			}
			return static_cast<boost::uint64_t>(buffer.st_size);
		}

		boost::optional<std::pair<digest, location>> hash_file(boost::filesystem::path const &file)
		{
			auto opened = Si::linux::open_reading(file).get();
			auto const size = file_size(opened.handle).get();
			std::array<char, 8192> buffer;
			auto content = Si::make_file_source(opened.handle, boost::make_iterator_range(buffer.data(), buffer.data() + buffer.size()));
			auto hashable_content = Si::make_transforming_source<boost::iterator_range<char const *>>(
				content,
				[&buffer](Si::file_read_result piece)
			{
				return Si::visit<boost::iterator_range<char const *>>(
					piece,
					[&buffer](std::size_t length) -> boost::iterator_range<char const *>
					{
						assert(length <= buffer.size());
						return boost::make_iterator_range(buffer.data(), buffer.data() + length);
					},
					[](boost::system::error_code error) -> boost::iterator_range<char const *>
					{
						boost::throw_exception(boost::system::system_error(error));
						SILICIUM_UNREACHABLE();
					});
			});
			auto sha256_digest = fileserver::sha256(hashable_content);
			digest resulting_digest;
			resulting_digest.assign(sha256_digest.bytes.begin(), sha256_digest.bytes.end());
			return std::make_pair(resulting_digest, location{file_system_location{std::make_shared<boost::filesystem::path>(file), size}});
		}
	}

	template <class PathObservable>
	Si::unique_observable<std::pair<digest, location>> get_locations_by_hash(PathObservable &&paths)
	{
		return Si::erase_unique(Si::transform_if_initialized<std::pair<digest, location>>(std::forward<PathObservable>(paths), detail::hash_file));
	}
}

int main()
{
	using namespace fileserver;

	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	Si::tcp_acceptor clients(acceptor);

	file_repository files;

	auto accept_all = Si::make_coroutine<session_handle>([&clients, &files](Si::yield_context<session_handle> &yield)
	{
		for (;;)
		{
			auto accepted = yield.get_one(clients);
			if (!accepted)
			{
				return;
			}
			Si::visit<void>(
				*accepted,
				[&yield, &files](std::shared_ptr<boost::asio::ip::tcp::socket> socket)
				{
					auto prepare_socket = [socket, &files](Si::yield_context<Si::nothing> &yield)
					{
						std::array<char, 1024> receive_buffer;
						Si::socket_observable received(*socket, boost::make_iterator_range(receive_buffer.data(), receive_buffer.data() + receive_buffer.size()));
						auto make_sender = [socket](Si::incoming_bytes sent)
						{
							return Si::sending_observable(*socket, to_range(sent));
						};
						auto shutdown = [socket]()
						{
							socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
						};
						serve_client(yield, received, make_sender, shutdown, files);
					};
					yield(Si::erase_shared(Si::make_coroutine<Si::nothing>(prepare_socket)));
				},
				[](boost::system::error_code)
				{
					throw std::logic_error("to do");
				}
			);
		}
	});
	auto all_sessions_finished = Si::flatten<boost::interprocess::null_mutex>(std::move(accept_all));
	auto done = Si::make_total_consumer(std::move(all_sessions_finished));
	done.start();

	auto listed = Si::for_each(get_locations_by_hash(list_files_recursively(boost::filesystem::current_path())), [&files, &io](std::pair<digest, location> const &entry)
	{
		auto &out = std::cerr;
		encode_ascii_hex_digits(entry.first.begin(), entry.first.end(), std::ostreambuf_iterator<char>(out));
		out
			<< " "
			<< Si::visit<std::string>(entry.second, [](file_system_location const &location)
			{
				return location.where->string();
			})
			<< '\n';

		io.post([entry, &files]()
		{
			files.available.insert(entry);
		});
	});
	listed.start();

	io.run();
}
<|endoftext|>


<commit_before>
#include "CLoadState.h"

#include "CMainState.h"
#include "CMainMenuState.h"
#include "CSite.h"

#include "CTerrainNodeManager.h"
#include "CVolumeNodeManager.h"
#include "CGlyphNodeManager.h"
#include "CPlaneGridSceneObject.h"

#include <ionGUI/CGUIEventManager.h>

void CLoadStateEventHandler::OnFinish(Gwen::Controls::Base * Control)
{
	CLoadState::Get().OnFinish();
}

void CLoadState::AddLabel(std::wstring const & Label, Gwen::Color const & Color)
{
	Gwen::Controls::Label * MediumLabel = new Gwen::Controls::Label(Canvas);
	MediumLabel->SetFont(GUIManager->GetMediumFont());
	MediumLabel->SetText(Label);
	MediumLabel->SetBounds(20 + Indent, LabelHeight, 1024, 300);
	MediumLabel->SetTextColor(Color);

	GUIManager->Draw(true);
	Context->Window->SwapBuffers();

	LabelHeight += 40;
}

CLoadState::CLoadState()
	: LabelHeight(0), Indent(0), GetConfirmation(false)
{
	LabelHeight = 70;
	Indent = 0;
}

void CLoadState::Begin()
{
	// Load References
	SingletonPointer<CMainState> MainState;
	SingletonPointer<CMainMenuState> MenuState;

	GUIManager = Context->GUIContext->Manager.Get();
	Canvas = GUIManager->GetCanvas();

	// Init Canvas
	Canvas->SetBackgroundColor(Gwen::Color(32, 48, 48));
	Canvas->SetDrawBackground(true);

	// Top Label
	Gwen::Controls::Label * BigLabel = new Gwen::Controls::Label(Canvas);
	BigLabel->SetFont(GUIManager->GetLargeFont());
	BigLabel->SetText(L"Loading...");
	BigLabel->SetBounds(10, 10, 1590, 300);
	BigLabel->SetTextColor(Gwen::Color(255, 255, 255, 84));

	GUIManager->Draw(0, true);
	Context->Window->SwapBuffers();

	AddLabel(L"Initializing System...");
	CGUIEventManager * Forwarder = new CGUIEventManager(GUIManager->GetCanvas(), Context->Window);

	AddLabel(L"Loading Scene Shaders...");
	LoadShaders();

	AddLabel(L"Loading Scene Objects...");
	LoadScene();

	AddLabel(L"Menu is Starting...");

	if (GetConfirmation)
	{
		Gwen::Controls::Button * Button = new Gwen::Controls::Button(GUIManager->GetCanvas());
		Button->SetBounds(250, 650, 250, 35);
		Button->SetText(L"Continue");
		Button->onPress.Add(& Handler, & CLoadStateEventHandler::OnFinish);
	}
	else
	{
		OnFinish();
	}
}

void CLoadState::Update(f32 const Elapsed)
{
	GUIManager->Draw(Elapsed, true);
}

void CLoadState::LoadShaders()
{
	Indent = 60;
	bool Failed = false;

	if (! (Context->Shaders.Glyph = SceneManager->GetShaderLibrary()->Load("Glyph")))
		AddLabel(L"Failed to load Glyph Shader - Glyphs will not draw.", Gwen::Color(255, 32, 32, 192)), Failed = true;
	if (! (Context->Shaders.DiffuseTexture = SceneManager->GetShaderLibrary()->Load("DiffuseTexture")))
		AddLabel(L"Failed to load Diffuse/Texture Shader - Backdrop will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Volume = SceneManager->GetShaderLibrary()->Load("Volume")))
		AddLabel(L"Failed to load Volume Shader - Volume will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Terrain = SceneManager->GetShaderLibrary()->Load("Terrain")))
		AddLabel(L"Failed to load Terrain Shader - Terrain will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Water = SceneManager->GetShaderLibrary()->Load("Water")))
		AddLabel(L"Failed to load Water Shader - Water will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Merge = SceneManager->GetShaderLibrary()->Load("Merge")))
		AddLabel(L"Failed to load Merge Shader - Water surface will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Refract = SceneManager->GetShaderLibrary()->Load("Refract")))
		AddLabel(L"Failed to load Refract Shader - Water surface  will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.White = SceneManager->GetShaderLibrary()->Load("White")))
		AddLabel(L"Failed to load White Shader - Water surface  will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;

	if (! Failed)
		AddLabel(L"All shaders compiled successfully.", Gwen::Color(64, 255, 64, 192));
	else
		GetConfirmation = true;

	Indent = 0;
}

void CLoadState::LoadScene()
{
	// References
	CProgramContext::SScene & Scene = Context->Scene;

	// Render Pass Setup
	CRenderPassManager * RenderPassManager = SceneManager->GetRenderPassManager();

	CFrameBuffer * DefaultFrameBuffer = new CFrameBuffer{};
	Context->SceneColorTexture = DefaultFrameBuffer->MakeScreenSizedColorAttachment(0);
	Context->SceneDepthBuffer = DefaultFrameBuffer->MakeScreenSizedDepthTextureAttachment();
	RenderPassManager->AddRenderPass("Default", DefaultFrameBuffer);

	CFrameBuffer * VolumeFrameBuffer = new CFrameBuffer{};
	VolumeFrameBuffer->AttachColorTexture(DefaultFrameBuffer->GetColorTextureAttachment(0), 0);
	RenderPassManager->AddRenderPass("Volume", VolumeFrameBuffer)->SetClearBuffers({});

	CFrameBuffer * MaskFrameBuffer = new CFrameBuffer();
	CTexture2D * MaskTexture = Context->RefractMaskTexture = MaskFrameBuffer->MakeScreenSizedColorAttachment(0);
	MaskFrameBuffer->AttachDepthTexture(Context->SceneDepthBuffer);
	RenderPassManager->AddRenderPass("RefractionMask", MaskFrameBuffer)->SetClearBuffers({ion::GL::EBuffer::Color});

	CFrameBuffer * RefractFrameBuffer = new CFrameBuffer();
	Context->SceneRefractColor = RefractFrameBuffer->MakeScreenSizedColorAttachment(0);
	RefractFrameBuffer->AttachDepthTexture(Context->SceneDepthBuffer);
	RenderPassManager->AddRenderPass("Refraction", RefractFrameBuffer)->SetClearBuffers({ion::GL::EBuffer::Color});

	RenderPassManager->SetRenderPassOrder({"Default", "Volume", "RefractionMask", "Refraction"});

	// Cameras
	Scene.Camera = SceneManager->GetFactory()->AddPerspectiveCamera(Context->Window->GetAspectRatio());
	Scene.CameraController = new CCameraController(Scene.Camera);//SVector3f(1.f, 1.3f, 4.5f));
	Scene.CameraController->SetVelocity(1.9f);
	Context->Window->AddListener(Scene.CameraController);

	Scene.OrbitCamera = SceneManager->GetFactory()->AddPerspectiveCamera(Context->Window->GetAspectRatio());
	SceneManager->GetScene()->SetActiveCamera(Scene.Camera);

	SceneManager->GetMeshLibrary()->Add("Cube", CGeometryCreator::CreateCube());
	SceneManager->GetMeshLibrary()->Add("Sphere", CGeometryCreator::CreateSphere());
	SceneManager->GetMeshLibrary()->Add("Plane", CGeometryCreator::CreatePlane());

	SceneManager->GetTextureLibrary()->Load("SkyMap.jpg");
	SceneManager->GetTextureLibrary()->Load("WaterNormals.jpg");

	Scene.SkyBox = SceneManager->GetFactory()->AddSkySphereNode("SkyMap.jpg");

	Scene.Glyphs->Init();

	Scene.Terrain->Load();

	Scene.Volume->Load();

	// Water
	Scene.Water = SceneManager->GetFactory()->AddSceneNode();
	Scene.Water->SetDebugName("Water");
	Scene.Water->SetMesh(SceneManager->GetMeshLibrary()->Get("Plane"));
	Scene.Water->SetShader(SceneManager->GetShaderLibrary()->Get("Refract"), "Refraction");
	Scene.Water->SetShader(SceneManager->GetShaderLibrary()->Get("White"), "RefractionMask");
	Scene.Water->SetTexture(0, SceneManager->GetTextureLibrary()->Get("WaterNormals.jpg"));
	Scene.Water->SetTexture(1, Context->SceneColorTexture);
	Scene.Water->SetTexture(2, MaskTexture);
	Scene.Water->SetScale(vec3f(25.f));
	Scene.Water->SetFeatureEnabled(ion::GL::EDrawFeature::DisableDepthTest, "Refraction", true);
}

void CLoadState::OnFinish()
{
	Canvas->RemoveAllChildren();
	StateManager->SetState(CMainMenuState::GetPtr());
}
<commit_msg>Minor cleanup<commit_after>
#include "CLoadState.h"

#include "CMainState.h"
#include "CMainMenuState.h"
#include "CSite.h"

#include "CTerrainNodeManager.h"
#include "CVolumeNodeManager.h"
#include "CGlyphNodeManager.h"
#include "CPlaneGridSceneObject.h"

#include <ionGUI/CGUIEventManager.h>

void CLoadStateEventHandler::OnFinish(Gwen::Controls::Base * Control)
{
	CLoadState::Get().OnFinish();
}

void CLoadState::AddLabel(std::wstring const & Label, Gwen::Color const & Color)
{
	Gwen::Controls::Label * MediumLabel = new Gwen::Controls::Label(Canvas);
	MediumLabel->SetFont(GUIManager->GetMediumFont());
	MediumLabel->SetText(Label);
	MediumLabel->SetBounds(20 + Indent, LabelHeight, 1024, 300);
	MediumLabel->SetTextColor(Color);

	GUIManager->Draw(true);
	Context->Window->SwapBuffers();

	LabelHeight += 40;
}

CLoadState::CLoadState()
	: LabelHeight(0), Indent(0), GetConfirmation(false)
{
	LabelHeight = 70;
	Indent = 0;
}

void CLoadState::Begin()
{
	// Load References
	SingletonPointer<CMainState> MainState;
	SingletonPointer<CMainMenuState> MenuState;

	GUIManager = Context->GUIContext->Manager.Get();
	Canvas = GUIManager->GetCanvas();

	// Init Canvas
	Canvas->SetBackgroundColor(Gwen::Color(32, 48, 48));
	Canvas->SetDrawBackground(true);

	// Top Label
	Gwen::Controls::Label * BigLabel = new Gwen::Controls::Label(Canvas);
	BigLabel->SetFont(GUIManager->GetLargeFont());
	BigLabel->SetText(L"Loading...");
	BigLabel->SetBounds(10, 10, 1590, 300);
	BigLabel->SetTextColor(Gwen::Color(255, 255, 255, 84));

	GUIManager->Draw(0, true);
	Context->Window->SwapBuffers();

	AddLabel(L"Initializing System...");
	CGUIEventManager * Forwarder = new CGUIEventManager(GUIManager->GetCanvas(), Context->Window);

	AddLabel(L"Loading Scene Shaders...");
	LoadShaders();

	AddLabel(L"Loading Scene Objects...");
	LoadScene();

	AddLabel(L"Menu is Starting...");

	if (GetConfirmation)
	{
		Gwen::Controls::Button * Button = new Gwen::Controls::Button(GUIManager->GetCanvas());
		Button->SetBounds(250, 650, 250, 35);
		Button->SetText(L"Continue");
		Button->onPress.Add(& Handler, & CLoadStateEventHandler::OnFinish);
	}
	else
	{
		OnFinish();
	}
}

void CLoadState::Update(f32 const Elapsed)
{
	GUIManager->Draw(Elapsed, true);
}

void CLoadState::LoadShaders()
{
	Indent = 60;
	bool Failed = false;

	if (! (Context->Shaders.Glyph = SceneManager->GetShaderLibrary()->Load("Glyph")))
		AddLabel(L"Failed to load Glyph Shader - Glyphs will not draw.", Gwen::Color(255, 32, 32, 192)), Failed = true;
	if (! (Context->Shaders.DiffuseTexture = SceneManager->GetShaderLibrary()->Load("DiffuseTexture")))
		AddLabel(L"Failed to load Diffuse/Texture Shader - Backdrop will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Volume = SceneManager->GetShaderLibrary()->Load("Volume")))
		AddLabel(L"Failed to load Volume Shader - Volume will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Terrain = SceneManager->GetShaderLibrary()->Load("Terrain")))
		AddLabel(L"Failed to load Terrain Shader - Terrain will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Water = SceneManager->GetShaderLibrary()->Load("Water")))
		AddLabel(L"Failed to load Water Shader - Water will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Merge = SceneManager->GetShaderLibrary()->Load("Merge")))
		AddLabel(L"Failed to load Merge Shader - Water surface will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.Refract = SceneManager->GetShaderLibrary()->Load("Refract")))
		AddLabel(L"Failed to load Refract Shader - Water surface  will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;
	if (! (Context->Shaders.White = SceneManager->GetShaderLibrary()->Load("White")))
		AddLabel(L"Failed to load White Shader - Water surface  will not draw.", Gwen::Color(255, 64, 64, 192)), Failed = true;

	if (! Failed)
		AddLabel(L"All shaders compiled successfully.", Gwen::Color(64, 255, 64, 192));
	else
		GetConfirmation = true;

	Indent = 0;
}

void CLoadState::LoadScene()
{
	// References
	CProgramContext::SScene & Scene = Context->Scene;

	// Render Pass Setup
	CRenderPassManager * RenderPassManager = SceneManager->GetRenderPassManager();

	CFrameBuffer * DefaultFrameBuffer = new CFrameBuffer{};
	Context->SceneColorTexture = DefaultFrameBuffer->MakeScreenSizedColorAttachment(0);
	Context->SceneDepthBuffer = DefaultFrameBuffer->MakeScreenSizedDepthTextureAttachment();
	RenderPassManager->AddRenderPass("Default", DefaultFrameBuffer);

	CFrameBuffer * VolumeFrameBuffer = new CFrameBuffer{};
	VolumeFrameBuffer->AttachColorTexture(DefaultFrameBuffer->GetColorTextureAttachment(0), 0);
	RenderPassManager->AddRenderPass("Volume", VolumeFrameBuffer)->SetClearBuffers({});

	CFrameBuffer * MaskFrameBuffer = new CFrameBuffer();
	CTexture2D * MaskTexture = Context->RefractMaskTexture = MaskFrameBuffer->MakeScreenSizedColorAttachment(0);
	MaskFrameBuffer->AttachDepthTexture(Context->SceneDepthBuffer);
	RenderPassManager->AddRenderPass("RefractionMask", MaskFrameBuffer)->SetClearBuffers({ion::GL::EBuffer::Color});

	CFrameBuffer * RefractFrameBuffer = new CFrameBuffer();
	Context->SceneRefractColor = RefractFrameBuffer->MakeScreenSizedColorAttachment(0);
	RefractFrameBuffer->AttachDepthTexture(Context->SceneDepthBuffer);
	RenderPassManager->AddRenderPass("Refraction", RefractFrameBuffer)->SetClearBuffers({ion::GL::EBuffer::Color});

	RenderPassManager->SetRenderPassOrder({"Default", "Volume", "RefractionMask", "Refraction"});

	// Cameras
	Scene.Camera = SceneManager->GetFactory()->AddPerspectiveCamera(Context->Window->GetAspectRatio());
	Scene.CameraController = new CCameraController(Scene.Camera);//SVector3f(1.f, 1.3f, 4.5f));
	Scene.CameraController->SetVelocity(1.9f);
	Context->Window->AddListener(Scene.CameraController);

	Scene.OrbitCamera = SceneManager->GetFactory()->AddPerspectiveCamera(Context->Window->GetAspectRatio());
	SceneManager->GetScene()->SetActiveCamera(Scene.Camera);

	// Assets
	SceneManager->GetMeshLibrary()->Add("Cube", CGeometryCreator::CreateCube());
	SceneManager->GetMeshLibrary()->Add("Sphere", CGeometryCreator::CreateSphere());
	SceneManager->GetMeshLibrary()->Add("Plane", CGeometryCreator::CreatePlane());

	SceneManager->GetTextureLibrary()->Load("SkyMap.jpg");
	SceneManager->GetTextureLibrary()->Load("WaterNormals.jpg");

	// Nodes
	Scene.SkyBox = SceneManager->GetFactory()->AddSkySphereNode("SkyMap.jpg");

	Scene.Glyphs->Init();
	Scene.Terrain->Load();
	Scene.Volume->Load();

	Scene.Water = SceneManager->GetFactory()->AddSceneNode();
	Scene.Water->SetDebugName("Water");
	Scene.Water->SetMesh(SceneManager->GetMeshLibrary()->Get("Plane"));
	Scene.Water->SetShader(SceneManager->GetShaderLibrary()->Get("Refract"), "Refraction");
	Scene.Water->SetShader(SceneManager->GetShaderLibrary()->Get("White"), "RefractionMask");
	Scene.Water->SetTexture(0, SceneManager->GetTextureLibrary()->Get("WaterNormals.jpg"));
	Scene.Water->SetTexture(1, Context->SceneColorTexture);
	Scene.Water->SetTexture(2, MaskTexture);
	Scene.Water->SetScale(vec3f(25.f));
	Scene.Water->SetFeatureEnabled(ion::GL::EDrawFeature::DisableDepthTest, "Refraction", true);
}

void CLoadState::OnFinish()
{
	Canvas->RemoveAllChildren();
	StateManager->SetState(CMainMenuState::GetPtr());
}
<|endoftext|>


<commit_before>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#define LOG_TAG "ArmnnDriver"

#include "ArmnnPreparedModel.hpp"
#include "Utils.hpp"

#include <boost/format.hpp>
#include <log/log.h>
#include <OperationsUtils.h>

#if defined(ARMNN_ANDROID_P)
// The headers of the ML framework have changed between Android O and Android P.
// The validation functions have been moved into their own header, ValidateHal.h.
#include <ValidateHal.h>
#endif

#include <cassert>
#include <cinttypes>

using namespace android;

namespace
{
using namespace armnn_driver;

void NotifyCallbackAndCheck(const ::android::sp<IExecutionCallback>& callback, ErrorStatus errorStatus,
                            std::string callingFunction)
{
    Return<void> returned = callback->notify(errorStatus);
    // This check is required, if the callback fails and it isn't checked it will bring down the service
    if (!returned.isOk())
    {
        ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
            callingFunction.c_str(), returned.description().c_str());
    }
}

bool ValidateRequestArgument(const RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
{
    if (requestArg.dimensions.size() != 0)
    {
        if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
        {
            ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
                  requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
            return false;
        }

        for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
        {
            if (requestArg.dimensions[d] != tensorInfo.GetShape()[d])
            {
                ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
                    d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
                return false;
            }
        }
    }

    return true;
}

armnn::Tensor GetTensorForRequestArgument(const RequestArgument& requestArg,
    const armnn::TensorInfo& tensorInfo,
    const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
{
    if (!ValidateRequestArgument(requestArg, tensorInfo))
    {
        return armnn::Tensor();
    }

    return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
}

inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
{
    return tensorNamePrefix + std::to_string(index);
}

}

using namespace android::hardware;

namespace armnn_driver
{

RequestThread ArmnnPreparedModel::m_RequestThread;

template <typename TensorBindingCollection>
void ArmnnPreparedModel::DumpTensorsIfRequired(char const* tensorNamePrefix,
    const TensorBindingCollection& tensorBindings)
{
    if (!m_RequestInputsAndOutputsDumpDir.empty())
    {
        const std::string requestName = boost::str(boost::format("%1%_%2%.dump") % m_NetworkId % m_RequestCount);
        for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
        {
            DumpTensor(m_RequestInputsAndOutputsDumpDir,
                requestName,
                BuildTensorName(tensorNamePrefix, i),
                tensorBindings[i].second);
        }
    }
}

ArmnnPreparedModel::ArmnnPreparedModel(armnn::NetworkId networkId,
                                       armnn::IRuntime* runtime,
                                       const neuralnetworks::V1_0::Model& model,
                                       const std::string& requestInputsAndOutputsDumpDir,
                                       const bool gpuProfilingEnabled)
    : m_NetworkId(networkId)
    , m_Runtime(runtime)
    , m_Model(model)
    , m_RequestCount(0)
    , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
    , m_GpuProfilingEnabled(gpuProfilingEnabled)
{
    // Enable profiling if required.
    m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
}

ArmnnPreparedModel::~ArmnnPreparedModel()
{
    // Get a hold of the profiler used by this model.
    std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);

    // Unload the network associated with this model.
    m_Runtime->UnloadNetwork(m_NetworkId);

    // Dump the profiling info to a file if required.
    DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
}

Return<ErrorStatus> ArmnnPreparedModel::execute(const Request& request,
                                                const ::android::sp<IExecutionCallback>& callback)
{
    ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
    m_RequestCount++;

    if (callback.get() == nullptr) {
        ALOGE("ArmnnPreparedModel::execute invalid callback passed");
        return ErrorStatus::INVALID_ARGUMENT;
    }

    if (!android::nn::validateRequest(request, m_Model))
    {
        NotifyCallbackAndCheck(callback, ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
        return ErrorStatus::INVALID_ARGUMENT;
    }

    if (!m_RequestInputsAndOutputsDumpDir.empty())
    {
        ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
    }

    // allocate the tensors on the heap, as they are passed to the request thread
    auto pInputTensors = std::make_shared<armnn::InputTensors>();
    auto pOutputTensors = std::make_shared<armnn::OutputTensors>();

    // map the memory pool into shared pointers
    // use a shared memory pools vector on the heap, as it is passed to the request thread
    auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
    if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
    {
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
        return ErrorStatus::GENERAL_FAILURE;
    }

    // add the inputs and outputs with their data
    try
    {
        pInputTensors->reserve(request.inputs.size());
        for (unsigned int i = 0; i < request.inputs.size(); i++)
        {
            const auto& inputArg = request.inputs[i];

            const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
            const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
            if (inputTensor.GetMemoryArea() == nullptr)
            {
                ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
                return ErrorStatus::GENERAL_FAILURE;
            }

            pInputTensors->emplace_back(i, inputTensor);
        }

        pOutputTensors->reserve(request.outputs.size());
        for (unsigned int i = 0; i < request.outputs.size(); i++)
        {
            const auto& outputArg = request.outputs[i];

            const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
            const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
            if (outputTensor.GetMemoryArea() == nullptr)
            {
                ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
                return ErrorStatus::GENERAL_FAILURE;
            }

            pOutputTensors->emplace_back(i, outputTensor);
        }
    }
    catch (armnn::Exception& e)
    {
        ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
        return ErrorStatus::GENERAL_FAILURE;
    }

    ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
    // post the request for asynchronous execution
    m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, callback);
    ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");

    return ErrorStatus::NONE; // successfully queued
}

void ArmnnPreparedModel::ExecuteGraph(std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
                                      std::shared_ptr<armnn::InputTensors>& pInputTensors,
                                      std::shared_ptr<armnn::OutputTensors>& pOutputTensors,
                                      const ::android::sp<IExecutionCallback>& callback)
{
    ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");

    DumpTensorsIfRequired("Input", *pInputTensors);

    // run it
    try
    {
        m_Runtime->EnqueueWorkload(m_NetworkId, *pInputTensors, *pOutputTensors);
    }
    catch (armnn::Exception& e)
    {
        ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
        return;
    }

    DumpTensorsIfRequired("Output", *pOutputTensors);

    // Commit output buffers.
    // Note that we update *all* pools, even if they aren't actually used as outputs -
    // this is simpler and is what the CpuExecutor does.
    for (android::nn::RunTimePoolInfo& pool : *pMemPools)
    {
        pool.update();
    }

    NotifyCallbackAndCheck(callback, ErrorStatus::NONE, "ExecuteGraph");
}

void ArmnnPreparedModel::ExecuteWithDummyInputs()
{
    std::vector<std::vector<char>> storage;
    armnn::InputTensors inputTensors;
    for (unsigned int i = 0; i < m_Model.inputIndexes.size(); i++)
    {
        const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
        storage.emplace_back(inputTensorInfo.GetNumBytes());
        const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());

        inputTensors.emplace_back(i, inputTensor);
    }

    armnn::OutputTensors outputTensors;
    for (unsigned int i = 0; i < m_Model.outputIndexes.size(); i++)
    {
        const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
        storage.emplace_back(outputTensorInfo.GetNumBytes());
        const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());

        outputTensors.emplace_back(i, outputTensor);
    }

    try
    {
        m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
    }
    catch (armnn::Exception& e)
    {
        ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
    }
}

} // namespace armnn_driver
<commit_msg>IVGCVSW-1513 - added utility method to android-nn-driver to print JSON profiling output to a file<commit_after>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#define LOG_TAG "ArmnnDriver"

#include "ArmnnPreparedModel.hpp"
#include "Utils.hpp"

#include <boost/format.hpp>
#include <log/log.h>
#include <OperationsUtils.h>

#if defined(ARMNN_ANDROID_P)
// The headers of the ML framework have changed between Android O and Android P.
// The validation functions have been moved into their own header, ValidateHal.h.
#include <ValidateHal.h>
#endif

#include <cassert>
#include <cinttypes>

using namespace android;

namespace
{
using namespace armnn_driver;

void NotifyCallbackAndCheck(const ::android::sp<IExecutionCallback>& callback, ErrorStatus errorStatus,
                            std::string callingFunction)
{
    Return<void> returned = callback->notify(errorStatus);
    // This check is required, if the callback fails and it isn't checked it will bring down the service
    if (!returned.isOk())
    {
        ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
            callingFunction.c_str(), returned.description().c_str());
    }
}

bool ValidateRequestArgument(const RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
{
    if (requestArg.dimensions.size() != 0)
    {
        if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
        {
            ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
                  requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
            return false;
        }

        for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
        {
            if (requestArg.dimensions[d] != tensorInfo.GetShape()[d])
            {
                ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
                    d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
                return false;
            }
        }
    }

    return true;
}

armnn::Tensor GetTensorForRequestArgument(const RequestArgument& requestArg,
    const armnn::TensorInfo& tensorInfo,
    const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
{
    if (!ValidateRequestArgument(requestArg, tensorInfo))
    {
        return armnn::Tensor();
    }

    return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
}

inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
{
    return tensorNamePrefix + std::to_string(index);
}

}

using namespace android::hardware;

namespace armnn_driver
{

RequestThread ArmnnPreparedModel::m_RequestThread;

template <typename TensorBindingCollection>
void ArmnnPreparedModel::DumpTensorsIfRequired(char const* tensorNamePrefix,
    const TensorBindingCollection& tensorBindings)
{
    if (!m_RequestInputsAndOutputsDumpDir.empty())
    {
        const std::string requestName = boost::str(boost::format("%1%_%2%.dump") % m_NetworkId % m_RequestCount);
        for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
        {
            DumpTensor(m_RequestInputsAndOutputsDumpDir,
                requestName,
                BuildTensorName(tensorNamePrefix, i),
                tensorBindings[i].second);
        }
    }
}

ArmnnPreparedModel::ArmnnPreparedModel(armnn::NetworkId networkId,
                                       armnn::IRuntime* runtime,
                                       const neuralnetworks::V1_0::Model& model,
                                       const std::string& requestInputsAndOutputsDumpDir,
                                       const bool gpuProfilingEnabled)
    : m_NetworkId(networkId)
    , m_Runtime(runtime)
    , m_Model(model)
    , m_RequestCount(0)
    , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
    , m_GpuProfilingEnabled(gpuProfilingEnabled)
{
    // Enable profiling if required.
    m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
}

ArmnnPreparedModel::~ArmnnPreparedModel()
{
    // Get a hold of the profiler used by this model.
    std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);

    // Unload the network associated with this model.
    m_Runtime->UnloadNetwork(m_NetworkId);

    // Dump the profiling info to a file if required.
    DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
}

Return<ErrorStatus> ArmnnPreparedModel::execute(const Request& request,
                                                const ::android::sp<IExecutionCallback>& callback)
{
    ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
    m_RequestCount++;

    if (callback.get() == nullptr) {
        ALOGE("ArmnnPreparedModel::execute invalid callback passed");
        return ErrorStatus::INVALID_ARGUMENT;
    }

    if (!android::nn::validateRequest(request, m_Model))
    {
        NotifyCallbackAndCheck(callback, ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
        return ErrorStatus::INVALID_ARGUMENT;
    }

    if (!m_RequestInputsAndOutputsDumpDir.empty())
    {
        ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
    }

    // allocate the tensors on the heap, as they are passed to the request thread
    auto pInputTensors = std::make_shared<armnn::InputTensors>();
    auto pOutputTensors = std::make_shared<armnn::OutputTensors>();

    // map the memory pool into shared pointers
    // use a shared memory pools vector on the heap, as it is passed to the request thread
    auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
    if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
    {
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
        return ErrorStatus::GENERAL_FAILURE;
    }

    // add the inputs and outputs with their data
    try
    {
        pInputTensors->reserve(request.inputs.size());
        for (unsigned int i = 0; i < request.inputs.size(); i++)
        {
            const auto& inputArg = request.inputs[i];

            const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
            const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
            if (inputTensor.GetMemoryArea() == nullptr)
            {
                ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
                return ErrorStatus::GENERAL_FAILURE;
            }

            pInputTensors->emplace_back(i, inputTensor);
        }

        pOutputTensors->reserve(request.outputs.size());
        for (unsigned int i = 0; i < request.outputs.size(); i++)
        {
            const auto& outputArg = request.outputs[i];

            const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
            const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
            if (outputTensor.GetMemoryArea() == nullptr)
            {
                ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
                return ErrorStatus::GENERAL_FAILURE;
            }

            pOutputTensors->emplace_back(i, outputTensor);
        }
    }
    catch (armnn::Exception& e)
    {
        ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
        return ErrorStatus::GENERAL_FAILURE;
    }

    ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
    // post the request for asynchronous execution
    m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, callback);
    ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");

    return ErrorStatus::NONE; // successfully queued
}

void ArmnnPreparedModel::ExecuteGraph(std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
                                      std::shared_ptr<armnn::InputTensors>& pInputTensors,
                                      std::shared_ptr<armnn::OutputTensors>& pOutputTensors,
                                      const ::android::sp<IExecutionCallback>& callback)
{
    ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");

    if (m_GpuProfilingEnabled)
    {
        m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(true);
    }

    DumpTensorsIfRequired("Input", *pInputTensors);

    // run it
    try
    {
        m_Runtime->EnqueueWorkload(m_NetworkId, *pInputTensors, *pOutputTensors);
    }
    catch (armnn::Exception& e)
    {
        ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
        NotifyCallbackAndCheck(callback, ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
        return;
    }

    DumpTensorsIfRequired("Output", *pOutputTensors);

    if (m_GpuProfilingEnabled && !m_RequestInputsAndOutputsDumpDir.empty())
    {
        DumpJsonProfiling(m_RequestInputsAndOutputsDumpDir, m_Runtime, m_NetworkId);
    }

    // Commit output buffers.
    // Note that we update *all* pools, even if they aren't actually used as outputs -
    // this is simpler and is what the CpuExecutor does.
    for (android::nn::RunTimePoolInfo& pool : *pMemPools)
    {
        pool.update();
    }

    NotifyCallbackAndCheck(callback, ErrorStatus::NONE, "ExecuteGraph");
}

void ArmnnPreparedModel::ExecuteWithDummyInputs()
{
    std::vector<std::vector<char>> storage;
    armnn::InputTensors inputTensors;
    for (unsigned int i = 0; i < m_Model.inputIndexes.size(); i++)
    {
        const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
        storage.emplace_back(inputTensorInfo.GetNumBytes());
        const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());

        inputTensors.emplace_back(i, inputTensor);
    }

    armnn::OutputTensors outputTensors;
    for (unsigned int i = 0; i < m_Model.outputIndexes.size(); i++)
    {
        const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
        storage.emplace_back(outputTensorInfo.GetNumBytes());
        const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());

        outputTensors.emplace_back(i, outputTensor);
    }

    try
    {
        m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
    }
    catch (armnn::Exception& e)
    {
        ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
    }
}

} // namespace armnn_driver
<|endoftext|>


<commit_before><commit_msg>Save 511 constraints with canonical approach to length padding.<commit_after><|endoftext|>