<commit_before>/**
 * \file multipath_alignment_emitter.cpp
 *
 * Implements a system for emitting multipath alignments and groups of multipath alignments in multiple formats.
 */

#include "multipath_alignment_emitter.hpp"
#include "json2pb.h"

namespace vg {
using namespace std;

MultipathAlignmentEmitter::MultipathAlignmentEmitter(ostream& out, int num_threads,
                                                     bool emit_single_path) :
    out(out),
    multiplexer(out, num_threads)
{
    // init the emitters for the correct output type
    if (emit_single_path) {
        aln_emitters.reserve(num_threads);
        for (int i = 0; i < num_threads; ++i) {
            aln_emitters.emplace_back(new vg::io::ProtobufEmitter<Alignment>(multiplexer.get_thread_stream(i)));
        }
    }
    else {
        mp_aln_emitters.reserve(num_threads);
        for (int i = 0; i < num_threads; ++i) {
            mp_aln_emitters.emplace_back(new vg::io::ProtobufEmitter<MultipathAlignment>(multiplexer.get_thread_stream(i)));
        }
    }
}

MultipathAlignmentEmitter::~MultipathAlignmentEmitter() {
    for (auto& emitter : aln_emitters) {
        // Flush each ProtobufEmitter
        emitter->flush();
        // Make it go away before the stream
        emitter.reset();
    }
    for (auto& emitter : mp_aln_emitters) {
        // Flush each ProtobufEmitter
        emitter->flush();
        // Make it go away before the stream
        emitter.reset();
    }
}

void MultipathAlignmentEmitter::emit_pairs(vector<pair<multipath_alignment_t, multipath_alignment_t>>&& mp_aln_pairs) {

    int thread_number = omp_get_thread_num();

    if (!mp_aln_emitters.empty()) {
        vector<MultipathAlignment> mp_alns_out(2 * mp_aln_pairs.size());
        for (size_t i = 0; i < mp_aln_pairs.size(); ++i) {
            to_proto_multipath_alignment(mp_aln_pairs[i].first, mp_alns_out[2 * i]);
            to_proto_multipath_alignment(mp_aln_pairs[i].second, mp_alns_out[2 * i + 1]);
        }

        mp_aln_emitters[thread_number]->write_many(std::move(mp_alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            mp_aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
    else {
        vector<Alignment> alns_out(2 * mp_aln_pairs.size());
        for (size_t i = 0; i < mp_aln_pairs.size(); ++i) {
            convert_multipath_alignment(mp_aln_pairs[i].first, alns_out[2 * i],
                                        nullptr,
                                        &mp_aln_pairs[i].second);
            convert_multipath_alignment(mp_aln_pairs[i].second, alns_out[2 * i + 1],
                                        &mp_aln_pairs[i].first,
                                        nullptr);
        }

        aln_emitters[thread_number]->write_many(std::move(alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
}

void MultipathAlignmentEmitter::emit_singles(vector<multipath_alignment_t>&& mp_alns) {

    int thread_number = omp_get_thread_num();

    if (!mp_aln_emitters.empty()) {
        vector<MultipathAlignment> mp_alns_out(mp_alns.size());
        for (size_t i = 0; i < mp_alns.size(); ++i) {
            to_proto_multipath_alignment(mp_alns[i], mp_alns_out[i]);
        }

        mp_aln_emitters[thread_number]->write_many(std::move(mp_alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            mp_aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
    else {
        vector<Alignment> alns_out(mp_alns.size());
        for (size_t i = 0; i < mp_alns.size(); ++i) {
            convert_multipath_alignment(mp_alns[i], alns_out[i]);
        }

        aln_emitters[thread_number]->write_many(std::move(alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
}

void MultipathAlignmentEmitter::convert_multipath_alignment(const multipath_alignment_t& mp_aln, Alignment& aln,
                                                            const multipath_alignment_t* prev_frag,
                                                            const multipath_alignment_t* next_frag) const {
    optimal_alignment(mp_aln, aln);
    if (prev_frag) {
        aln.mutable_fragment_prev()->set_name(prev_pair->name());
    }
    if (next_frag) {
        aln.mutable_fragment_next()->set_name(next_pair->name());
    }
    // at one point vg call needed these, maybe it doesn't anymore though
    aln.set_identity(identity(aln.path()));
}
}
<commit_msg>fix syntax error<commit_after>/**
 * \file multipath_alignment_emitter.cpp
 *
 * Implements a system for emitting multipath alignments and groups of multipath alignments in multiple formats.
 */

#include "multipath_alignment_emitter.hpp"
#include "json2pb.h"

namespace vg {
using namespace std;

MultipathAlignmentEmitter::MultipathAlignmentEmitter(ostream& out, int num_threads,
                                                     bool emit_single_path) :
    out(out),
    multiplexer(out, num_threads)
{
    // init the emitters for the correct output type
    if (emit_single_path) {
        aln_emitters.reserve(num_threads);
        for (int i = 0; i < num_threads; ++i) {
            aln_emitters.emplace_back(new vg::io::ProtobufEmitter<Alignment>(multiplexer.get_thread_stream(i)));
        }
    }
    else {
        mp_aln_emitters.reserve(num_threads);
        for (int i = 0; i < num_threads; ++i) {
            mp_aln_emitters.emplace_back(new vg::io::ProtobufEmitter<MultipathAlignment>(multiplexer.get_thread_stream(i)));
        }
    }
}

MultipathAlignmentEmitter::~MultipathAlignmentEmitter() {
    for (auto& emitter : aln_emitters) {
        // Flush each ProtobufEmitter
        emitter->flush();
        // Make it go away before the stream
        emitter.reset();
    }
    for (auto& emitter : mp_aln_emitters) {
        // Flush each ProtobufEmitter
        emitter->flush();
        // Make it go away before the stream
        emitter.reset();
    }
}

void MultipathAlignmentEmitter::emit_pairs(vector<pair<multipath_alignment_t, multipath_alignment_t>>&& mp_aln_pairs) {

    int thread_number = omp_get_thread_num();

    if (!mp_aln_emitters.empty()) {
        vector<MultipathAlignment> mp_alns_out(2 * mp_aln_pairs.size());
        for (size_t i = 0; i < mp_aln_pairs.size(); ++i) {
            to_proto_multipath_alignment(mp_aln_pairs[i].first, mp_alns_out[2 * i]);
            to_proto_multipath_alignment(mp_aln_pairs[i].second, mp_alns_out[2 * i + 1]);
        }

        mp_aln_emitters[thread_number]->write_many(std::move(mp_alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            mp_aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
    else {
        vector<Alignment> alns_out(2 * mp_aln_pairs.size());
        for (size_t i = 0; i < mp_aln_pairs.size(); ++i) {
            convert_multipath_alignment(mp_aln_pairs[i].first, alns_out[2 * i],
                                        nullptr,
                                        &mp_aln_pairs[i].second);
            convert_multipath_alignment(mp_aln_pairs[i].second, alns_out[2 * i + 1],
                                        &mp_aln_pairs[i].first,
                                        nullptr);
        }

        aln_emitters[thread_number]->write_many(std::move(alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
}

void MultipathAlignmentEmitter::emit_singles(vector<multipath_alignment_t>&& mp_alns) {

    int thread_number = omp_get_thread_num();

    if (!mp_aln_emitters.empty()) {
        vector<MultipathAlignment> mp_alns_out(mp_alns.size());
        for (size_t i = 0; i < mp_alns.size(); ++i) {
            to_proto_multipath_alignment(mp_alns[i], mp_alns_out[i]);
        }

        mp_aln_emitters[thread_number]->write_many(std::move(mp_alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            mp_aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
    else {
        vector<Alignment> alns_out(mp_alns.size());
        for (size_t i = 0; i < mp_alns.size(); ++i) {
            convert_multipath_alignment(mp_alns[i], alns_out[i]);
        }

        aln_emitters[thread_number]->write_many(std::move(alns_out));

        if (multiplexer.want_breakpoint(thread_number)) {
            // The multiplexer wants our data.
            // Flush and create a breakpoint.
            aln_emitters[thread_number]->flush();
            multiplexer.register_breakpoint(thread_number);
        }
    }
}

void MultipathAlignmentEmitter::convert_multipath_alignment(const multipath_alignment_t& mp_aln, Alignment& aln,
                                                            const multipath_alignment_t* prev_frag,
                                                            const multipath_alignment_t* next_frag) const {
    optimal_alignment(mp_aln, aln);
    if (prev_frag) {
        aln.mutable_fragment_prev()->set_name(prev_frag->name());
    }
    if (next_frag) {
        aln.mutable_fragment_next()->set_name(next_frag->name());
    }
    // at one point vg call needed these, maybe it doesn't anymore though
    aln.set_identity(identity(aln.path()));
}
}
<|endoftext|>


<commit_before><commit_msg>fwd: Cleanup<commit_after><|endoftext|>


<commit_before>//
// Copyright (c) 2018 Rokas Kupstys
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#if URHO3D_PLUGINS

#define CR_HOST CR_DISABLE

#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Core/Thread.h>
#include <Urho3D/Engine/PluginApplication.h>
#include <Urho3D/IO/File.h>
#include <Urho3D/IO/FileSystem.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/Script/Script.h>
#include <Toolbox/SystemUI/Widgets.h>
#include "EditorEvents.h"
#include "Editor.h"
#include "Plugins/PluginManager.h"
#include "PluginManager.h"

namespace Urho3D
{

URHO3D_EVENT(E_ENDFRAMEPRIVATE, EndFramePrivate)
{
}

#if __linux__
static const char* platformDynamicLibrarySuffix = ".so";
#elif _WIN32
static const char* platformDynamicLibrarySuffix = ".dll";
#elif __APPLE__
static const char* platformDynamicLibrarySuffix = ".dylib";
#else
#   error Unsupported platform.
#endif

#if URHO3D_CSHARP && URHO3D_PLUGINS
extern "C" URHO3D_EXPORT_API void ParseArgumentsC(int argc, char** argv) { ParseArguments(argc, argv); }
extern "C" URHO3D_EXPORT_API Application* CreateEditorApplication(Context* context) { return new Editor(context); }
#endif

Plugin::Plugin(Context* context)
    : Object(context)
{
}

bool Plugin::Unload()
{
#if URHO3D_PLUGINS
    if (type_ == PLUGIN_NATIVE)
    {
        cr_plugin_close(nativeContext_);
        nativeContext_.userdata = nullptr;
        return true;
    }
#if URHO3D_CSHARP
    else if (type_ == PLUGIN_MANAGED)
    {
        Script* script = GetSubsystem<Script>();
        script->UnloadRuntime();        // Destroy plugin AppDomain.
        script->LoadRuntime();          // Create new empty plugin AppDomain. Caller is responsible for plugin reinitialization.
        return true;
    }
#endif
#endif
    return false;
}

PluginManager::PluginManager(Context* context)
    : Object(context)
{
#if URHO3D_PLUGINS
    CleanUp();
    SubscribeToEvent(E_ENDFRAMEPRIVATE, [this](StringHash, VariantMap&) { OnEndFrame(); });
    SubscribeToEvent(E_SIMULATIONSTART, [this](StringHash, VariantMap&) {
        for (auto& plugin : plugins_)
        {
            if (plugin->nativeContext_.userdata != nullptr && plugin->nativeContext_.userdata != context_)
                reinterpret_cast<PluginApplication*>(plugin->nativeContext_.userdata)->Start();
        }
    });
    SubscribeToEvent(E_SIMULATIONSTOP, [this](StringHash, VariantMap&) {
        for (auto& plugin : plugins_)
        {
            if (plugin->nativeContext_.userdata != nullptr && plugin->nativeContext_.userdata != context_)
                reinterpret_cast<PluginApplication*>(plugin->nativeContext_.userdata)->Stop();
        }
    });
#if URHO3D_CSHARP
    // Initialize AppDomain for managed plugins.
    GetSubsystem<Script>()->LoadRuntime();
#endif
#endif
}

Plugin* PluginManager::Load(const String& name)
{
#if URHO3D_PLUGINS
    if (Plugin* loaded = GetPlugin(name))
        return loaded;

    String pluginPath = NameToPath(name);
    if (pluginPath.Empty())
        return nullptr;

    SharedPtr<Plugin> plugin(new Plugin(context_));
    plugin->type_ = GetPluginType(context_, pluginPath);

    if (plugin->type_ == PLUGIN_NATIVE)
    {
        if (cr_plugin_load(plugin->nativeContext_, pluginPath.CString()))
        {
            plugin->nativeContext_.userdata = context_;
            plugin->name_ = name;
            plugin->path_ = pluginPath;
            plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(pluginPath);
            plugins_.Push(plugin);
            return plugin.Get();
        }
        else
            URHO3D_LOGWARNINGF("Failed loading native plugin \"%s\".", name.CString());
    }
#if URHO3D_CSHARP
    else if (plugin->type_ == PLUGIN_MANAGED)
    {
        if (GetSubsystem<Script>()->LoadAssembly(pluginPath))
        {
            plugin->name_ = name;
            plugin->path_ = pluginPath;
            plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(pluginPath);
            plugins_.Push(plugin);
            return plugin.Get();
        }
    }
#endif
#endif
    return nullptr;
}

void PluginManager::Unload(Plugin* plugin)
{
    if (plugin == nullptr)
        return;

    auto it = plugins_.Find(SharedPtr<Plugin>(plugin));
    if (it == plugins_.End())
    {
        URHO3D_LOGERRORF("Plugin %s was never loaded.", plugin->name_.CString());
        return;
    }

    plugin->unloading_ = true;
}

void PluginManager::OnEndFrame()
{
#if URHO3D_PLUGINS
#if URHO3D_CSHARP
    Script* script = GetSubsystem<Script>();
    // C# plugin auto-reloading.
    bool reloadManagedRuntime = false;
    for (auto it = plugins_.Begin(); it != plugins_.End() && !reloadManagedRuntime; it++)
    {
        Plugin* plugin = it->Get();
        reloadManagedRuntime = plugin->type_ == PLUGIN_MANAGED &&
                               plugin->mtime_ < GetFileSystem()->GetLastModifiedTime(plugin->path_);
    }

    if (reloadManagedRuntime)
    {
        script->UnloadRuntime();
        script->LoadRuntime();
        for (auto& plugin : plugins_)
        {
            if (plugin->type_ == PLUGIN_MANAGED)
            {
                plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(plugin->path_);
                script->LoadAssembly(plugin->path_);
            }
        }
        URHO3D_LOGINFO("Managed plugins were reloaded.");
    }
#endif

    bool eventSent = false;
    for (auto it = plugins_.Begin(); it != plugins_.End();)
    {
        Plugin* plugin = it->Get();

        if (plugin->unloading_)
        {
            if (!eventSent)
            {
                SendEvent(E_EDITORUSERCODERELOADSTART);
                eventSent = true;
            }
            // Actual unload
            plugin->Unload();
#if URHO3D_CSHARP
            if (plugin->type_ == PLUGIN_MANAGED)
            {
                // Now load back all managed plugins except this one.
                for (auto& plug : plugins_)
                {
                    if (plug == plugin || plug->type_ == PLUGIN_NATIVE)
                        continue;
                    script->LoadAssembly(plug->path_);
                }
            }
#endif
            URHO3D_LOGINFOF("Plugin %s was unloaded.", plugin->name_.CString());
            it = plugins_.Erase(it);
        }
        else if (plugin->type_ == PLUGIN_NATIVE && plugin->nativeContext_.userdata)
        {
            bool reloading = cr_plugin_changed(plugin->nativeContext_);
            if (reloading)
            {
                if (!eventSent)
                {
                    SendEvent(E_EDITORUSERCODERELOADSTART);
                    eventSent = true;
                }
            }

            if (cr_plugin_update(plugin->nativeContext_) != 0)
            {
                URHO3D_LOGERRORF("Processing plugin \"%s\" failed and it was unloaded.",
                    GetFileNameAndExtension(plugin->name_).CString());
                cr_plugin_close(plugin->nativeContext_);
                plugin->nativeContext_.userdata = nullptr;
            }
            else if (reloading && plugin->nativeContext_.userdata != nullptr)
            {
                URHO3D_LOGINFOF("Loaded plugin \"%s\" version %d.", GetFileNameAndExtension(plugin->name_).CString(),
                    plugin->nativeContext_.version);
            }

            it++;
        }
        else
            it++;
    }

    if (eventSent)
        SendEvent(E_EDITORUSERCODERELOADEND);
#endif
}

void PluginManager::CleanUp(String directory)
{
#if URHO3D_PLUGINS
    if (directory.Empty())
        directory = GetFileSystem()->GetProgramDir();

    if (!GetFileSystem()->DirExists(directory))
        return;

    StringVector files;
    GetFileSystem()->ScanDir(files, directory, "*.*", SCAN_FILES, false);

    for (const String& fileName : files)
    {
        String filePath = directory + fileName;
        String baseName = GetFileName(fileName);
        if (IsDigit(static_cast<unsigned int>(baseName.Back())) && GetPluginType(context_, filePath) != PLUGIN_INVALID)
        {
            GetFileSystem()->Delete(filePath);
            if (filePath.EndsWith(".dll"))
                GetFileSystem()->Delete(ReplaceExtension(filePath, ".pdb"));
        }
    }
#endif
}

Plugin* PluginManager::GetPlugin(const String& name)
{
    for (auto it = plugins_.Begin(); it != plugins_.End(); it++)
    {
        if (it->Get()->name_ == name)
            return it->Get();
    }
    return nullptr;
}

String PluginManager::NameToPath(const String& name) const
{
    FileSystem* fs = GetFileSystem();
    String result;

#if __linux__ || __APPLE__
    result = ToString("%slib%s%s", fs->GetProgramDir().CString(), name.CString(), platformDynamicLibrarySuffix);
    if (fs->FileExists(result))
        return result;
#endif

#if !_WIN32
    result = ToString("%s%s%s", fs->GetProgramDir().CString(), name.CString(), ".dll");
    if (fs->FileExists(result))
        return result;
#endif

    result = ToString("%s%s%s", fs->GetProgramDir().CString(), name.CString(), platformDynamicLibrarySuffix);
    if (fs->FileExists(result))
        return result;

    return String::EMPTY;
}

String PluginManager::PathToName(const String& path)
{
#if !_WIN32
    if (path.EndsWith(platformDynamicLibrarySuffix))
    {
        String name = GetFileName(path);
#if __linux__ || __APPLE__
        if (name.StartsWith("lib"))
            name = name.Substring(3);
#endif
        return name;
    }
    else
#endif
    if (path.EndsWith(".dll"))
        return GetFileName(path);
    return String::EMPTY;
}

PluginManager::~PluginManager()
{
    for (auto& plugin : plugins_)
    {
        if (plugin->type_ == PLUGIN_NATIVE)
            // Native plugins can be unloaded one by one.
            plugin->Unload();
    }

#if URHO3D_CSHARP
    // Managed plugins can not be unloaded one at a time. Entire plugin AppDomain must be dropped.
    GetSubsystem<Script>()->UnloadRuntime();
#endif
}

const StringVector& GetPluginNames(Context* context)
{
#if URHO3D_PLUGINS
    StringVector* pluginNames = ui::GetUIState<StringVector>();

    if (pluginNames->Empty())
    {
        FileSystem* fs = context->GetFileSystem();

        StringVector files;
        HashMap<String, String> nameToPath;
        fs->ScanDir(files, fs->GetProgramDir(), "*.*", SCAN_FILES, false);
        // Remove definitely not plugins.
        for (auto it = files.Begin(); it != files.End(); ++it)
        {
            String baseName = PluginManager::PathToName(*it);
            // Native plugins will rename main file and append version after base name.
            if (baseName.Empty() || IsDigit(static_cast<unsigned int>(baseName.Back())))
                continue;

            String fullPath = fs->GetProgramDir() + "/" + *it;
            if (GetPluginType(context, fullPath) == PLUGIN_INVALID)
                continue;

            pluginNames->Push(baseName);
        }
    }
#endif
    return *pluginNames;
}

}

#endif
<commit_msg>Plugins: Wait until build is done before loading plugins.<commit_after>//
// Copyright (c) 2018 Rokas Kupstys
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#if URHO3D_PLUGINS

#define CR_HOST CR_DISABLE

#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Core/Thread.h>
#include <Urho3D/Engine/PluginApplication.h>
#include <Urho3D/IO/File.h>
#include <Urho3D/IO/FileSystem.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/Script/Script.h>
#include <Toolbox/SystemUI/Widgets.h>
#include "EditorEvents.h"
#include "Editor.h"
#include "Plugins/PluginManager.h"
#include "PluginManager.h"

namespace Urho3D
{

URHO3D_EVENT(E_ENDFRAMEPRIVATE, EndFramePrivate)
{
}

#if __linux__
static const char* platformDynamicLibrarySuffix = ".so";
#elif _WIN32
static const char* platformDynamicLibrarySuffix = ".dll";
#elif __APPLE__
static const char* platformDynamicLibrarySuffix = ".dylib";
#else
#   error Unsupported platform.
#endif

#if URHO3D_CSHARP && URHO3D_PLUGINS
extern "C" URHO3D_EXPORT_API void ParseArgumentsC(int argc, char** argv) { ParseArguments(argc, argv); }
extern "C" URHO3D_EXPORT_API Application* CreateEditorApplication(Context* context) { return new Editor(context); }
#endif

Plugin::Plugin(Context* context)
    : Object(context)
{
}

bool Plugin::Unload()
{
#if URHO3D_PLUGINS
    if (type_ == PLUGIN_NATIVE)
    {
        cr_plugin_close(nativeContext_);
        nativeContext_.userdata = nullptr;
        return true;
    }
#if URHO3D_CSHARP
    else if (type_ == PLUGIN_MANAGED)
    {
        Script* script = GetSubsystem<Script>();
        script->UnloadRuntime();        // Destroy plugin AppDomain.
        script->LoadRuntime();          // Create new empty plugin AppDomain. Caller is responsible for plugin reinitialization.
        return true;
    }
#endif
#endif
    return false;
}

PluginManager::PluginManager(Context* context)
    : Object(context)
{
#if URHO3D_PLUGINS
    CleanUp();
    SubscribeToEvent(E_ENDFRAMEPRIVATE, [this](StringHash, VariantMap&) { OnEndFrame(); });
    SubscribeToEvent(E_SIMULATIONSTART, [this](StringHash, VariantMap&) {
        for (auto& plugin : plugins_)
        {
            if (plugin->nativeContext_.userdata != nullptr && plugin->nativeContext_.userdata != context_)
                reinterpret_cast<PluginApplication*>(plugin->nativeContext_.userdata)->Start();
        }
    });
    SubscribeToEvent(E_SIMULATIONSTOP, [this](StringHash, VariantMap&) {
        for (auto& plugin : plugins_)
        {
            if (plugin->nativeContext_.userdata != nullptr && plugin->nativeContext_.userdata != context_)
                reinterpret_cast<PluginApplication*>(plugin->nativeContext_.userdata)->Stop();
        }
    });
#if URHO3D_CSHARP
    // Initialize AppDomain for managed plugins.
    GetSubsystem<Script>()->LoadRuntime();
#endif
#endif
}

Plugin* PluginManager::Load(const String& name)
{
#if URHO3D_PLUGINS
    if (Plugin* loaded = GetPlugin(name))
        return loaded;

    String pluginPath = NameToPath(name);
    if (pluginPath.Empty())
        return nullptr;

    SharedPtr<Plugin> plugin(new Plugin(context_));
    plugin->type_ = GetPluginType(context_, pluginPath);

    if (plugin->type_ == PLUGIN_NATIVE)
    {
        if (cr_plugin_load(plugin->nativeContext_, pluginPath.CString()))
        {
            plugin->nativeContext_.userdata = context_;
            plugin->name_ = name;
            plugin->path_ = pluginPath;
            plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(pluginPath);
            plugins_.Push(plugin);
            return plugin.Get();
        }
        else
            URHO3D_LOGWARNINGF("Failed loading native plugin \"%s\".", name.CString());
    }
#if URHO3D_CSHARP
    else if (plugin->type_ == PLUGIN_MANAGED)
    {
        if (GetSubsystem<Script>()->LoadAssembly(pluginPath))
        {
            plugin->name_ = name;
            plugin->path_ = pluginPath;
            plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(pluginPath);
            plugins_.Push(plugin);
            return plugin.Get();
        }
    }
#endif
#endif
    return nullptr;
}

void PluginManager::Unload(Plugin* plugin)
{
    if (plugin == nullptr)
        return;

    auto it = plugins_.Find(SharedPtr<Plugin>(plugin));
    if (it == plugins_.End())
    {
        URHO3D_LOGERRORF("Plugin %s was never loaded.", plugin->name_.CString());
        return;
    }

    plugin->unloading_ = true;
}

void PluginManager::OnEndFrame()
{
#if URHO3D_PLUGINS
    // TODO: Timeout probably should be configured, larger projects will have a pretty long linking time.
    const unsigned pluginLinkingTimeout = 10000;
    Timer wait;
#if URHO3D_CSHARP
    Script* script = GetSubsystem<Script>();
    // C# plugin auto-reloading.
    PODVector<Plugin*> reloadingPlugins;
    for (auto it = plugins_.Begin(); it != plugins_.End(); it++)
    {
        Plugin* plugin = it->Get();
        if (plugin->type_ == PLUGIN_MANAGED && plugin->mtime_ < GetFileSystem()->GetLastModifiedTime(plugin->path_))
            reloadingPlugins.Push(plugin);
    }

    if (!reloadingPlugins.Empty())
    {
        script->UnloadRuntime();
        script->LoadRuntime();
        for (auto& plugin : plugins_)
        {
            if (plugin->type_ == PLUGIN_MANAGED)
            {
                if (reloadingPlugins.Contains(plugin.Get()))
                {
                    // This plugin was modified and triggered a reload. Good idea before loading it would be waiting for
                    // build to be done (should it still be in progress).
                    while (GetPluginType(context_, plugin->path_) != plugin->type_ && wait.GetMSec(false) < pluginLinkingTimeout)
                        Time::Sleep(0);
                }
                plugin->mtime_ = GetFileSystem()->GetLastModifiedTime(plugin->path_);
                script->LoadAssembly(plugin->path_);
            }
        }
        URHO3D_LOGINFO("Managed plugins were reloaded.");
    }
#endif

    bool eventSent = false;
    for (auto it = plugins_.Begin(); it != plugins_.End();)
    {
        Plugin* plugin = it->Get();

        if (plugin->unloading_)
        {
            if (!eventSent)
            {
                SendEvent(E_EDITORUSERCODERELOADSTART);
                eventSent = true;
            }
            // Actual unload
            plugin->Unload();
#if URHO3D_CSHARP
            if (plugin->type_ == PLUGIN_MANAGED)
            {
                // Now load back all managed plugins except this one.
                for (auto& plug : plugins_)
                {
                    if (plug == plugin || plug->type_ == PLUGIN_NATIVE)
                        continue;
                    script->LoadAssembly(plug->path_);
                }
            }
#endif
            URHO3D_LOGINFOF("Plugin %s was unloaded.", plugin->name_.CString());
            it = plugins_.Erase(it);
        }
        else if (plugin->type_ == PLUGIN_NATIVE && plugin->nativeContext_.userdata)
        {
            bool reloading = cr_plugin_changed(plugin->nativeContext_);
            if (reloading)
            {
                if (!eventSent)
                {
                    SendEvent(E_EDITORUSERCODERELOADSTART);
                    eventSent = true;
                }

                // Plugin change is detected the moment compiler starts linking file. We should wait until linker is done.
                while (GetPluginType(context_, plugin->path_) != plugin->type_ && wait.GetMSec(false) < pluginLinkingTimeout)
                    Time::Sleep(0);
            }

            if (cr_plugin_update(plugin->nativeContext_) != 0)
            {
                URHO3D_LOGERRORF("Processing plugin \"%s\" failed and it was unloaded.",
                    GetFileNameAndExtension(plugin->name_).CString());
                cr_plugin_close(plugin->nativeContext_);
                plugin->nativeContext_.userdata = nullptr;
            }
            else if (reloading && plugin->nativeContext_.userdata != nullptr)
            {
                URHO3D_LOGINFOF("Loaded plugin \"%s\" version %d.", GetFileNameAndExtension(plugin->name_).CString(),
                    plugin->nativeContext_.version);
            }

            it++;
        }
        else
            it++;
    }

    if (eventSent)
        SendEvent(E_EDITORUSERCODERELOADEND);
#endif
}

void PluginManager::CleanUp(String directory)
{
#if URHO3D_PLUGINS
    if (directory.Empty())
        directory = GetFileSystem()->GetProgramDir();

    if (!GetFileSystem()->DirExists(directory))
        return;

    StringVector files;
    GetFileSystem()->ScanDir(files, directory, "*.*", SCAN_FILES, false);

    for (const String& fileName : files)
    {
        String filePath = directory + fileName;
        String baseName = GetFileName(fileName);
        if (IsDigit(static_cast<unsigned int>(baseName.Back())) && GetPluginType(context_, filePath) != PLUGIN_INVALID)
        {
            GetFileSystem()->Delete(filePath);
            if (filePath.EndsWith(".dll"))
                GetFileSystem()->Delete(ReplaceExtension(filePath, ".pdb"));
        }
    }
#endif
}

Plugin* PluginManager::GetPlugin(const String& name)
{
    for (auto it = plugins_.Begin(); it != plugins_.End(); it++)
    {
        if (it->Get()->name_ == name)
            return it->Get();
    }
    return nullptr;
}

String PluginManager::NameToPath(const String& name) const
{
    FileSystem* fs = GetFileSystem();
    String result;

#if __linux__ || __APPLE__
    result = ToString("%slib%s%s", fs->GetProgramDir().CString(), name.CString(), platformDynamicLibrarySuffix);
    if (fs->FileExists(result))
        return result;
#endif

#if !_WIN32
    result = ToString("%s%s%s", fs->GetProgramDir().CString(), name.CString(), ".dll");
    if (fs->FileExists(result))
        return result;
#endif

    result = ToString("%s%s%s", fs->GetProgramDir().CString(), name.CString(), platformDynamicLibrarySuffix);
    if (fs->FileExists(result))
        return result;

    return String::EMPTY;
}

String PluginManager::PathToName(const String& path)
{
#if !_WIN32
    if (path.EndsWith(platformDynamicLibrarySuffix))
    {
        String name = GetFileName(path);
#if __linux__ || __APPLE__
        if (name.StartsWith("lib"))
            name = name.Substring(3);
#endif
        return name;
    }
    else
#endif
    if (path.EndsWith(".dll"))
        return GetFileName(path);
    return String::EMPTY;
}

PluginManager::~PluginManager()
{
    for (auto& plugin : plugins_)
    {
        if (plugin->type_ == PLUGIN_NATIVE)
            // Native plugins can be unloaded one by one.
            plugin->Unload();
    }

#if URHO3D_CSHARP
    // Managed plugins can not be unloaded one at a time. Entire plugin AppDomain must be dropped.
    GetSubsystem<Script>()->UnloadRuntime();
#endif
}

const StringVector& GetPluginNames(Context* context)
{
#if URHO3D_PLUGINS
    StringVector* pluginNames = ui::GetUIState<StringVector>();

    if (pluginNames->Empty())
    {
        FileSystem* fs = context->GetFileSystem();

        StringVector files;
        HashMap<String, String> nameToPath;
        fs->ScanDir(files, fs->GetProgramDir(), "*.*", SCAN_FILES, false);
        // Remove definitely not plugins.
        for (auto it = files.Begin(); it != files.End(); ++it)
        {
            String baseName = PluginManager::PathToName(*it);
            // Native plugins will rename main file and append version after base name.
            if (baseName.Empty() || IsDigit(static_cast<unsigned int>(baseName.Back())))
                continue;

            String fullPath = fs->GetProgramDir() + "/" + *it;
            if (GetPluginType(context, fullPath) == PLUGIN_INVALID)
                continue;

            pluginNames->Push(baseName);
        }
    }
#endif
    return *pluginNames;
}

}

#endif
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "libmesh/petsc_preconditioner.h"
#include "libmesh/petsc_macro.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"
#include "libmesh/libmesh_common.h"

// PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
#if PETSC_VERSION_LESS_THAN(3,1,0)

EXTERN_C_FOR_PETSC_BEGIN
#include "petscksp.h"
EXTERN_C_FOR_PETSC_END

#endif

namespace libMesh
{

template <typename T>
void PetscPreconditioner<T>::apply(const NumericVector<T> & x, NumericVector<T> & y)
{
  PetscVector<T> & x_pvec = libmesh_cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x));
  PetscVector<T> & y_pvec = libmesh_cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(y));

  Vec x_vec = x_pvec.vec();
  Vec y_vec = y_pvec.vec();

  int ierr = PCApply(_pc,x_vec,y_vec);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);
}

template <typename T>
void PetscPreconditioner<T>::init ()
{
  if(!this->_matrix)
  {
    libMesh::err << "ERROR: No matrix set for PetscPreconditioner, but init() called" << std::endl;
    libmesh_error();
  }

  // Clear the preconditioner in case it has been created in the past
  if (!this->_is_initialized)
  {
    // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
    if (_pc)
    {
      int ierr = PCDestroy(&_pc);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }

    int ierr = PCCreate(libMesh::COMM_WORLD,&_pc);
    CHKERRABORT(libMesh::COMM_WORLD,ierr);

    PetscMatrix<T> * pmatrix = libmesh_cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix);

    _mat = pmatrix->mat();
  }

  int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the PCType.  Note: this used to be done *before* the call to
  // PCSetOperators(), and only when !_is_initialized, but
  // 1.) Some preconditioners (those employing sub-preconditioners,
  // for example) have to call PCSetUp(), and can only do this after
  // the operators have been set.
  // 2.) It should be safe to call set_petsc_preconditioner_type()
  // multiple times.
  set_petsc_preconditioner_type(this->_preconditioner_type, _pc);

  this->_is_initialized = true;
}

template <typename T>
void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
{
  int ierr = 0;

  switch (preconditioner_type)
  {
  case IDENTITY_PRECOND:
    ierr = PCSetType (pc, (char*) PCNONE);      CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case CHOLESKY_PRECOND:
    ierr = PCSetType (pc, (char*) PCCHOLESKY);  CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case ICC_PRECOND:
    ierr = PCSetType (pc, (char*) PCICC);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case ILU_PRECOND:
    {
      // In serial, just set the ILU preconditioner type
      if (libMesh::n_processors() == 1)
	{
	  ierr = PCSetType (pc, (char*) PCILU);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel ILU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign ILU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCILU, pc);
	}
      break;
    }

  case LU_PRECOND:
    {
      // In serial, just set the LU preconditioner type
      if (libMesh::n_processors() == 1)
	{
	  ierr = PCSetType (pc, (char*) PCLU);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel LU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign LU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCLU, pc);
	}
      break;
    }

  case ASM_PRECOND:
    {
      // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
      // I tried setting a different sub-preconditioner here, but apparently the matrix
      // is not in the correct state (at this point) to call PCSetUp().
      ierr = PCSetType (pc, (char*) PCASM);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
      break;
    }

  case JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCJACOBI);    CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case BLOCK_JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCBJACOBI);   CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case SOR_PRECOND:
    ierr = PCSetType (pc, (char*) PCSOR);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case EISENSTAT_PRECOND:
    ierr = PCSetType (pc, (char*) PCEISENSTAT); CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case AMG_PRECOND:
    ierr = PCSetType (pc, (char*) PCHYPRE);     CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
    // Only available for PETSC >= 2.1.2
  case USER_PRECOND:
    ierr = PCSetType (pc, (char*) PCMAT);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;
#endif

  case SHELL_PRECOND:
    ierr = PCSetType (pc, (char*) PCSHELL);     CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  default:
    libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
                  << preconditioner_type       << std::endl
                  << "Continuing with PETSC defaults" << std::endl;
  }

  // Set additional options if we are doing AMG and
  // HYPRE is available
#ifdef LIBMESH_HAVE_PETSC_HYPRE
  if (preconditioner_type == AMG_PRECOND)
    {
      ierr = PCHYPRESetType(pc, "boomeramg");
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
#endif

  // Let the commandline override stuff
  // FIXME: Unless we are doing AMG???
  if (preconditioner_type != AMG_PRECOND)
    {
      ierr = PCSetFromOptions(pc);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
#if PETSC_VERSION_LESS_THAN(3,0,0)
 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc)
#else
 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc)
#endif
{
  // For catching PETSc error return codes
  int ierr = 0;

  // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
  // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
  //
  // "Object is in wrong state!"
  // "Matrix must be set first."
  //
  // error messages...
  ierr = PCSetUp(pc);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // To store array of local KSP contexts on this processor
  KSP* subksps;

  // the number of blocks on this processor
  int n_local;

  // The global number of the first block on this processor.
  // This is not used, so we just pass PETSC_NULL instead.
  // int first_local;

  // Fill array of local KSP contexts
  ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Loop over sub-ksp objects, set ILU preconditioner
  for (int i=0; i<n_local; ++i)
    {
      // Get pointer to sub KSP object's PC
      PC subpc;
      ierr = KSPGetPC(subksps[i], &subpc);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);

      // Set requested type on the sub PC
      ierr = PCSetType(subpc, type);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }

}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscPreconditioner<Number>;

} // namespace libMesh

#endif // #ifdef LIBMESH_HAVE_PETSC
<commit_msg>fix for PETSc 3.1 and older<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "libmesh/petsc_preconditioner.h"
#include "libmesh/petsc_macro.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"
#include "libmesh/libmesh_common.h"

// PCBJacobiGetSubKSP was defined in petscksp.h in PETSc 2.3.3, 3.1.0
#if PETSC_VERSION_LESS_THAN(3,1,0)

EXTERN_C_FOR_PETSC_BEGIN
#include "petscksp.h"
EXTERN_C_FOR_PETSC_END

#endif

namespace libMesh
{

template <typename T>
void PetscPreconditioner<T>::apply(const NumericVector<T> & x, NumericVector<T> & y)
{
  PetscVector<T> & x_pvec = libmesh_cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(x));
  PetscVector<T> & y_pvec = libmesh_cast_ref<PetscVector<T>&>(const_cast<NumericVector<T>&>(y));

  Vec x_vec = x_pvec.vec();
  Vec y_vec = y_pvec.vec();

  int ierr = PCApply(_pc,x_vec,y_vec);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);
}

template <typename T>
void PetscPreconditioner<T>::init ()
{
  if(!this->_matrix)
  {
    libMesh::err << "ERROR: No matrix set for PetscPreconditioner, but init() called" << std::endl;
    libmesh_error();
  }

  // Clear the preconditioner in case it has been created in the past
  if (!this->_is_initialized)
  {
    // Should probably use PCReset(), but it's not working at the moment so we'll destroy instead
    if (_pc)
    {
#if PETSC_VERSION_LESS_THAN(3,2,0)
      int ierr = PCDestroy(_pc);
#else
      int ierr = PCDestroy(&_pc);
#endif
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }

    int ierr = PCCreate(libMesh::COMM_WORLD,&_pc);
    CHKERRABORT(libMesh::COMM_WORLD,ierr);

    PetscMatrix<T> * pmatrix = libmesh_cast_ptr<PetscMatrix<T>*, SparseMatrix<T> >(this->_matrix);

    _mat = pmatrix->mat();
  }

  int ierr = PCSetOperators(_pc,_mat,_mat,SAME_NONZERO_PATTERN);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the PCType.  Note: this used to be done *before* the call to
  // PCSetOperators(), and only when !_is_initialized, but
  // 1.) Some preconditioners (those employing sub-preconditioners,
  // for example) have to call PCSetUp(), and can only do this after
  // the operators have been set.
  // 2.) It should be safe to call set_petsc_preconditioner_type()
  // multiple times.
  set_petsc_preconditioner_type(this->_preconditioner_type, _pc);

  this->_is_initialized = true;
}

template <typename T>
void PetscPreconditioner<T>::set_petsc_preconditioner_type (const PreconditionerType & preconditioner_type, PC & pc)
{
  int ierr = 0;

  switch (preconditioner_type)
  {
  case IDENTITY_PRECOND:
    ierr = PCSetType (pc, (char*) PCNONE);      CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case CHOLESKY_PRECOND:
    ierr = PCSetType (pc, (char*) PCCHOLESKY);  CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case ICC_PRECOND:
    ierr = PCSetType (pc, (char*) PCICC);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case ILU_PRECOND:
    {
      // In serial, just set the ILU preconditioner type
      if (libMesh::n_processors() == 1)
	{
	  ierr = PCSetType (pc, (char*) PCILU);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel ILU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign ILU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCILU, pc);
	}
      break;
    }

  case LU_PRECOND:
    {
      // In serial, just set the LU preconditioner type
      if (libMesh::n_processors() == 1)
	{
	  ierr = PCSetType (pc, (char*) PCLU);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);
	}
      else
	{
	  // But PETSc has no truly parallel LU, instead you have to set
	  // an actual parallel preconditioner (e.g. block Jacobi) and then
	  // assign LU sub-preconditioners.
	  ierr = PCSetType (pc, (char*) PCBJACOBI);
	  CHKERRABORT(libMesh::COMM_WORLD,ierr);

	  // Set ILU as the sub preconditioner type
	  set_petsc_subpreconditioner_type(PCLU, pc);
	}
      break;
    }

  case ASM_PRECOND:
    {
      // In parallel, I think ASM uses ILU by default as the sub-preconditioner...
      // I tried setting a different sub-preconditioner here, but apparently the matrix
      // is not in the correct state (at this point) to call PCSetUp().
      ierr = PCSetType (pc, (char*) PCASM);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
      break;
    }

  case JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCJACOBI);    CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case BLOCK_JACOBI_PRECOND:
    ierr = PCSetType (pc, (char*) PCBJACOBI);   CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case SOR_PRECOND:
    ierr = PCSetType (pc, (char*) PCSOR);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case EISENSTAT_PRECOND:
    ierr = PCSetType (pc, (char*) PCEISENSTAT); CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  case AMG_PRECOND:
    ierr = PCSetType (pc, (char*) PCHYPRE);     CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

#if !(PETSC_VERSION_LESS_THAN(2,1,2))
    // Only available for PETSC >= 2.1.2
  case USER_PRECOND:
    ierr = PCSetType (pc, (char*) PCMAT);       CHKERRABORT(libMesh::COMM_WORLD,ierr); break;
#endif

  case SHELL_PRECOND:
    ierr = PCSetType (pc, (char*) PCSHELL);     CHKERRABORT(libMesh::COMM_WORLD,ierr); break;

  default:
    libMesh::err << "ERROR:  Unsupported PETSC Preconditioner: "
                  << preconditioner_type       << std::endl
                  << "Continuing with PETSC defaults" << std::endl;
  }

  // Set additional options if we are doing AMG and
  // HYPRE is available
#ifdef LIBMESH_HAVE_PETSC_HYPRE
  if (preconditioner_type == AMG_PRECOND)
    {
      ierr = PCHYPRESetType(pc, "boomeramg");
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
#endif

  // Let the commandline override stuff
  // FIXME: Unless we are doing AMG???
  if (preconditioner_type != AMG_PRECOND)
    {
      ierr = PCSetFromOptions(pc);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
#if PETSC_VERSION_LESS_THAN(3,0,0)
 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(PCType type, PC& pc)
#else
 void PetscPreconditioner<T>::set_petsc_subpreconditioner_type(const PCType type, PC& pc)
#endif
{
  // For catching PETSc error return codes
  int ierr = 0;

  // All docs say must call KSPSetUp or PCSetUp before calling PCBJacobiGetSubKSP.
  // You must call PCSetUp after the preconditioner operators have been set, otherwise you get the:
  //
  // "Object is in wrong state!"
  // "Matrix must be set first."
  //
  // error messages...
  ierr = PCSetUp(pc);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // To store array of local KSP contexts on this processor
  KSP* subksps;

  // the number of blocks on this processor
  int n_local;

  // The global number of the first block on this processor.
  // This is not used, so we just pass PETSC_NULL instead.
  // int first_local;

  // Fill array of local KSP contexts
  ierr = PCBJacobiGetSubKSP(pc, &n_local, PETSC_NULL, &subksps);
  CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Loop over sub-ksp objects, set ILU preconditioner
  for (int i=0; i<n_local; ++i)
    {
      // Get pointer to sub KSP object's PC
      PC subpc;
      ierr = KSPGetPC(subksps[i], &subpc);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);

      // Set requested type on the sub PC
      ierr = PCSetType(subpc, type);
      CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }

}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscPreconditioner<Number>;

} // namespace libMesh

#endif // #ifdef LIBMESH_HAVE_PETSC
<|endoftext|>


<commit_before>/**
 * @license cc-dict 0.0.3
 * Copyright (c) 2011, Takeru Ohta, phjgt308@gmail.com
 * MIT license
 * https://github.com/sile/cc-dict/blob/master/COPYING
 */
#ifndef DICT_HASH_HH
#define DICT_HASH_HH

#include <string>

namespace dict {
  const unsigned GOLDEN_RATIO_PRIME=(2^31) + (2^29) - (2^25) + (2^22) - (2^19) - (2^16) + 1;

  template<class Key>
  class hash_functor {
  public:
    unsigned operator()(const Key& key) const {
      return hash(key);
    }
  };

  unsigned hash(int key) {
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(unsigned key) {
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(long key) {
    // XXX: if sizeof(long) > sizeof(unsigned), the calculation will lose high bits information of key.
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(const char* key) {
    unsigned h = GOLDEN_RATIO_PRIME;
    for(const char* c=key; *c != 0; c++)
      h = (h*33) + *c;
    return h;
  }

  unsigned hash(const std::string& key) {
    return hash(key.c_str());
  }
}

#endif
<commit_msg>unordered_mapに合わせてconst char*はポインタとして扱うように修正<commit_after>/**
 * @license cc-dict 0.0.3
 * Copyright (c) 2011, Takeru Ohta, phjgt308@gmail.com
 * MIT license
 * https://github.com/sile/cc-dict/blob/master/COPYING
 */
#ifndef DICT_HASH_HH
#define DICT_HASH_HH

#include <string>

namespace dict {
  const unsigned GOLDEN_RATIO_PRIME=(2^31) + (2^29) - (2^25) + (2^22) - (2^19) - (2^16) + 1;

  template<class Key>
  class hash_functor {
  public:
    unsigned operator()(const Key& key) const {
      return hash(key);
    }
  };

  unsigned hash(int key) {
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(unsigned key) {
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(long key) {
    // XXX: if sizeof(long) > sizeof(unsigned), the calculation will lose high bits information of key.
    return key * GOLDEN_RATIO_PRIME;
  }

  unsigned hash(const char* key) {
    return hash(reinterpret_cast<long>(key));
  }

  unsigned hash(const std::string& key) {
    unsigned h = GOLDEN_RATIO_PRIME;
    for(const char* c=key.c_str(); *c != 0; c++)
      h = (h*33) + *c;
    return h;
  }
}

#endif
<|endoftext|>


<commit_before>/*
    Copyright (C) 2016 Clownacy

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
    USA
*/

#include <windows.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>

#include "Common.h"
#include "PrjHndl.h"
#include "WinAPI.h"

namespace WinAPI
{

HWND hWnd;
HMENU hMenu;
HMENU hSubMenu_File;
HMENU hSubMenu_View;
COLORREF custom_colours[16];

void SaveHWND(SDL_Window* const window);
void CreateMenuBar(void);
void HandleWindowsEvent(const SDL_Event* const event);
bool OpenProjectFilePrompt(char* const filepath);
void EnableMenuBarOption(bool enable, int menu_option);

void SaveHWND(SDL_Window* const window)
{
	SDL_SysWMinfo info;
	SDL_VERSION(&info.version)
	SDL_GetWindowWMInfo(window,&info);
	hWnd = info.info.win.window;
}

void CreateMenuBar(void)
{
	hMenu = CreateMenu();
	hSubMenu_File = CreatePopupMenu();
	AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu_File, "&File");
	AppendMenu(hSubMenu_File, MF_STRING, MENUBAR_FILE_OPENPROJECT, "&Open");
	AppendMenu(hSubMenu_File, MF_STRING | MF_GRAYED, MENUBAR_FILE_SAVE, "&Save");
	AppendMenu(hSubMenu_File, MF_STRING | MF_GRAYED, MENUBAR_FILE_CLOSE, "&Close");
	AppendMenu(hSubMenu_File, MF_SEPARATOR, 0, NULL);
	AppendMenu(hSubMenu_File, MF_STRING, MENUBAR_FILE_EXIT, "&Exit");
	hSubMenu_View = CreatePopupMenu();
	AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu_View, "&View");
	AppendMenu(hSubMenu_View, MF_STRING, MENUBAR_VIEW_BACKGROUNDCOLOUR, "&Background Colour...");

	SetMenu(hWnd, hMenu);

	SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
}

void HandleWindowsEvent(const SDL_Event* const event)
{
	if (event->syswm.msg->msg.win.msg == WM_COMMAND)
	{
		switch (LOWORD(event->syswm.msg->msg.win.wParam))
		{
			case MENUBAR_FILE_OPENPROJECT:
			{
				char filename[500] = "";
				if (WinAPI::OpenProjectFilePrompt(filename) == true)
				{
					if (CurProject != NULL)
						delete CurProject;
					CurProject = new Project(filename);

					EnableMenuBarOption(true, MENUBAR_FILE_SAVE);
					EnableMenuBarOption(true, MENUBAR_FILE_CLOSE);

					//Process initial display
					MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
					CurProject->Redraw();
				}
				break;
			}
			case MENUBAR_FILE_SAVE:
			{
				CurProject->Save();
				break;
			}
			case MENUBAR_FILE_CLOSE:
			{
				delete CurProject;
				CurProject = NULL;	// Deleting an object does not NULL this pointer, so we have to do it ourselves
				EnableMenuBarOption(false, MENUBAR_FILE_SAVE);
				EnableMenuBarOption(false, MENUBAR_FILE_CLOSE);
				MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
				break;
			}
			case MENUBAR_FILE_EXIT:
			{
				exit(1);
			}
			case MENUBAR_VIEW_BACKGROUNDCOLOUR:
			{
				CHOOSECOLOR user_colour;
				memset(&user_colour, 0, sizeof(user_colour));
				user_colour.lStructSize = sizeof(user_colour);
				user_colour.hwndOwner = hWnd;
				user_colour.rgbResult = RGB(MainScreen->BackgroundColour.red,MainScreen->BackgroundColour.green,MainScreen->BackgroundColour.blue);
				user_colour.lpCustColors = custom_colours;
				user_colour.Flags = CC_RGBINIT;
				if (ChooseColor(&user_colour) == true)
				{
					MainScreen->BackgroundColour.red = GetRValue(user_colour.rgbResult);
					MainScreen->BackgroundColour.green = GetGValue(user_colour.rgbResult);
					MainScreen->BackgroundColour.blue = GetBValue(user_colour.rgbResult);
					MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
					if (CurProject != NULL)
						CurProject->Redraw();
				}
				break;
			}
		}
	}
}

bool OpenProjectFilePrompt(char* const filepath)
{
	OPENFILENAME ofn;
        memset(&ofn, 0, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hWnd;
        ofn.hInstance = NULL;
        ofn.lpstrFilter = TEXT("PlaneEd project file (*.txt)\0*.txt\0\0");
        ofn.nFilterIndex = 1;
        ofn.lpstrFile = filepath;
        ofn.nMaxFile = 500;
        ofn.Flags = OFN_FILEMUSTEXIST;
        bool bRes = GetOpenFileName(&ofn);
	return bRes;
}

void EnableMenuBarOption(bool enable, int menu_option)
{
	HMENU submenu;
	if (menu_option > MENUBAR_FILE_START && menu_option < MENUBAR_FILE_END)
		submenu = hSubMenu_File;
	else //if (menu_option > MENUBAR_VIEW_START && menu_option < MENUBAR_VIEW_END)
		submenu = hSubMenu_View;

	EnableMenuItem(submenu, menu_option, enable ? MF_ENABLED : MF_DISABLED);
}

}
<commit_msg>Prototypes made this redundant<commit_after>/*
    Copyright (C) 2016 Clownacy

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
    USA
*/

#include <windows.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>

#include "Common.h"
#include "PrjHndl.h"
#include "WinAPI.h"

namespace WinAPI
{

HWND hWnd;
HMENU hMenu;
HMENU hSubMenu_File;
HMENU hSubMenu_View;
COLORREF custom_colours[16];

void SaveHWND(SDL_Window* const window);
void CreateMenuBar(void);
void HandleWindowsEvent(const SDL_Event* const event);
bool OpenProjectFilePrompt(char* const filepath);
void EnableMenuBarOption(bool enable, int menu_option);

void SaveHWND(SDL_Window* const window)
{
	SDL_SysWMinfo info;
	SDL_VERSION(&info.version)
	SDL_GetWindowWMInfo(window,&info);
	hWnd = info.info.win.window;
}

void CreateMenuBar(void)
{
	hMenu = CreateMenu();
	hSubMenu_File = CreatePopupMenu();
	AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu_File, "&File");
	AppendMenu(hSubMenu_File, MF_STRING, MENUBAR_FILE_OPENPROJECT, "&Open");
	AppendMenu(hSubMenu_File, MF_STRING | MF_GRAYED, MENUBAR_FILE_SAVE, "&Save");
	AppendMenu(hSubMenu_File, MF_STRING | MF_GRAYED, MENUBAR_FILE_CLOSE, "&Close");
	AppendMenu(hSubMenu_File, MF_SEPARATOR, 0, NULL);
	AppendMenu(hSubMenu_File, MF_STRING, MENUBAR_FILE_EXIT, "&Exit");
	hSubMenu_View = CreatePopupMenu();
	AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu_View, "&View");
	AppendMenu(hSubMenu_View, MF_STRING, MENUBAR_VIEW_BACKGROUNDCOLOUR, "&Background Colour...");

	SetMenu(hWnd, hMenu);

	SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
}

void HandleWindowsEvent(const SDL_Event* const event)
{
	if (event->syswm.msg->msg.win.msg == WM_COMMAND)
	{
		switch (LOWORD(event->syswm.msg->msg.win.wParam))
		{
			case MENUBAR_FILE_OPENPROJECT:
			{
				char filename[500] = "";
				if (OpenProjectFilePrompt(filename) == true)
				{
					if (CurProject != NULL)
						delete CurProject;
					CurProject = new Project(filename);

					EnableMenuBarOption(true, MENUBAR_FILE_SAVE);
					EnableMenuBarOption(true, MENUBAR_FILE_CLOSE);

					//Process initial display
					MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
					CurProject->Redraw();
				}
				break;
			}
			case MENUBAR_FILE_SAVE:
			{
				CurProject->Save();
				break;
			}
			case MENUBAR_FILE_CLOSE:
			{
				delete CurProject;
				CurProject = NULL;	// Deleting an object does not NULL this pointer, so we have to do it ourselves
				EnableMenuBarOption(false, MENUBAR_FILE_SAVE);
				EnableMenuBarOption(false, MENUBAR_FILE_CLOSE);
				MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
				break;
			}
			case MENUBAR_FILE_EXIT:
			{
				exit(1);
			}
			case MENUBAR_VIEW_BACKGROUNDCOLOUR:
			{
				CHOOSECOLOR user_colour;
				memset(&user_colour, 0, sizeof(user_colour));
				user_colour.lStructSize = sizeof(user_colour);
				user_colour.hwndOwner = hWnd;
				user_colour.rgbResult = RGB(MainScreen->BackgroundColour.red,MainScreen->BackgroundColour.green,MainScreen->BackgroundColour.blue);
				user_colour.lpCustColors = custom_colours;
				user_colour.Flags = CC_RGBINIT;
				if (ChooseColor(&user_colour) == true)
				{
					MainScreen->BackgroundColour.red = GetRValue(user_colour.rgbResult);
					MainScreen->BackgroundColour.green = GetGValue(user_colour.rgbResult);
					MainScreen->BackgroundColour.blue = GetBValue(user_colour.rgbResult);
					MainScreen->Fill(MainScreen->BackgroundColour.red, MainScreen->BackgroundColour.green, MainScreen->BackgroundColour.blue);
					if (CurProject != NULL)
						CurProject->Redraw();
				}
				break;
			}
		}
	}
}

bool OpenProjectFilePrompt(char* const filepath)
{
	OPENFILENAME ofn;
        memset(&ofn, 0, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hWnd;
        ofn.hInstance = NULL;
        ofn.lpstrFilter = TEXT("PlaneEd project file (*.txt)\0*.txt\0\0");
        ofn.nFilterIndex = 1;
        ofn.lpstrFile = filepath;
        ofn.nMaxFile = 500;
        ofn.Flags = OFN_FILEMUSTEXIST;
        bool bRes = GetOpenFileName(&ofn);
	return bRes;
}

void EnableMenuBarOption(bool enable, int menu_option)
{
	HMENU submenu;
	if (menu_option > MENUBAR_FILE_START && menu_option < MENUBAR_FILE_END)
		submenu = hSubMenu_File;
	else //if (menu_option > MENUBAR_VIEW_START && menu_option < MENUBAR_VIEW_END)
		submenu = hSubMenu_View;

	EnableMenuItem(submenu, menu_option, enable ? MF_ENABLED : MF_DISABLED);
}

}
<|endoftext|>


<commit_before>#include <stingraykit/string/HumanReadableSize.h>
#include <stingraykit/string/ToString.h>
#include <stingraykit/string/regex.h>

namespace stingray
{

	namespace
	{

		const std::string Suffixes("kMGTPEZ");

	}

	std::string ToHumanReadableSize(u64 size)
	{
		for (size_t i = 0; i < Suffixes.size(); ++i)
		{
			u64 classToCompare = (u64)1 << 10 * (i + 1);
			u64 remainder = size % classToCompare;
			size_t classModifier = remainder > 0 ? 1 : 0;
			size_t roundModifier = remainder >= classToCompare / 2 ? 1 : 0;
			if (size < (u64)1 << 10 * (i + 1 + classModifier))
			{
				u64 result = size / ((u64)1 << 10 * i) + roundModifier;
				if (i > 0)
					return ToString(result) + Suffixes[i - 1];
				else
					return ToString(result);
			}
		}

		return ToString(size);
	}

	u64 FromHumanReadableSize(const std::string& str)
	{
		u64 num;
		try
		{
			num = FromString<u64>(str);
			return num;
		}
		catch (const std::exception &) { }

		smatch m;
		std::string suffix;
		if (regex_search(str, m, regex(std::string("^(\\d+)") + "([" + Suffixes + "])$")))
		{
			num = FromString<u64>(m[1]);
			suffix = FromString<std::string>(m[2]);

			for (size_t i = 0; i < Suffixes.size(); ++i)
				if (suffix[0] == Suffixes[i])
					return num * ((u64)1 << 10 * (i + 1));
		}

		STINGRAYKIT_THROW(FormatException(str));
	}

}
<commit_msg>removed redundant newline<commit_after>#include <stingraykit/string/HumanReadableSize.h>
#include <stingraykit/string/ToString.h>
#include <stingraykit/string/regex.h>

namespace stingray
{

	namespace
	{

		const std::string Suffixes("kMGTPEZ");

	}

	std::string ToHumanReadableSize(u64 size)
	{
		for (size_t i = 0; i < Suffixes.size(); ++i)
		{
			u64 classToCompare = (u64)1 << 10 * (i + 1);
			u64 remainder = size % classToCompare;
			size_t classModifier = remainder > 0 ? 1 : 0;
			size_t roundModifier = remainder >= classToCompare / 2 ? 1 : 0;
			if (size < (u64)1 << 10 * (i + 1 + classModifier))
			{
				u64 result = size / ((u64)1 << 10 * i) + roundModifier;
				if (i > 0)
					return ToString(result) + Suffixes[i - 1];
				else
					return ToString(result);
			}
		}

		return ToString(size);
	}

	u64 FromHumanReadableSize(const std::string& str)
	{
		u64 num;
		try
		{
			num = FromString<u64>(str);
			return num;
		}
		catch (const std::exception &) { }

		smatch m;
		std::string suffix;
		if (regex_search(str, m, regex(std::string("^(\\d+)") + "([" + Suffixes + "])$")))
		{
			num = FromString<u64>(m[1]);
			suffix = FromString<std::string>(m[2]);

			for (size_t i = 0; i < Suffixes.size(); ++i)
				if (suffix[0] == Suffixes[i])
					return num * ((u64)1 << 10 * (i + 1));
		}

		STINGRAYKIT_THROW(FormatException(str));
	}

}
<|endoftext|>


<commit_before><commit_msg>almost complete bls<commit_after><|endoftext|>


<commit_before><commit_msg>versao final do metodo de pre_processamento (ainda nao comentado)<commit_after><|endoftext|>


<commit_before><commit_msg>[RPC] Remove warning about wallet addresses in createmultisig()<commit_after><|endoftext|>


<commit_before><commit_msg>warning C4800: 'unsigned long' : forcing value to bool 'true' or 'false'<commit_after><|endoftext|>


<commit_before>#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

#include "cache.h"

//#define USE_PROCESS

#define NUM_PAGES 16384
#define NUM_THREADS 32
enum {
	NORMAL,
	DIRECT,
	MMAP,
};

int cache_hits;
off_t *offset;
int flags = O_RDONLY;
int npages;
int nthreads;
struct timeval global_start;
char static_buf[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
volatile int first[NUM_THREADS];

void permute_offset(off_t *offset, int num)
{
	int i;
	for (i = num - 1; i >= 1; i--) {
		int j = random() % i;
		off_t tmp = offset[j];
		offset[j] = offset[i];
		offset[i] = tmp;
	}
}

float time_diff(struct timeval time1, struct timeval time2)
{
	return time2.tv_sec - time1.tv_sec
			+ ((float)(time2.tv_usec - time1.tv_usec))/1000000;
}

/* this data structure stores the thread-private info. */
class thread_private
{
public:
#ifdef USE_PROCESS
	pid_t id;
#else
	pthread_t id;
#endif
	/* the location in the thread descriptor array. */
	int idx;
	/* where the data read from the disk is stored */
	char *buf;
	/* shows the locations in the array where data has be to stored.*/
	off_t *buf_offset;

	/* the range in the file where we need to read data. */
	int start_i;
	int end_i;

	virtual ssize_t access(char *, off_t, ssize_t) = 0;
	virtual int thread_init() = 0;

	thread_private(int idx) {
		this->idx = idx;
		buf = (char *) valloc(PAGE_SIZE * (NUM_PAGES / nthreads));
		buf_offset = (off_t *) malloc(sizeof (*buf_offset) * NUM_PAGES / nthreads);

		if (buf == NULL){
			fprintf(stderr, "can't allocate buffer\n");
			exit(1);
		}
		/* trigger page faults and bring pages to memory. */
		for (int i = 0; i < NUM_PAGES / nthreads; i++)
			buf[i * PAGE_SIZE] = 0;

		for (int i = 0; i < NUM_PAGES / nthreads; i++)
			buf_offset[i] = i;
		permute_offset(buf_offset, NUM_PAGES / nthreads);
	}
};

class read_private: public thread_private
{
	char *file_name;
	int fd;
public:
	read_private(char *name, int idx): thread_private(idx) {
		file_name = name;
	}

	int thread_init() {
		int ret;

		fd = open(file_name, flags);
		if (fd < 0) {
			perror("open");
			exit (1);
		}
		ret = posix_fadvise(fd, start_i,
				end_i, POSIX_FADV_RANDOM);
		if (ret < 0) {
			perror("posix_fadvise");
			exit(1);
		}
		return 0;
	}

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		off_t ret = lseek(fd, offset, SEEK_SET);
		if (ret < 0) {
			perror("lseek");
			printf("%ld\n", offset);
			exit(1);
		}
		ret = read(fd, buf, size);
		return ret;
	}
};

class mmap_private: public thread_private
{
	void *addr;

public:
	mmap_private(char *new_name, int idx): thread_private(idx) {
		static void *addr = NULL;
		static char *file_name = NULL;
		/* if we are mapping to a different file, do the real mapping. */
		if (file_name == NULL || strcmp(file_name, new_name)) {
			int fd = open(new_name, flags);
			int ret;

			if (fd < 0) {
				perror("open");
				exit (1);
			}
			addr = mmap(NULL, ((ssize_t) npages) * PAGE_SIZE,
					PROT_READ, MAP_PRIVATE, fd, 0);
			if (addr == NULL) {
				perror("mmap");
				exit(1);
			}
			ret = madvise(addr, ((ssize_t) npages) * PAGE_SIZE, MADV_RANDOM);
			if (ret < 0) {
				perror("madvise");
				exit(1);
			}
			file_name = new_name;
		}
		this->addr = addr;
	}

	int thread_init() {
		return 0;
	}

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		int i;
		char *page = (char *) addr + offset;
		/* I try to avoid gcc optimization eliminating the code below,
		 * and it works. */
		first[idx] = page[0];
		__asm__ __volatile__("" : : "g"(&first[idx]));
		return size;
	}
};

class part_cached_private: public read_private
{
	page_cache *cache;

public:
	part_cached_private(char *name, int idx): read_private(name, idx) { }

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		ssize_t ret = cache->get_from_cache(buf, offset, size);
		if (ret < 0) {
			struct page *p = cache->get_empty_page(offset);
			ret = read_private::access((char *) p->get_data(),
					ROUND_PAGE(offset), PAGE_SIZE);
			if (ret < 0) {
				perror("read");
				exit(1);
			}
			p->set_offset(offset);
			offset -= ROUND_PAGE(offset);
			/* I assume the data I read never crosses the page boundary */
			memcpy(buf, (char *) p->get_data() + offset, size);
		}
		else
			cache_hits++;
		return ret;
	}
};

class global_cached_private: public read_private
{
	page_cache *cache;
public:
	global_cached_private(char *name, int idx): read_private(name, idx) { }

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		return 0;
	}
};

thread_private *threads[NUM_THREADS];

void *rand_read(void *arg)
{
	ssize_t ret;
	int i, j, start_i, end_i;
	ssize_t read_bytes = 0;
	struct timeval start_time, end_time;
	thread_private *priv = threads[(long) arg];
	char *buf;
	off_t *buf_offset;
	int fd;

	priv->thread_init();
	start_i = priv->start_i;
	end_i = priv->end_i;
	buf = priv->buf;
	buf_offset = priv->buf_offset;

	gettimeofday(&start_time, NULL);
	for (i = start_i, j = 0; i < end_i; i++, j++) {
		if (j == NUM_PAGES / nthreads)
			j = 0;
		ret = priv->access(buf + buf_offset[j] * PAGE_SIZE,
				offset[i], PAGE_SIZE);
		if (ret > 0)
			read_bytes += ret;
		else
			break;
	}
	if (ret < 0) {
		perror("read");
		exit(1);
	}
	gettimeofday(&end_time, NULL);
	printf("read %ld bytes, start at %f seconds, takes %f seconds\n",
			read_bytes, time_diff(global_start, start_time),
			time_diff(start_time, end_time));

#ifdef USE_PROCESS
	exit(read_bytes);
#else
	pthread_exit((void *) read_bytes);
#endif
}

int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}

enum {
	READ_ACCESS,
	MMAP_ACCESS,
	LOCAL_CACHE_ACCESS,
	GLOBAL_CACHE_ACCESS
};

int main(int argc, char *argv[])
{
	int cache_size = 512 * 1024 * 1024;
	int access_options;
	int ret;
	int i, j;
	struct timeval start_time, end_time;
	ssize_t read_bytes = 0;
	int is_mmap = 0;
	int num_files = 0;
	char *file_names[NUM_THREADS];

	if (argc < 5) {
		fprintf(stderr, "read files option num_pages num_threads\n");
		exit(1);
	}

	switch (atoi(argv[argc - 3])) {
		case NORMAL:
			access_options = READ_ACCESS;
			break;
		case DIRECT:
			flags |= O_DIRECT;
			access_options = READ_ACCESS;
			break;
		case MMAP:
			is_mmap = 1;
			access_options = MMAP_ACCESS;
			break;
		default:
			fprintf(stderr, "wrong option\n");
			exit(1);
	}
	num_files = argc - 4;
	for (i = 0; i < num_files; i++) {
		file_names[i] = argv[1 + i];
	}

	npages = atoi(argv[argc - 2]);
	offset = (off_t *) malloc(sizeof(*offset) * npages);
	for(i = 0; i < npages; i++) {
		offset[i] = ((off_t) i) * 4096L;
		if (offset[i] < 0) {
			printf("offset[%d]: %ld\n", i, offset[i]);
			exit(1);
		}
	}
	permute_offset(offset, npages);

	nthreads = atoi(argv[argc - 1]);
	if (nthreads > NUM_THREADS) {
		fprintf(stderr, "too many threads\n");
		exit(1);
	}
	if (num_files > 1 && num_files != nthreads) {
		fprintf(stderr, "if there are multiple files, \
				the number of files must be the same as the number of threads\n");
		exit(1);
	}

	/* initialize the threads' private data. */
	for (j = 0; j < nthreads; j++) {
		char *file_name;
		if (num_files > 1) {
			file_name = file_names[j];
		}
		else {
			file_name = file_names[0];
		}
		switch (access_options) {
			case READ_ACCESS:
				threads[j] = new read_private(file_name, j);
				break;
			case MMAP_ACCESS:
				threads[j] = new mmap_private(file_name, j);
				break;
			case LOCAL_CACHE_ACCESS:
				threads[j] = new part_cached_private(file_name, j);
				break;
			case GLOBAL_CACHE_ACCESS:
				threads[j] = new global_cached_private(file_name, j);
				break;
			default:
				fprintf(stderr, "wrong access option\n");
				exit(1);
		}

		if (num_files > 1) {
			threads[j]->start_i = 0;
			threads[j]->end_i = npages;
		}
		else {
			threads[j]->start_i = npages / nthreads * j;
			threads[j]->end_i = threads[j]->start_i + npages / nthreads;
		}
	}

	ret = setpriority(PRIO_PROCESS, getpid(), -20);
	if (ret < 0) {
		perror("setpriority");
		exit(1);
	}

	gettimeofday(&start_time, NULL);
	global_start = start_time;
	for (i = 0; i < nthreads; i++) {
#ifdef USE_PROCESS
		ret = process_create(&threads[i]->id, rand_read, (void *) i);
#else
		ret = pthread_create(&threads[i]->id, NULL, rand_read, (void *) i);
#endif
		if (ret) {
			perror("pthread_create");
			exit(1);
		}
	}

	for (i = 0; i < nthreads; i++) {
		ssize_t size;
#ifdef USE_PROCESS
		ret = process_join(threads[i]->id);
#else
		ret = pthread_join(threads[i]->id, (void **) &size);
#endif
		if (ret) {
			perror("pthread_join");
			exit(1);
		}
		read_bytes += size;
	}
	gettimeofday(&end_time, NULL);
	printf("read %ld bytes, takes %f seconds\n",
			read_bytes, end_time.tv_sec - start_time.tv_sec
			+ ((float)(end_time.tv_usec - start_time.tv_usec))/1000000);
	printf("there are %d cache hits\n", cache_hits);
}
<commit_msg>make options more extensible.<commit_after>#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

#include <iostream>
#include <string>

#include "cache.h"

//#define USE_PROCESS

#define NUM_PAGES 16384
#define NUM_THREADS 32
enum {
	NORMAL,
	DIRECT,
	MMAP,
};

int cache_hits;
off_t *offset;
int npages;
int nthreads = 1;
struct timeval global_start;
char static_buf[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE)));
volatile int first[NUM_THREADS];

void permute_offset(off_t *offset, int num)
{
	int i;
	for (i = num - 1; i >= 1; i--) {
		int j = random() % i;
		off_t tmp = offset[j];
		offset[j] = offset[i];
		offset[i] = tmp;
	}
}

float time_diff(struct timeval time1, struct timeval time2)
{
	return time2.tv_sec - time1.tv_sec
			+ ((float)(time2.tv_usec - time1.tv_usec))/1000000;
}

/* this data structure stores the thread-private info. */
class thread_private
{
public:
#ifdef USE_PROCESS
	pid_t id;
#else
	pthread_t id;
#endif
	/* the location in the thread descriptor array. */
	int idx;
	/* where the data read from the disk is stored */
	char *buf;
	/* shows the locations in the array where data has be to stored.*/
	off_t *buf_offset;

	/* the range in the file where we need to read data. */
	int start_i;
	int end_i;

	virtual ssize_t access(char *, off_t, ssize_t) = 0;
	virtual int thread_init() = 0;

	thread_private(int idx) {
		this->idx = idx;
		buf = (char *) valloc(PAGE_SIZE * (NUM_PAGES / nthreads));
		buf_offset = (off_t *) malloc(sizeof (*buf_offset) * NUM_PAGES / nthreads);

		if (buf == NULL){
			fprintf(stderr, "can't allocate buffer\n");
			exit(1);
		}
		/* trigger page faults and bring pages to memory. */
		for (int i = 0; i < NUM_PAGES / nthreads; i++)
			buf[i * PAGE_SIZE] = 0;

		for (int i = 0; i < NUM_PAGES / nthreads; i++)
			buf_offset[i] = i;
		permute_offset(buf_offset, NUM_PAGES / nthreads);
	}
};

class read_private: public thread_private
{
	const char *file_name;
	int fd;
	int flags;
public:
	read_private(const char *name, int idx, int flags = O_RDONLY): thread_private(idx), file_name(name) {
		this->flags = flags;
	}

	int thread_init() {
		int ret;

		fd = open(file_name, flags);
		if (fd < 0) {
			perror("open");
			exit (1);
		}
		ret = posix_fadvise(fd, start_i,
				end_i, POSIX_FADV_RANDOM);
		if (ret < 0) {
			perror("posix_fadvise");
			exit(1);
		}
		return 0;
	}

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		off_t ret = lseek(fd, offset, SEEK_SET);
		if (ret < 0) {
			perror("lseek");
			printf("%ld\n", offset);
			exit(1);
		}
		ret = read(fd, buf, size);
		return ret;
	}
};

class direct_private: public read_private
{
public:
	direct_private(const char *name, int idx): read_private(name, idx,
			O_DIRECT | O_RDONLY) {}
};

class mmap_private: public thread_private
{
	void *addr;

public:
	mmap_private(const char *new_name, int idx): thread_private(idx) {
		static void *addr = NULL;
		static const char *file_name = NULL;
		/* if we are mapping to a different file, do the real mapping. */
		if (file_name == NULL || strcmp(file_name, new_name)) {
			int fd = open(new_name, O_RDONLY);
			int ret;

			if (fd < 0) {
				perror("open");
				exit (1);
			}
			addr = mmap(NULL, ((ssize_t) npages) * PAGE_SIZE,
					PROT_READ, MAP_PRIVATE, fd, 0);
			if (addr == NULL) {
				perror("mmap");
				exit(1);
			}
			ret = madvise(addr, ((ssize_t) npages) * PAGE_SIZE, MADV_RANDOM);
			if (ret < 0) {
				perror("madvise");
				exit(1);
			}
			file_name = new_name;
		}
		this->addr = addr;
	}

	int thread_init() {
		return 0;
	}

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		int i;
		char *page = (char *) addr + offset;
		/* I try to avoid gcc optimization eliminating the code below,
		 * and it works. */
		first[idx] = page[0];
		__asm__ __volatile__("" : : "g"(&first[idx]));
		return size;
	}
};

class part_cached_private: public direct_private
{
	page_cache *cache;

public:
	part_cached_private(const char *name, int idx): direct_private(name, idx) {
	}

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		ssize_t ret = cache->get_from_cache(buf, offset, size);
		if (ret < 0) {
			struct page *p = cache->get_empty_page(offset);
			ret = read_private::access((char *) p->get_data(),
					ROUND_PAGE(offset), PAGE_SIZE);
			if (ret < 0) {
				perror("read");
				exit(1);
			}
			p->set_offset(offset);
			offset -= ROUND_PAGE(offset);
			/* I assume the data I read never crosses the page boundary */
			memcpy(buf, (char *) p->get_data() + offset, size);
		}
		else
			cache_hits++;
		return ret;
	}
};

class global_cached_private: public direct_private
{
	page_cache *cache;
public:
	global_cached_private(const char *name, int idx): direct_private(name, idx) { }

	ssize_t access(char *buf, off_t offset, ssize_t size) {
		return 0;
	}
};

thread_private *threads[NUM_THREADS];

void *rand_read(void *arg)
{
	ssize_t ret;
	int i, j, start_i, end_i;
	ssize_t read_bytes = 0;
	struct timeval start_time, end_time;
	thread_private *priv = threads[(long) arg];
	char *buf;
	off_t *buf_offset;
	int fd;

	priv->thread_init();
	start_i = priv->start_i;
	end_i = priv->end_i;
	buf = priv->buf;
	buf_offset = priv->buf_offset;

	gettimeofday(&start_time, NULL);
	for (i = start_i, j = 0; i < end_i; i++, j++) {
		if (j == NUM_PAGES / nthreads)
			j = 0;
		ret = priv->access(buf + buf_offset[j] * PAGE_SIZE,
				offset[i], PAGE_SIZE);
		if (ret > 0)
			read_bytes += ret;
		else
			break;
	}
	if (ret < 0) {
		perror("read");
		exit(1);
	}
	gettimeofday(&end_time, NULL);
	printf("read %ld bytes, start at %f seconds, takes %f seconds\n",
			read_bytes, time_diff(global_start, start_time),
			time_diff(start_time, end_time));

#ifdef USE_PROCESS
	exit(read_bytes);
#else
	pthread_exit((void *) read_bytes);
#endif
}

int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}

enum {
	READ_ACCESS,
	DIRECT_ACCESS,
	MMAP_ACCESS,
	LOCAL_CACHE_ACCESS,
	GLOBAL_CACHE_ACCESS
};

struct access_method {
	std::string name;
	int access;
} methods[] = {
	"normal", READ_ACCESS,
	"direct", DIRECT_ACCESS,
	"mmap", MMAP_ACCESS,
	"local_cache", LOCAL_CACHE_ACCESS,
	"global_cache", GLOBAL_CACHE_ACCESS
};

void print_methods() {
	std::cout<<"available methods: ";
	int num_methods = sizeof(methods) / sizeof(methods[0]);
	for (int i = 0; i < num_methods; i++) {
		std::cout<<methods[i].name;
		if (i < num_methods - 1)
			std::cout<<", ";
	}
	std::cout<<std::endl;
}

int map_method(const std::string &method)
{
	int num_methods = sizeof(methods) / sizeof(methods[0]);
	for (int i = 0; i < num_methods; i++) {
		if (methods[i].name.compare(method) == 0)
			return i;
	}
	return -1;
}

int main(int argc, char *argv[])
{
	int cache_size = 512 * 1024 * 1024;
	int entry_size = 128;
	int access_option;
	int ret;
	int i, j;
	struct timeval start_time, end_time;
	ssize_t read_bytes = 0;
	int num_files = 0;
	std::string file_names[NUM_THREADS];

	if (argc < 5) {
		fprintf(stderr, "read files option pages threads cache_size entry_size\n");
		print_methods();
		exit(1);
	}

	for (int i = 1; i < argc; i++) {
		std::string str = argv[i];
		size_t found = str.find("=");
		/* if there isn't `=', I assume it's a file name*/
		if (found == std::string::npos) {
			file_names[num_files++] = str;
			continue;
		}

		std::string value = str.substr(found + 1);
		std::string key = str.substr(0, found);
		if (key.compare("option") == 0) {
			access_option = map_method(value);
			if (access_option < 0) {
				fprintf(stderr, "can't find the right option\n");
				exit(1);
			}
		}
		else if(key.compare("pages") == 0) {
			npages = atoi(value.c_str());
		}
		else if(key.compare("threads") == 0) {
			nthreads = atoi(value.c_str());
		}
		else if(key.compare("cache_size") == 0) {
			cache_size = atoi(value.c_str());
		}
		else if(key.compare("entry_size") == 0) {
			entry_size = atoi(value.c_str());
		}
		else {
			fprintf(stderr, "wrong option\n");
			exit(1);
		}
	}

	offset = (off_t *) malloc(sizeof(*offset) * npages);
	for(i = 0; i < npages; i++) {
		offset[i] = ((off_t) i) * 4096L;
		if (offset[i] < 0) {
			printf("offset[%d]: %ld\n", i, offset[i]);
			exit(1);
		}
	}
	permute_offset(offset, npages);

	if (nthreads > NUM_THREADS) {
		fprintf(stderr, "too many threads\n");
		exit(1);
	}
	if (num_files > 1 && num_files != nthreads) {
		fprintf(stderr, "if there are multiple files, \
				the number of files must be the same as the number of threads\n");
		exit(1);
	}

	/* initialize the threads' private data. */
	for (j = 0; j < nthreads; j++) {
		const char *file_name;
		if (num_files > 1) {
			file_name = file_names[j].c_str();
		}
		else {
			file_name = file_names[0].c_str();
		}
		switch (access_option) {
			case READ_ACCESS:
				threads[j] = new read_private(file_name, j);
				break;
			case DIRECT_ACCESS:
				threads[j] = new direct_private(file_name, j);
				break;
			case MMAP_ACCESS:
				threads[j] = new mmap_private(file_name, j);
				break;
			case LOCAL_CACHE_ACCESS:
				threads[j] = new part_cached_private(file_name, j);
				break;
			case GLOBAL_CACHE_ACCESS:
				threads[j] = new global_cached_private(file_name, j);
				break;
			default:
				fprintf(stderr, "wrong access option\n");
				exit(1);
		}

		if (num_files > 1) {
			threads[j]->start_i = 0;
			threads[j]->end_i = npages;
		}
		else {
			threads[j]->start_i = npages / nthreads * j;
			threads[j]->end_i = threads[j]->start_i + npages / nthreads;
		}
	}

	ret = setpriority(PRIO_PROCESS, getpid(), -20);
	if (ret < 0) {
		perror("setpriority");
		exit(1);
	}

	gettimeofday(&start_time, NULL);
	global_start = start_time;
	for (i = 0; i < nthreads; i++) {
#ifdef USE_PROCESS
		ret = process_create(&threads[i]->id, rand_read, (void *) i);
#else
		ret = pthread_create(&threads[i]->id, NULL, rand_read, (void *) i);
#endif
		if (ret) {
			perror("pthread_create");
			exit(1);
		}
	}

	for (i = 0; i < nthreads; i++) {
		ssize_t size;
#ifdef USE_PROCESS
		ret = process_join(threads[i]->id);
#else
		ret = pthread_join(threads[i]->id, (void **) &size);
#endif
		if (ret) {
			perror("pthread_join");
			exit(1);
		}
		read_bytes += size;
	}
	gettimeofday(&end_time, NULL);
	printf("read %ld bytes, takes %f seconds\n",
			read_bytes, end_time.tv_sec - start_time.tv_sec
			+ ((float)(end_time.tv_usec - start_time.tv_usec))/1000000);
	printf("there are %d cache hits\n", cache_hits);
}
<|endoftext|>