<commit_before>// Copyright Hugh Perkins 2016

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cocl/cocl_events.h"

#include "cocl/cocl_error.h"
#include "cocl/cocl_defs.h"
#include "cocl/hostside_opencl_funcs.h"
#include "cocl/cocl_streams.h"
#include "cocl/cocl_context.h"

#include "EasyCL/EasyCL.h"

#include "pthread.h"

#include <iostream>
#include <memory>

using namespace std;
using namespace cocl;
using namespace easycl;

#ifdef COCL_PRINT
#undef COCL_PRINT
#endif

#ifdef COCL_SPAM_EVENTS
#define COCL_PRINT(x) std::cout << "[EVT] " << x << std::endl;
#else
#define COCL_PRINT(x)
#endif

// I guess that events should only be called from a single thread, so there might
// be a bug elesewhere, but in the meantime, the events are being called in parallel, from
// mutliple threads, which crasehs stuff. lets try using a mutex to "fix" this for now
static pthread_mutex_t cocl_events_mutex = PTHREAD_MUTEX_INITIALIZER;

namespace cocl {
    CoclEvent::CoclEvent() {
        COCL_PRINT("CoclEvent() this=" << this);
        event = 0;
    }
    CoclEvent::~CoclEvent() {
        COCL_PRINT("~CoclEvent() this=" << this);
        if(event != 0) {
            COCL_PRINT("~CoclEvent() releasing underlying clevent " << event);
            cl_int err = clReleaseEvent(event);
            EasyCL::checkError(err);
        }
    }
    // bool CoclEvent::has_event() {
    //     bool res = event != 0;
    //     return res;
    // }
}

size_t cuStreamWaitEvent(char *_queue, CoclEvent *event, unsigned int flags) {
    pthread_mutex_lock(&cocl_events_mutex);
    CoclStream *stream = (CoclStream *)_queue;
    // StreamLock streamlock(stream);
    CLQueue *queue = stream->clqueue;
    // CLQueue *queue = (CLQueue*)_queue;
    // COCL_PRINT(cout << "cuStreamWaitEvent redirected queue=" << queue << " event=" << event << " flags=" << flags << endl);
    if(queue == 0) {
        cout << "cuStreamWaitEvent stream==0 not implemented" << std::endl;
        throw runtime_error("cuStreamWaitEvent stream==0 not implemented");
    }

    // I think what cuStreamWaitEvent does is:
    // - add something to the queue, some marker/barrier
    // - anything added to the queue after this will NOT start executing
    // - until the event given to cuStreamWaitEvent is marked as finished
    //
    // I think that with clWaitForEvents, we can give a list of cl events to wait on,
    // but its the *host* thread that waits, ie the call is blocking
    // I think that cuStreamWaitEvent is not actually a blocking call, for the host, its more like
    // some kind of barrier

    // I think waht we plausibly need is clEnqueueBarrierWithWaitList
    // so lets try that...

    if(event->event == 0) {
        cerr << "cuStreamWaitEvent redirected: Warning: you havent Recorded on the event you passed in" << endl;
    } else {
        // cl_event clevent;
        clEnqueueBarrierWithWaitList(queue->queue,
            1,
            &event->event,
            0);
    }
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

// opencl:
// clCreateUserEvent()   CL_EVENT_COMMAND_ EXECUTION_STATUS
// clWaitForEvents(num_events, event_list);
// clEnqueueMarkerWithWaitList
// clGetEventInfo()
// clReleaseEvent

// cuda:
// cuEventCreate(CUCoclEvent *, flags)
// cuEventRecord(CUEvent, CUstream);  => puts into the stream
// cuEventQuery(CUevent)
// cuEventSynchronize(CUevent)
// cuEventDestroy

size_t cudaStreamWaitEvent(char *_queue, CoclEvent *event, unsigned int flags) {
    return cuStreamWaitEvent(_queue, event, flags);
}

size_t cuEventCreate(CoclEvent **pevent, unsigned int flags) {
    pthread_mutex_lock(&cocl_events_mutex);
    CoclEvent *event = new CoclEvent();
    *pevent = event;
    COCL_PRINT("cuEventCreate flags=" << flags << " new CoclEvent=" << event);
    // throw runtime_error("fake stop");
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventCreateWithFlags(CoclEvent **pevent, unsigned int flags) {
    return cuEventCreate(pevent, flags);
}

size_t cudaEventCreate(CoclEvent **pevent) {
    return cuEventCreate(pevent, 0);
}

size_t cuEventSynchronize(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventSynchronize CoclEvent=" << event);
    cl_int err = clWaitForEvents(1, &event->event);  // 1 is number of events, 2nd parameter is list of events
    EasyCL::checkError(err);
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaProfilerStop() {
    return 0;
}

size_t cudaEventElapsedTime(float *p_elapsedTime, cocl::CoclEvent *start, cocl::CoclEvent *stop) {
    *p_elapsedTime = 0.0f;
    return 0;
}

size_t cudaEventSynchronize(cocl::CoclEvent *event) {
    return cuEventSynchronize(event);
}

size_t cuEventRecord(CoclEvent *event, char *_queue) {
    pthread_mutex_lock(&cocl_events_mutex);
    CoclStream *coclStream = (CoclStream *)_queue;
    CLQueue *queue = coclStream->clqueue;
    // CLQueue *queue = (CLQueue *)_queue;
    COCL_PRINT("cuEventRecord CoclEvent=" << event << " queue=" << queue);
    if(queue == 0) {
        cout << "cuEventRecord not implemented for stream 0" << endl;
        throw runtime_error("cuEventRecord not implemented for stream 0");
    }
    cl_int err;
    err = clFlush(queue->queue);
    EasyCL::checkError(err);
    if(event->event != 0) {
        COCL_PRINT("  cuEventRecord releasing existing clevent " << event->event);
        err = clReleaseEvent(event->event);
        EasyCL::checkError(err);
        event->event = 0;
        // cout << "cuEventRecrd event is already assigned => error" << endl;
        // throw runtime_error("cuEventRecord: event is already assigned => error");
    }
    cl_event clevent;
    err = clEnqueueMarkerWithWaitList(queue->queue, 0, 0, &clevent);
    COCL_PRINT("cuEventRecord CoclEvent=" << event << " created clevent=" << clevent);
    EasyCL::checkError(err);
    err = clFlush(queue->queue);
    EasyCL::checkError(err);
    event->event = clevent;
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventRecord(cocl::CoclEvent *event, char *queue) {
    return cuEventRecord(event, queue);
}

size_t cuEventQuery(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventQuery CoclEvent=" << event << " clevent=" << event->event);
    cl_int res;
    cl_int err = clGetEventInfo (
        event->event,
        CL_EVENT_COMMAND_EXECUTION_STATUS,
        sizeof(cl_int),
        &res,
        0);
    COCL_PRINT("clGetEventInfo: " << res);
    EasyCL::checkError(err);
    pthread_mutex_unlock(&cocl_events_mutex);
    if(res == CL_COMPLETE) { // success
        COCL_PRINT("cuEventQuery, event completed");
        return 0;
    } else if(res > 0) { // not finished yet
        COCL_PRINT("cuEventQuery, event not finished yet");
        return cudaErrorNotReady;
    } else { // error
        COCL_PRINT("cuEventQuery, event error");
        return 1;
    }
}

size_t cuEventDestroy_v2(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventDestroy CoclEvent=" << event);
    // if(event->event != 0) {
    //     COCL_PRINT("cuEventDestory_v2: releasing event " << event->event);
    //     cu_int err = clReleaseEvent(event->event);
    //     EasyCL::checkError(err);
    // }
    delete event;
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventDestroy(CoclEvent *event) {
    return cuEventDestroy(event);
}
<commit_msg>fix bug in cocl_events.cpp so fill_copy_sequence does t at least run now<commit_after>// Copyright Hugh Perkins 2016

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cocl/cocl_events.h"

#include "cocl/cocl_error.h"
#include "cocl/cocl_defs.h"
#include "cocl/hostside_opencl_funcs.h"
#include "cocl/cocl_streams.h"
#include "cocl/cocl_context.h"

#include "EasyCL/EasyCL.h"

#include "pthread.h"

#include <iostream>
#include <memory>

using namespace std;
using namespace cocl;
using namespace easycl;

#ifdef COCL_PRINT
#undef COCL_PRINT
#endif

#ifdef COCL_SPAM_EVENTS
#define COCL_PRINT(x) std::cout << "[EVT] " << x << std::endl;
#else
#define COCL_PRINT(x)
#endif

// I guess that events should only be called from a single thread, so there might
// be a bug elesewhere, but in the meantime, the events are being called in parallel, from
// mutliple threads, which crasehs stuff. lets try using a mutex to "fix" this for now
static pthread_mutex_t cocl_events_mutex = PTHREAD_MUTEX_INITIALIZER;

namespace cocl {
    CoclEvent::CoclEvent() {
        COCL_PRINT("CoclEvent() this=" << this);
        event = 0;
    }
    CoclEvent::~CoclEvent() {
        COCL_PRINT("~CoclEvent() this=" << this);
        if(event != 0) {
            COCL_PRINT("~CoclEvent() releasing underlying clevent " << event);
            cl_int err = clReleaseEvent(event);
            EasyCL::checkError(err);
        }
    }
    // bool CoclEvent::has_event() {
    //     bool res = event != 0;
    //     return res;
    // }
}

size_t cuStreamWaitEvent(char *_queue, CoclEvent *event, unsigned int flags) {
    pthread_mutex_lock(&cocl_events_mutex);
    CoclStream *stream = (CoclStream *)_queue;
    // StreamLock streamlock(stream);
    CLQueue *queue = stream->clqueue;
    // CLQueue *queue = (CLQueue*)_queue;
    // COCL_PRINT(cout << "cuStreamWaitEvent redirected queue=" << queue << " event=" << event << " flags=" << flags << endl);
    if(queue == 0) {
        cout << "cuStreamWaitEvent stream==0 not implemented" << std::endl;
        throw runtime_error("cuStreamWaitEvent stream==0 not implemented");
    }

    // I think what cuStreamWaitEvent does is:
    // - add something to the queue, some marker/barrier
    // - anything added to the queue after this will NOT start executing
    // - until the event given to cuStreamWaitEvent is marked as finished
    //
    // I think that with clWaitForEvents, we can give a list of cl events to wait on,
    // but its the *host* thread that waits, ie the call is blocking
    // I think that cuStreamWaitEvent is not actually a blocking call, for the host, its more like
    // some kind of barrier

    // I think waht we plausibly need is clEnqueueBarrierWithWaitList
    // so lets try that...

    if(event->event == 0) {
        cerr << "cuStreamWaitEvent redirected: Warning: you havent Recorded on the event you passed in" << endl;
    } else {
        // cl_event clevent;
        clEnqueueBarrierWithWaitList(queue->queue,
            1,
            &event->event,
            0);
    }
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

// opencl:
// clCreateUserEvent()   CL_EVENT_COMMAND_ EXECUTION_STATUS
// clWaitForEvents(num_events, event_list);
// clEnqueueMarkerWithWaitList
// clGetEventInfo()
// clReleaseEvent

// cuda:
// cuEventCreate(CUCoclEvent *, flags)
// cuEventRecord(CUEvent, CUstream);  => puts into the stream
// cuEventQuery(CUevent)
// cuEventSynchronize(CUevent)
// cuEventDestroy

size_t cudaStreamWaitEvent(char *_queue, CoclEvent *event, unsigned int flags) {
    return cuStreamWaitEvent(_queue, event, flags);
}

size_t cuEventCreate(CoclEvent **pevent, unsigned int flags) {
    pthread_mutex_lock(&cocl_events_mutex);
    CoclEvent *event = new CoclEvent();
    *pevent = event;
    COCL_PRINT("cuEventCreate flags=" << flags << " new CoclEvent=" << event);
    // throw runtime_error("fake stop");
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventCreateWithFlags(CoclEvent **pevent, unsigned int flags) {
    return cuEventCreate(pevent, flags);
}

size_t cudaEventCreate(CoclEvent **pevent) {
    return cuEventCreate(pevent, 0);
}

size_t cuEventSynchronize(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventSynchronize CoclEvent=" << event);
    cl_int err = clWaitForEvents(1, &event->event);  // 1 is number of events, 2nd parameter is list of events
    EasyCL::checkError(err);
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaProfilerStop() {
    return 0;
}

size_t cudaEventElapsedTime(float *p_elapsedTime, cocl::CoclEvent *start, cocl::CoclEvent *stop) {
    *p_elapsedTime = 0.0f;
    return 0;
}

size_t cudaEventSynchronize(cocl::CoclEvent *event) {
    return cuEventSynchronize(event);
}

size_t cuEventRecord(CoclEvent *event, char *_queue) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventRecord CoclEvent=" << (long)event << " _queue=" << (long)_queue);
    CoclStream *coclStream = (CoclStream *)_queue;

    ThreadVars *v = getThreadVars();
    // EasyCL *cl = v->getContext()->getCl();
    if(coclStream == 0) {
        coclStream = v->currentContext->default_stream.get();
    }
    CLQueue *queue = coclStream->clqueue;
    COCL_PRINT("  cuEventRecord queue=" << queue);
    // CLQueue *queue = (CLQueue *)_queue;
    if(queue == 0) {
        cout << "cuEventRecord not implemented for stream 0" << endl;
        throw runtime_error("cuEventRecord not implemented for stream 0");
    }
    cl_int err;
    err = clFlush(queue->queue);
    EasyCL::checkError(err);
    if(event->event != 0) {
        COCL_PRINT("  cuEventRecord releasing existing clevent " << event->event);
        err = clReleaseEvent(event->event);
        EasyCL::checkError(err);
        event->event = 0;
        // cout << "cuEventRecrd event is already assigned => error" << endl;
        // throw runtime_error("cuEventRecord: event is already assigned => error");
    }
    cl_event clevent;
    err = clEnqueueMarkerWithWaitList(queue->queue, 0, 0, &clevent);
    COCL_PRINT("cuEventRecord CoclEvent=" << event << " created clevent=" << clevent);
    EasyCL::checkError(err);
    err = clFlush(queue->queue);
    EasyCL::checkError(err);
    event->event = clevent;
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventRecord(cocl::CoclEvent *event, char *queue) {
    return cuEventRecord(event, queue);
}

size_t cuEventQuery(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventQuery CoclEvent=" << event << " clevent=" << event->event);
    cl_int res;
    cl_int err = clGetEventInfo (
        event->event,
        CL_EVENT_COMMAND_EXECUTION_STATUS,
        sizeof(cl_int),
        &res,
        0);
    COCL_PRINT("clGetEventInfo: " << res);
    EasyCL::checkError(err);
    pthread_mutex_unlock(&cocl_events_mutex);
    if(res == CL_COMPLETE) { // success
        COCL_PRINT("cuEventQuery, event completed");
        return 0;
    } else if(res > 0) { // not finished yet
        COCL_PRINT("cuEventQuery, event not finished yet");
        return cudaErrorNotReady;
    } else { // error
        COCL_PRINT("cuEventQuery, event error");
        return 1;
    }
}

size_t cuEventDestroy_v2(CoclEvent *event) {
    pthread_mutex_lock(&cocl_events_mutex);
    COCL_PRINT("cuEventDestroy CoclEvent=" << event);
    // if(event->event != 0) {
    //     COCL_PRINT("cuEventDestory_v2: releasing event " << event->event);
    //     cu_int err = clReleaseEvent(event->event);
    //     EasyCL::checkError(err);
    // }
    delete event;
    pthread_mutex_unlock(&cocl_events_mutex);
    return 0;
}

size_t cudaEventDestroy(CoclEvent *event) {
    return cuEventDestroy(event);
}
<|endoftext|>


<commit_before>/*
	Copyright (C) 2003-2013 by Kristina Simpson <sweet.kristas@gmail.com>

	This software is provided 'as-is', without any express or implied
	warranty. In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	   1. The origin of this software must not be misrepresented; you must not
	   claim that you wrote the original software. If you use this software
	   in a product, an acknowledgment in the product documentation would be
	   appreciated but is not required.

	   2. Altered source versions must be plainly marked as such, and must not be
	   misrepresented as being the original software.

	   3. This notice may not be removed or altered from any source
	   distribution.
*/

#pragma once

#include <string>
#include <vector>

#include "RenderFwd.hpp"

#include "xhtml_fwd.hpp"
#include "xhtml_node.hpp"
#include "css_styles.hpp"

namespace xhtml
{
	class ObjectProxy : public std::enable_shared_from_this<ObjectProxy>
	{
	public:
		explicit ObjectProxy(const AttributeMap& attributes);
		virtual void init() {}
		virtual void process(float dt) {}
		virtual KRE::SceneObjectPtr getRenderable() = 0;
		int width() const { return width_; }
		int height () const { return height_; }
		void setDimensions(int w, int h);
		rect getDimensions() { return rect(0, 0, width_, height_); }
		bool areDimensionsFixed() const { return dimensions_fixed_; }

		virtual bool mouseButtonUp(const point& p, int button, unsigned button_state, unsigned short ctrl_key_state) { return false; }
		virtual bool mouseButtonDown(const point& p, int button, unsigned button_state, unsigned short ctrl_key_state) { return false; }
		virtual bool mouseMove(const point& p, unsigned button_state, unsigned ctrl_key_state) { return false; }
		virtual bool keyDown(const point& p, const Keystate& keysym, bool pressed, bool repeat) { return false; }
		virtual bool keyUp(const point& p, const Keystate& keysym, bool pressed, bool repeat) { return false; }
	private:
		int width_;
		int height_;
		bool dimensions_fixed_;
	};

	typedef std::shared_ptr<ObjectProxy> ObjectProxyPtr;

	typedef std::function<ObjectProxyPtr(const AttributeMap& attributes)> object_create_fn;

	// XXX should cache class, id, xml:id, lang, dir in the class structure.
	class Element : public Node
	{
	public:
		virtual ~Element();
		static ElementPtr create(const std::string& name, WeakDocumentPtr owner=WeakDocumentPtr());
		std::string toString() const override;
		ElementId getElementId() const { return tag_; }
		const std::string& getTag() const override { return name_; }
		const std::string& getName() const { return name_; }
		bool hasTag(const std::string& tag) const { return tag == name_; }
		bool hasTag(ElementId tag) const { return tag == tag_; }

		static void registerObjectHandler(const std::string& content_type, object_create_fn fn);
	protected:
		explicit Element(ElementId id, const std::string& name, WeakDocumentPtr owner);
		std::string name_;
		ElementId tag_;
	};

	void add_custom_element(const std::string& e);

	struct ObjectProxyRegistrar
	{
		explicit ObjectProxyRegistrar(const std::string& type, object_create_fn fn)
		{
			Element::registerObjectHandler(type, fn);
		}
	};
}
<commit_msg>Fix ObjectProxy not having virtual destructor.<commit_after>/*
	Copyright (C) 2003-2013 by Kristina Simpson <sweet.kristas@gmail.com>

	This software is provided 'as-is', without any express or implied
	warranty. In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	   1. The origin of this software must not be misrepresented; you must not
	   claim that you wrote the original software. If you use this software
	   in a product, an acknowledgment in the product documentation would be
	   appreciated but is not required.

	   2. Altered source versions must be plainly marked as such, and must not be
	   misrepresented as being the original software.

	   3. This notice may not be removed or altered from any source
	   distribution.
*/

#pragma once

#include <string>
#include <vector>

#include "RenderFwd.hpp"

#include "xhtml_fwd.hpp"
#include "xhtml_node.hpp"
#include "css_styles.hpp"

namespace xhtml
{
	class ObjectProxy : public std::enable_shared_from_this<ObjectProxy>
	{
	public:
		explicit ObjectProxy(const AttributeMap& attributes);
		virtual ~ObjectProxy() {}
		virtual void init() {}
		virtual void process(float dt) {}
		virtual KRE::SceneObjectPtr getRenderable() = 0;
		int width() const { return width_; }
		int height () const { return height_; }
		void setDimensions(int w, int h);
		rect getDimensions() { return rect(0, 0, width_, height_); }
		bool areDimensionsFixed() const { return dimensions_fixed_; }

		virtual bool mouseButtonUp(const point& p, int button, unsigned button_state, unsigned short ctrl_key_state) { return false; }
		virtual bool mouseButtonDown(const point& p, int button, unsigned button_state, unsigned short ctrl_key_state) { return false; }
		virtual bool mouseMove(const point& p, unsigned button_state, unsigned ctrl_key_state) { return false; }
		virtual bool keyDown(const point& p, const Keystate& keysym, bool pressed, bool repeat) { return false; }
		virtual bool keyUp(const point& p, const Keystate& keysym, bool pressed, bool repeat) { return false; }
	private:
		int width_;
		int height_;
		bool dimensions_fixed_;
	};

	typedef std::shared_ptr<ObjectProxy> ObjectProxyPtr;

	typedef std::function<ObjectProxyPtr(const AttributeMap& attributes)> object_create_fn;

	// XXX should cache class, id, xml:id, lang, dir in the class structure.
	class Element : public Node
	{
	public:
		virtual ~Element();
		static ElementPtr create(const std::string& name, WeakDocumentPtr owner=WeakDocumentPtr());
		std::string toString() const override;
		ElementId getElementId() const { return tag_; }
		const std::string& getTag() const override { return name_; }
		const std::string& getName() const { return name_; }
		bool hasTag(const std::string& tag) const { return tag == name_; }
		bool hasTag(ElementId tag) const { return tag == tag_; }

		static void registerObjectHandler(const std::string& content_type, object_create_fn fn);
	protected:
		explicit Element(ElementId id, const std::string& name, WeakDocumentPtr owner);
		std::string name_;
		ElementId tag_;
	};

	void add_custom_element(const std::string& e);

	struct ObjectProxyRegistrar
	{
		explicit ObjectProxyRegistrar(const std::string& type, object_create_fn fn)
		{
			Element::registerObjectHandler(type, fn);
		}
	};
}
<|endoftext|>


<commit_before>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Connection::raw_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  int64_t server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    const ssize_t read_result = sftp_read(file, v.data(), v.size());
    sftp_close(file);

    if (seek_result < 0 || read_result != ssize_t(v.size()))
     throw Exception("Error during sftp_read");

    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done\n";

  return server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::retry
 ////////////////////////////////////////////////////////////////////////////
 (
  std::function<int64_t()> f
 )
 {
  while (true)
  {
   if (connection)
    try
    {
     return f();
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }

   while (true)
   {
    if (connection)
    {
     if (trace)
      std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

     std::this_thread::sleep_for(std::chrono::seconds(sleep_time));
    }

    if (trace)
     std::cerr << "Connecting... ";
    try
    {
     reset();
     if (trace)
      std::cerr << "Success!\n";
     break;
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  return retry
  (
   [&client_journal,this](){return connection->pull(client_journal);}
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::lock_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  return retry
  (
   [&client_journal,this](){return connection->lock_pull(client_journal);}
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  retry
  (
   [&client_journal,server_position,this]()->int64_t
   {
    connection->push_unlock(client_journal, server_position);
    return 0;
   }
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level)
 {
  retry([this]()->int64_t{return 0;});
 }
}

#endif
<commit_msg>fix SSH_Connection (big read + uninitialized sleep_time).<commit_after>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Connection::raw_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  int64_t server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    if (seek_result < 0)
    {
     sftp_close(file);
     throw Exception("Error while seeking");
    }

    ssize_t total_read = 0;

    while (total_read < ssize_t(v.size()))
    {
     const ssize_t read_result = sftp_read
     (
      file,
      &v[total_read],
      v.size() - total_read
     );

     if (read_result < 0)
     {
      sftp_close(file);
      throw Exception("Error during sftp_read");
     }

     total_read += read_result;
     if (trace)
      std::cerr << -read_result;
    }

    sftp_close(file);
    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << " done\n";

  return server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::retry
 ////////////////////////////////////////////////////////////////////////////
 (
  std::function<int64_t()> f
 )
 {
  while (true)
  {
   if (connection)
    try
    {
     return f();
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }

   while (true)
   {
    if (connection)
    {
     if (trace)
      std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

     std::this_thread::sleep_for(std::chrono::seconds(sleep_time));
    }

    if (trace)
     std::cerr << "Connecting... ";
    try
    {
     reset();
     if (trace)
      std::cerr << "Success!\n";
     break;
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  return retry
  (
   [&client_journal,this](){return connection->pull(client_journal);}
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Robust_Connection::lock_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  return retry
  (
   [&client_journal,this](){return connection->lock_pull(client_journal);}
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  retry
  (
   [&client_journal,server_position,this]()->int64_t
   {
    connection->push_unlock(client_journal, server_position);
    return 0;
   }
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level),
  sleep_time(10)
 {
  retry([this]()->int64_t{return 0;});
 }
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include "util.hpp"
#include "../arm/arm.hpp"
#include "../policy/policy.hpp"

namespace bandit{

class RoundwiseLog{
public:
  uint K, P, T, run;
  std::vector<std::vector<double> > roundwiseRewards;
  std::vector<std::vector<double> > roundwiseRegrets;
  RoundwiseLog(uint K, uint P, uint T): K(K), P(P), T(T) {
    roundwiseRewards = std::vector<std::vector<double> >(P, std::vector<double>(T, 0.0));
    roundwiseRegrets = std::vector<std::vector<double> >(P, std::vector<double>(T, 0.0));
    run=0;
  }
  //start new run
  void startRun(){
    run+=1;
  }
  //policy p at round t chose arm k and received reward r
  void record(uint p, uint t, uint k, double r, double regretDelta){
    roundwiseRewards[p][t]+=r;
    roundwiseRegrets[p][t]+=regretDelta;
  }
};

class RoundwiseLogWriter{
public:
  static void logWrite(RoundwiseLog &log,
       std::vector<std::string> armNames, std::vector<std::string> policyNames,
       uint T, std::string filename, bool rewardPlot=true, bool regretPlot=true){
    const uint K = armNames.size();
    const uint P = policyNames.size();
    std::ofstream ofs( filename );
    ofs << "#averaged result over " << log.run << " trials" << std::endl;
    for(uint i=0;i<K;++i){
      ofs << "#arm" << i << " " << armNames[i] << std::endl;
    }
    for(uint p=0;p<P;++p){
      ofs << "#policy " << p << " " << policyNames[p] << std::endl;
    }
    ofs.setf(std::ios::fixed, std::ios::floatfield);

    ofs << "#results:" << std::endl;
    ofs << "#T" ;
    for(uint p=0;p<P;++p){
      if(rewardPlot){
        ofs << " reward" << p;
      }
      if(regretPlot){
        ofs << " regret" << p ;
      }
    }
    ofs << std::endl;
    std::vector<double> cumulatedRewards(P, 0.0);
    std::vector<double> cumulatedRegrets(P, 0.0);
    for(uint t=0;t<T;++t){
      ofs << (t+1);
      for(uint p=0;p<P;++p){
        cumulatedRewards[p]+=log.roundwiseRewards[p][t];
        cumulatedRegrets[p]+=log.roundwiseRegrets[p][t];
        if(rewardPlot){
          ofs << std::setprecision(2) << " " << cumulatedRewards[p]/log.run;
        }
        if(regretPlot){
          ofs << std::setprecision(2) << " " << cumulatedRegrets[p]/log.run ;
        }
      }
      ofs << std::endl;
    }
  }
};

} //namespace
<commit_msg>commit test<commit_after>#pragma once

#include "util.hpp"
#include "../arm/arm.hpp"
#include "../policy/policy.hpp"

namespace bandit{

class RoundwiseLog{
public:
  uint K, P, T, run;
  std::vector<std::vector<double> > roundwiseRewards;
  std::vector<std::vector<double> > roundwiseRegrets;
  RoundwiseLog(uint K, uint P, uint T): K(K), P(P), T(T) {
    roundwiseRewards = std::vector<std::vector<double> >(P, std::vector<double>(T, 0.0));
    roundwiseRegrets = std::vector<std::vector<double> >(P, std::vector<double>(T, 0.0));
    run=0;
  }
  //start new run
  void startRun(){
    run+=1;
  }
  //policy p at round t chose arm k and received reward r
  void record(uint p, uint t, uint k, double r, double regretDelta){
    roundwiseRewards[p][t]+=r;
    roundwiseRegrets[p][t]+=regretDelta;
  }
};

class RoundwiseLogWriter{
public:
  static void logWrite(RoundwiseLog &log,
       std::vector<std::string> armNames, std::vector<std::string> policyNames,
       uint T, std::string filename, bool rewardPlot=true, bool regretPlot=true){
    const uint K = armNames.size();
    const uint P = policyNames.size();
    std::ofstream ofs( filename );
    ofs << "#averaged result over " << log.run << " trials" << std::endl;
    for(uint i=0;i<K;++i){
      ofs << "#arm" << i << " " << armNames[i] << std::endl;
    }
    for(uint p=0;p<P;++p){
      ofs << "#policy " << p << " " << policyNames[p] << std::endl;
    }
    ofs.setf(std::ios::fixed, std::ios::floatfield);

    ofs << "#results:" << std::endl;
    ofs << "#T" ;
    for(uint p=0;p<P;++p){
      if(rewardPlot){
        ofs << " reward" << p;
      }
      if(regretPlot){
        ofs << " regret" << p ;
      }
    }
    ofs << std::endl;
    std::vector<double> cumulatedRewards(P, 0.0);
    std::vector<double> cumulatedRegrets(P, 0.0);
    for(uint t=0;t<T;++t){
      ofs << (t+1);
      for(uint p=0;p<P;++p){
        cumulatedRewards[p]+=log.roundwiseRewards[p][t];
        cumulatedRegrets[p]+=log.roundwiseRegrets[p][t];
        if(rewardPlot){
          ofs << std::setprecision(2) << " " << cumulatedRewards[p]/log.run;
        }
        if(regretPlot){
          ofs << std::setprecision(2) << " " << cumulatedRegrets[p]/log.run ;
        }
      }
      ofs << std::endl;
    }
  }
};

} //namespace
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2008 Thomas Thrainer <tom_t@gmx.at>

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

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

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

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include <KDebug>

#include "kotodoviewsortfilterproxymodel.h"

#include "kotodomodel.h"

#include <QModelIndex>

KOTodoViewSortFilterProxyModel::KOTodoViewSortFilterProxyModel( QObject *parent )
  : QSortFilterProxyModel( parent )
{
}

bool KOTodoViewSortFilterProxyModel::filterAcceptsRow(
                  int source_row, const QModelIndex &source_parent ) const
{
  bool ret = QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );

  if ( ret && !mCategories.isEmpty() ) {
    QStringList categories = sourceModel()->index( source_row, KOTodoModel::CategoriesColumn, source_parent )
                                              .data( Qt::EditRole ).toStringList();
    foreach ( const QString &category, categories ) {
      if ( mCategories.contains(category) ) return true;
    }
    ret = false;
  }

  // check if one of the children is accepted, and accept this node too if so
  QModelIndex cur = sourceModel()->index( source_row, KOTodoModel::SummaryColumn,
                                          source_parent );
  for ( int r = 0; r < cur.model()->rowCount( cur ); ++r ) {
    if ( filterAcceptsRow( r, cur ) ) return true;
  }

  return ret;
}

void KOTodoViewSortFilterProxyModel::setCategoryFilter( const QStringList &categories )
{
  mCategories = categories;
  invalidateFilter();
}

#include "kotodoviewsortfilterproxymodel.moc"
<commit_msg>my own header first. SVN_SILENT:<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2008 Thomas Thrainer <tom_t@gmx.at>

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

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

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

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "kotodoviewsortfilterproxymodel.h"
#include "kotodomodel.h"

#include <KDebug>
#include <QModelIndex>

KOTodoViewSortFilterProxyModel::KOTodoViewSortFilterProxyModel( QObject *parent )
  : QSortFilterProxyModel( parent )
{
}

bool KOTodoViewSortFilterProxyModel::filterAcceptsRow(
                  int source_row, const QModelIndex &source_parent ) const
{
  bool ret = QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );

  if ( ret && !mCategories.isEmpty() ) {
    QStringList categories =
      sourceModel()->index( source_row, KOTodoModel::CategoriesColumn, source_parent ).
      data( Qt::EditRole ).toStringList();
    foreach ( const QString &category, categories ) {
      if ( mCategories.contains( category ) ) {
        return true;
      }
    }
    ret = false;
  }

  // check if one of the children is accepted, and accept this node too if so
  QModelIndex cur = sourceModel()->index( source_row, KOTodoModel::SummaryColumn, source_parent );
  for ( int r = 0; r < cur.model()->rowCount( cur ); ++r ) {
    if ( filterAcceptsRow( r, cur ) ) {
      return true;
    }
  }

  return ret;
}

void KOTodoViewSortFilterProxyModel::setCategoryFilter( const QStringList &categories )
{
  mCategories = categories;
  invalidateFilter();
}

#include "kotodoviewsortfilterproxymodel.moc"
<|endoftext|>


<commit_before>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.23 2003/07/29 19:27:09 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TProcessID
//
// A TProcessID identifies a ROOT job in a unique way in time and space.
// The TProcessID title consists of a TUUID object which provides a globally
// unique identifier (for more see TUUID.h).
//
// A TProcessID is automatically created by the TROOT constructor.
// When a TFile contains referenced objects (see TRef), the TProcessID
// object is written to the file.
// If a file has been written in multiple sessions (same machine or not),
// a TProcessID is written for each session.
// These objects are used by the class TRef to uniquely identified
// any TObject pointed by a TRef.
//
// When a referenced object is read from a file (its bit kIsReferenced is set),
// this object is entered into the objects table of the corresponding TProcessID.
// Each TFile has a list of TProcessIDs (see TFile::fProcessIDs) also
// accessible via TProcessID::fgPIDs (for all files).
// When this object is deleted, it is removed from the table via the cleanup
// mechanism invoked by the TObject destructor.
//
// Each TProcessID has a table (TObjArray *fObjects) that keeps track
// of all referenced objects. If a referenced object has a fUniqueID set,
// a pointer to this unique object may be found via fObjects->At(fUniqueID).
// In the same way, when a TRef::GetObject is called, GetObject uses
// its own fUniqueID to find the pointer to the referenced object.
// See TProcessID::GetObjectWithID and PutObjectWithID.
//
// When a referenced object is deleted, its slot in fObjects is set to null.
//
// See also TProcessUUID: a specialized TProcessID to manage the single list
// of TUUIDs.
//
//////////////////////////////////////////////////////////////////////////

#include "TProcessID.h"
#include "TROOT.h"
#include "TFile.h"
#include "TObjArray.h"
#include "TExMap.h"

TObjArray  *TProcessID::fgPIDs   = 0; //pointer to the list of TProcessID
TProcessID *TProcessID::fgPID    = 0; //pointer to the TProcessID of the current session
UInt_t      TProcessID::fgNumber = 0; //Current referenced object instance count
TExMap     *TProcessID::fgObjPIDs= 0; //Table (pointer,pids)
ClassImp(TProcessID)

//______________________________________________________________________________
static inline ULong_t Void_Hash(const void *ptr)
{
   // Return hash value for this object.

   return TMath::Hash(&ptr, sizeof(void*));
}

//______________________________________________________________________________
TProcessID::TProcessID()
{
   fCount = 0;
   fObjects = 0;
}

//______________________________________________________________________________
TProcessID::~TProcessID()
{

   delete fObjects;
   fObjects = 0;
   fgPIDs->Remove(this);
}

//______________________________________________________________________________
TProcessID::TProcessID(const TProcessID &ref) : TNamed(ref)
{
   // TProcessID copy ctor.
}

//______________________________________________________________________________
TProcessID *TProcessID::AddProcessID()
{
// static function to add a new TProcessID to the list of PIDs

   TProcessID *pid = new TProcessID();

   if (!fgPIDs) {
      fgPID  = pid;
      fgPIDs = new TObjArray(10);
      gROOT->GetListOfCleanups()->Add(fgPIDs);
   }
   UShort_t apid = fgPIDs->GetEntriesFast();
   pid->IncrementCount();

   fgPIDs->Add(pid);
   char name[20];
   sprintf(name,"ProcessID%d",apid);
   pid->SetName(name);
   TUUID u;
   apid = fgPIDs->GetEntriesFast();
   pid->SetTitle(u.AsString());
   return pid;
}

//______________________________________________________________________________
UInt_t TProcessID::AssignID(TObject *obj)
{
// static function returning the ID assigned to obj
// If the object is not yet referenced, its kIsReferenced bit is set
// and its fUniqueID set to the current number of referenced objects so far.

   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == fgPID->GetObjectWithID(uid)) return uid;
   if (obj->TestBit(kIsReferenced)) {
      fgPID->PutObjectWithID(obj,uid);
      return uid;
   }
   fgNumber++;
   obj->SetBit(kIsReferenced);
   uid = fgNumber;
   obj->SetUniqueID(uid);
   fgPID->PutObjectWithID(obj,uid);
   return uid;
}

//______________________________________________________________________________
void TProcessID::Cleanup()
{
   // static function (called by TROOT destructor) to delete all TProcessIDs

   fgPIDs->Delete();
   gROOT->GetListOfCleanups()->Remove(fgPIDs);
   delete fgPIDs;
}

//______________________________________________________________________________
void TProcessID::Clear(Option_t *)
{
// delete the TObjArray pointing to referenced objects
// this function is called by TFile::Close("R")

   delete fObjects; fObjects = 0;
}

//______________________________________________________________________________
Int_t TProcessID::DecrementCount()
{

   // the reference fCount is used to delete the TProcessID
   // in the TFile destructor when fCount = 0

   fCount--;
   if (fCount < 0) fCount = 0;
   return fCount;
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessID(UShort_t pid)
{
// static function returning a pointer to TProcessID number pid in fgPIDs

   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, void *obj)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   if (pid==0xff) {
      // Look up the pid in the table (pointer,pid)
      if (fgObjPIDs==0) return 0;
      ULong_t hash = Void_Hash(obj);
      pid = fgObjPIDs->GetValue(hash,(Long_t)obj);
   }
   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetSessionProcessID()
{
// static function returning the pointer to the session TProcessID

   return fgPID;
}

//______________________________________________________________________________
Int_t TProcessID::IncrementCount()
{

   if (!fObjects) fObjects = new TObjArray(100);
   fCount++;
   return fCount;
}

//______________________________________________________________________________
UInt_t TProcessID::GetObjectCount()
{
// Return the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   return fgNumber;
}

//______________________________________________________________________________
TObject *TProcessID::GetObjectWithID(UInt_t uidd)
{
   //returns the TObject with unique identifier uid in the table of objects
   //if (!fObjects) fObjects = new TObjArray(100);

   Int_t uid = uidd & 0xffffff;  //take only the 24 lower bits

   if (uid >= fObjects->GetSize()) return 0;
   return fObjects->UncheckedAt(uid);
}

//______________________________________________________________________________
Bool_t TProcessID::IsValid(TProcessID *pid)
{
   // static function. return kTRUE if pid is a valid TProcessID

   if (fgPIDs->IndexOf(pid) >= 0) return kTRUE;
   if (pid == (TProcessID*)gROOT->GetUUIDs())  return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TProcessID::PutObjectWithID(TObject *obj, UInt_t uid)
{
   //stores the object at the uid th slot in the table of objects
   //The object uniqueid is set as well as its kMustCleanup bit
   //if (!fObjects) fObjects = new TObjArray(100);

   if (uid == 0) uid = obj->GetUniqueID() & 0xffffff;
   fObjects->AddAtAndExpand(obj,uid);
   obj->SetBit(kMustCleanup);
   if ( (obj->GetUniqueID()&0xff000000)==0xff000000 ) {
      // We have more than 255 pids we need to store this
      // pointer in the table(pointer,pid) since there is no
      // more space in fUniqueID
      if (fgObjPIDs==0) fgObjPIDs = new TExMap;
      ULong_t hash = Void_Hash(obj);
      fgObjPIDs->Add(hash, (Long_t)obj, GetUniqueID());
   }
}

//______________________________________________________________________________
TProcessID  *TProcessID::ReadProcessID(UShort_t pidf, TFile *file)
{
// static function

   //The TProcessID with number pidf is read from file.
   //If the object is not already entered in the gROOT list, it is added.

   if (!file) {
      if (!pidf) return fgPID; //may happen when cloning an object
      return 0;
   }
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) {
      if (!pid->fObjects) pid->fObjects = new TObjArray(100);
      return pid;
   }

   //check if fProcessIDs[uid] is set in file
   //if not set, read the process uid from file
   char pidname[32];
   sprintf(pidname,"ProcessID%d",pidf);
   TDirectory *dirsav = gDirectory;
   file->cd();
   pid = (TProcessID *)file->Get(pidname);
   if (dirsav) dirsav->cd();
   if (gDebug > 0) {
      printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,file->GetName(),(Long_t)pid);
   }
   if (!pid) {
      //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
      return 0;
   }
      //check that a similar pid is not already registered in fgPIDs
   TIter next(fgPIDs);
   TProcessID *p;
   while ((p = (TProcessID*)next())) {
      if (!strcmp(p->GetTitle(),pid->GetTitle())) {
         delete pid;
         pids->AddAtAndExpand(p,pidf);
         p->IncrementCount();
         return p;
      }
   }
   pids->AddAtAndExpand(pid,pidf);
   pid->IncrementCount();
   fgPIDs->Add(pid);
   Int_t ind = fgPIDs->IndexOf(pid);
   pid->SetUniqueID((UInt_t)ind);
   return pid;
}

//______________________________________________________________________________
void TProcessID::RecursiveRemove(TObject *obj)
{
   // called by the object destructor
   // remove reference to obj from the current table if it is referenced

   if (!fObjects) return;
   if (!obj->TestBit(kIsReferenced)) return;
   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == GetObjectWithID(uid)) fObjects->RemoveAt(uid);
}

//______________________________________________________________________________
void TProcessID::SetObjectCount(UInt_t number)
{
// static function to set the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   fgNumber = number;
}

//______________________________________________________________________________
UShort_t TProcessID::WriteProcessID(TProcessID *pidd, TFile *file)
{
// static function
// Check if the ProcessID pid is already in the file.
// if not, add it and return the index  number in the local file list

   if (!file) return 0;
   TProcessID *pid = pidd;
   if (!pid) pid = fgPID;
   TObjArray *pids = file->GetListOfProcessIDs();
   Int_t npids = file->GetNProcessIDs();
   for (Int_t i=0;i<npids;i++) {
      if (pids->At(i) == pid) return (UShort_t)i;
   }

   TDirectory *dirsav = gDirectory;
   file->cd();
   file->SetBit(TFile::kHasReferences);
   pids->AddAtAndExpand(pid,npids);
   pid->IncrementCount();
   char name[32];
   sprintf(name,"ProcessID%d",npids);
   pid->Write(name);
   file->IncrementProcessIDs();
   if (gDebug > 0) {
      printf("WriteProcessID, name=%s, file=%s\n",name,file->GetName());
   }
   if (dirsav) dirsav->cd();
   return (UShort_t)npids;
}
<commit_msg>From Philippe: When the number of processIds is greater than 255 and an address is re-used, we should not issue an error, just update the pids registered in fObjPIDs.<commit_after>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.24 2005/01/28 05:45:41 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TProcessID
//
// A TProcessID identifies a ROOT job in a unique way in time and space.
// The TProcessID title consists of a TUUID object which provides a globally
// unique identifier (for more see TUUID.h).
//
// A TProcessID is automatically created by the TROOT constructor.
// When a TFile contains referenced objects (see TRef), the TProcessID
// object is written to the file.
// If a file has been written in multiple sessions (same machine or not),
// a TProcessID is written for each session.
// These objects are used by the class TRef to uniquely identified
// any TObject pointed by a TRef.
//
// When a referenced object is read from a file (its bit kIsReferenced is set),
// this object is entered into the objects table of the corresponding TProcessID.
// Each TFile has a list of TProcessIDs (see TFile::fProcessIDs) also
// accessible via TProcessID::fgPIDs (for all files).
// When this object is deleted, it is removed from the table via the cleanup
// mechanism invoked by the TObject destructor.
//
// Each TProcessID has a table (TObjArray *fObjects) that keeps track
// of all referenced objects. If a referenced object has a fUniqueID set,
// a pointer to this unique object may be found via fObjects->At(fUniqueID).
// In the same way, when a TRef::GetObject is called, GetObject uses
// its own fUniqueID to find the pointer to the referenced object.
// See TProcessID::GetObjectWithID and PutObjectWithID.
//
// When a referenced object is deleted, its slot in fObjects is set to null.
//
// See also TProcessUUID: a specialized TProcessID to manage the single list
// of TUUIDs.
//
//////////////////////////////////////////////////////////////////////////

#include "TProcessID.h"
#include "TROOT.h"
#include "TFile.h"
#include "TObjArray.h"
#include "TExMap.h"

TObjArray  *TProcessID::fgPIDs   = 0; //pointer to the list of TProcessID
TProcessID *TProcessID::fgPID    = 0; //pointer to the TProcessID of the current session
UInt_t      TProcessID::fgNumber = 0; //Current referenced object instance count
TExMap     *TProcessID::fgObjPIDs= 0; //Table (pointer,pids)
ClassImp(TProcessID)

//______________________________________________________________________________
static inline ULong_t Void_Hash(const void *ptr)
{
   // Return hash value for this object.

   return TMath::Hash(&ptr, sizeof(void*));
}

//______________________________________________________________________________
TProcessID::TProcessID()
{
   fCount = 0;
   fObjects = 0;
}

//______________________________________________________________________________
TProcessID::~TProcessID()
{

   delete fObjects;
   fObjects = 0;
   fgPIDs->Remove(this);
}

//______________________________________________________________________________
TProcessID::TProcessID(const TProcessID &ref) : TNamed(ref)
{
   // TProcessID copy ctor.
}

//______________________________________________________________________________
TProcessID *TProcessID::AddProcessID()
{
// static function to add a new TProcessID to the list of PIDs

   TProcessID *pid = new TProcessID();

   if (!fgPIDs) {
      fgPID  = pid;
      fgPIDs = new TObjArray(10);
      gROOT->GetListOfCleanups()->Add(fgPIDs);
   }
   UShort_t apid = fgPIDs->GetEntriesFast();
   pid->IncrementCount();

   fgPIDs->Add(pid);
   char name[20];
   sprintf(name,"ProcessID%d",apid);
   pid->SetName(name);
   TUUID u;
   apid = fgPIDs->GetEntriesFast();
   pid->SetTitle(u.AsString());
   return pid;
}

//______________________________________________________________________________
UInt_t TProcessID::AssignID(TObject *obj)
{
// static function returning the ID assigned to obj
// If the object is not yet referenced, its kIsReferenced bit is set
// and its fUniqueID set to the current number of referenced objects so far.

   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == fgPID->GetObjectWithID(uid)) return uid;
   if (obj->TestBit(kIsReferenced)) {
      fgPID->PutObjectWithID(obj,uid);
      return uid;
   }
   fgNumber++;
   obj->SetBit(kIsReferenced);
   uid = fgNumber;
   obj->SetUniqueID(uid);
   fgPID->PutObjectWithID(obj,uid);
   return uid;
}

//______________________________________________________________________________
void TProcessID::Cleanup()
{
   // static function (called by TROOT destructor) to delete all TProcessIDs

   fgPIDs->Delete();
   gROOT->GetListOfCleanups()->Remove(fgPIDs);
   delete fgPIDs;
}

//______________________________________________________________________________
void TProcessID::Clear(Option_t *)
{
// delete the TObjArray pointing to referenced objects
// this function is called by TFile::Close("R")

   delete fObjects; fObjects = 0;
}

//______________________________________________________________________________
Int_t TProcessID::DecrementCount()
{

   // the reference fCount is used to delete the TProcessID
   // in the TFile destructor when fCount = 0

   fCount--;
   if (fCount < 0) fCount = 0;
   return fCount;
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessID(UShort_t pid)
{
// static function returning a pointer to TProcessID number pid in fgPIDs

   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, void *obj)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   if (pid==0xff) {
      // Look up the pid in the table (pointer,pid)
      if (fgObjPIDs==0) return 0;
      ULong_t hash = Void_Hash(obj);
      pid = fgObjPIDs->GetValue(hash,(Long_t)obj);
   }
   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetSessionProcessID()
{
// static function returning the pointer to the session TProcessID

   return fgPID;
}

//______________________________________________________________________________
Int_t TProcessID::IncrementCount()
{

   if (!fObjects) fObjects = new TObjArray(100);
   fCount++;
   return fCount;
}

//______________________________________________________________________________
UInt_t TProcessID::GetObjectCount()
{
// Return the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   return fgNumber;
}

//______________________________________________________________________________
TObject *TProcessID::GetObjectWithID(UInt_t uidd)
{
   //returns the TObject with unique identifier uid in the table of objects
   //if (!fObjects) fObjects = new TObjArray(100);

   Int_t uid = uidd & 0xffffff;  //take only the 24 lower bits

   if (uid >= fObjects->GetSize()) return 0;
   return fObjects->UncheckedAt(uid);
}

//______________________________________________________________________________
Bool_t TProcessID::IsValid(TProcessID *pid)
{
   // static function. return kTRUE if pid is a valid TProcessID

   if (fgPIDs->IndexOf(pid) >= 0) return kTRUE;
   if (pid == (TProcessID*)gROOT->GetUUIDs())  return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TProcessID::PutObjectWithID(TObject *obj, UInt_t uid)
{
   //stores the object at the uid th slot in the table of objects
   //The object uniqueid is set as well as its kMustCleanup bit
   //if (!fObjects) fObjects = new TObjArray(100);

   if (uid == 0) uid = obj->GetUniqueID() & 0xffffff;
   fObjects->AddAtAndExpand(obj,uid);
   obj->SetBit(kMustCleanup);
   if ( (obj->GetUniqueID()&0xff000000)==0xff000000 ) {
      // We have more than 255 pids we need to store this
      // pointer in the table(pointer,pid) since there is no
      // more space in fUniqueID
      if (fgObjPIDs==0) fgObjPIDs = new TExMap;
      ULong_t hash = Void_Hash(obj);

      // We use operator() rather than Add() because
      // if the address has already been registered, we want to
      // update it's uniqueID (this can easily happen when the
      // referenced obejct have been stored in a TClonesArray.
      (*fgObjPIDs)(hash, (Long_t)obj) = GetUniqueID();
   }
}

//______________________________________________________________________________
TProcessID  *TProcessID::ReadProcessID(UShort_t pidf, TFile *file)
{
// static function

   //The TProcessID with number pidf is read from file.
   //If the object is not already entered in the gROOT list, it is added.

   if (!file) {
      if (!pidf) return fgPID; //may happen when cloning an object
      return 0;
   }
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) {
      if (!pid->fObjects) pid->fObjects = new TObjArray(100);
      return pid;
   }

   //check if fProcessIDs[uid] is set in file
   //if not set, read the process uid from file
   char pidname[32];
   sprintf(pidname,"ProcessID%d",pidf);
   TDirectory *dirsav = gDirectory;
   file->cd();
   pid = (TProcessID *)file->Get(pidname);
   if (dirsav) dirsav->cd();
   if (gDebug > 0) {
      printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,file->GetName(),(Long_t)pid);
   }
   if (!pid) {
      //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
      return 0;
   }
      //check that a similar pid is not already registered in fgPIDs
   TIter next(fgPIDs);
   TProcessID *p;
   while ((p = (TProcessID*)next())) {
      if (!strcmp(p->GetTitle(),pid->GetTitle())) {
         delete pid;
         pids->AddAtAndExpand(p,pidf);
         p->IncrementCount();
         return p;
      }
   }
   pids->AddAtAndExpand(pid,pidf);
   pid->IncrementCount();
   fgPIDs->Add(pid);
   Int_t ind = fgPIDs->IndexOf(pid);
   pid->SetUniqueID((UInt_t)ind);
   return pid;
}

//______________________________________________________________________________
void TProcessID::RecursiveRemove(TObject *obj)
{
   // called by the object destructor
   // remove reference to obj from the current table if it is referenced

   if (!fObjects) return;
   if (!obj->TestBit(kIsReferenced)) return;
   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == GetObjectWithID(uid)) fObjects->RemoveAt(uid);
}

//______________________________________________________________________________
void TProcessID::SetObjectCount(UInt_t number)
{
// static function to set the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   fgNumber = number;
}

//______________________________________________________________________________
UShort_t TProcessID::WriteProcessID(TProcessID *pidd, TFile *file)
{
// static function
// Check if the ProcessID pid is already in the file.
// if not, add it and return the index  number in the local file list

   if (!file) return 0;
   TProcessID *pid = pidd;
   if (!pid) pid = fgPID;
   TObjArray *pids = file->GetListOfProcessIDs();
   Int_t npids = file->GetNProcessIDs();
   for (Int_t i=0;i<npids;i++) {
      if (pids->At(i) == pid) return (UShort_t)i;
   }

   TDirectory *dirsav = gDirectory;
   file->cd();
   file->SetBit(TFile::kHasReferences);
   pids->AddAtAndExpand(pid,npids);
   pid->IncrementCount();
   char name[32];
   sprintf(name,"ProcessID%d",npids);
   pid->Write(name);
   file->IncrementProcessIDs();
   if (gDebug > 0) {
      printf("WriteProcessID, name=%s, file=%s\n",name,file->GetName());
   }
   if (dirsav) dirsav->cd();
   return (UShort_t)npids;
}
<|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.

#include "util/mem-info.h"
#include "util/debug-util.h"
#include "util/string-parser.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include "util/pretty-printer.h"

#include "common/names.h"

using boost::algorithm::is_any_of;
using boost::algorithm::split;
using boost::algorithm::token_compress_on;

namespace impala {

bool MemInfo::initialized_ = false;
int64_t MemInfo::physical_mem_ = -1;
int32_t MemInfo::vm_overcommit_ = -1;
int64_t MemInfo::commit_limit_ = -1;

// Lines in meminfo have the form key colon whitespace value for example:
// MemTotal: 16129508 kB
int64_t ParseMemString(const char* val, size_t len) {
  StringParser::ParseResult result;
  int64_t mem_total_kb = StringParser::StringToInt<int64_t>(val,
      len, &result);
  if (result != StringParser::PARSE_SUCCESS) return -1;
  // Entries in /proc/meminfo are in KB.
  return mem_total_kb * 1024L;
}

void MemInfo::Init() {
  // Read overcommit settings
  ParseOvercommit();

  // Read from /proc/meminfo
  ifstream meminfo("/proc/meminfo", ios::in);
  string line;
  while (meminfo.good() && !meminfo.eof()) {
    getline(meminfo, line);
    vector<string> fields;
    split(fields, line, is_any_of(" "), token_compress_on);
    // We expect lines such as, e.g., 'MemTotal: 16129508 kB'
    if (fields.size() < 3) continue;

    // Make sure that the format of the file does not change
    DCHECK_EQ(fields[2], "kB");

    if (fields[0].compare("MemTotal:") == 0) {
      physical_mem_ = ParseMemString(fields[1].data(), fields[1].size());
    } else if (fields[0].compare("CommitLimit:") == 0) {
      commit_limit_ = ParseMemString(fields[1].data(), fields[1].size());
    }
  }
  if (meminfo.is_open()) meminfo.close();

  if (physical_mem_ == -1) {
    LOG(WARNING) << "Could not determine amount of physical memory on this machine "
                 << "using /proc/meminfo.";
  }

  if (commit_limit_ == -1) {
    LOG(WARNING) << "Could not determine memory commit limit on this machine "
                 << "using /proc/meminfo.";
  }
  initialized_ = true;
}

void MemInfo::ParseOvercommit() {
  ifstream overcommit_s("/proc/sys/vm/overcommit_memory", ios::in);
  overcommit_s >> vm_overcommit_;
}

bool MemInfo::HaveSmaps() {
  MappedMemInfo result;
  ifstream smaps("/proc/self/smaps", ios::in);
  return smaps.good();
}

MappedMemInfo MemInfo::ParseSmaps() {
  MappedMemInfo result;
  ifstream smaps("/proc/self/smaps", ios::in);
  if (!smaps) {
    LOG_FIRST_N(INFO, 1) << "Could not open smaps";
    return result;
  }
  while (smaps) {
    string line;
    getline(smaps, line);
    if (line.empty()) continue;
    if (isdigit(line[0])) {
      // Line is the start of a new mapping, of form:
      // 561ceff9c000-561ceffa1000 rw-p 00000000 00:00 0
      ++result.num_maps;
      continue;
    }
    // Line is in the form of <Name>:<spaces><value>, e.g.:
    // Size:         1084 kB
    // VmFlags: rd ex mr mw me dw
    size_t colon_pos = line.find(':');
    if (colon_pos == string::npos) continue;
    string name = line.substr(0, colon_pos);
    size_t non_space_after_colon_pos = line.find_first_not_of(" ", colon_pos + 1);
    if (non_space_after_colon_pos == string::npos) continue;
    // From the first non-space after the colon through the end of the string.
    string value = line.substr(non_space_after_colon_pos);

    // Use atol() to parse the value, ignoring " kB" suffix.
    if (name == "Size") {
      result.size_kb += atol(value.c_str());
    } else if (name == "Rss") {
      result.rss_kb += atol(value.c_str());
    } else if (name == "AnonHugePages") {
      result.anon_huge_pages_kb += atol(value.c_str());
    }
  }
  return result;
}

ThpConfig MemInfo::ParseThpConfig() {
  ThpConfig result;
  result.enabled = GetThpConfigVal("enabled");
  result.defrag = GetThpConfigVal("defrag");
  result.khugepaged_defrag = GetThpConfigVal("khugepaged/defrag");
  return result;
}

string MemInfo::GetThpConfigVal(const string& relative_path) {
  // This is the standard location for the configs.
  ifstream file("/sys/kernel/mm/transparent_hugepage/" + relative_path);
  if (!file) {
    // Some earlier versions of CentOS/RHEL put the configs in a different place.
    file.open("/sys/kernel/mm/redhat_transparent_hugepage/" + relative_path);
    if (!file) {
      LOG_FIRST_N(INFO, 1) << "Could not open thp config: " << relative_path;
      return "<unknown>";
    }
  }
  string result;
  getline(file, result);
  return result;
}

string MemInfo::DebugString() {
  DCHECK(initialized_);
  stringstream stream;
  stream << "Physical Memory: " << PrettyPrinter::Print(physical_mem_, TUnit::BYTES)
         << endl;
  stream << ParseThpConfig().DebugString();
  return stream.str();
}

string MappedMemInfo::DebugString() const {
  stringstream stream;
  stream << "Number of mappings: " << num_maps << endl;
  stream << "Total mapping (kB): " << size_kb << endl;
  stream << "RSS (kB): " << rss_kb << endl;
  stream << "Anon huge pages (kB): " << anon_huge_pages_kb << endl;
  return stream.str();
}

string ThpConfig::DebugString() const {
  stringstream stream;
  stream << "Transparent Huge Pages Config:" << endl;
  stream << "  enabled: " << enabled << endl;
  stream << "  defrag: " << defrag << endl;
  stream << "  khugepaged defrag: " << khugepaged_defrag << endl;
  return stream.str();
}
}
<commit_msg>IMPALA-7237: handle hex digits in ParseSmaps()<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.

#include "util/mem-info.h"
#include "util/debug-util.h"
#include "util/string-parser.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include "util/pretty-printer.h"

#include "common/names.h"

using boost::algorithm::is_any_of;
using boost::algorithm::split;
using boost::algorithm::token_compress_on;

namespace impala {

bool MemInfo::initialized_ = false;
int64_t MemInfo::physical_mem_ = -1;
int32_t MemInfo::vm_overcommit_ = -1;
int64_t MemInfo::commit_limit_ = -1;

// Lines in meminfo have the form key colon whitespace value for example:
// MemTotal: 16129508 kB
int64_t ParseMemString(const char* val, size_t len) {
  StringParser::ParseResult result;
  int64_t mem_total_kb = StringParser::StringToInt<int64_t>(val,
      len, &result);
  if (result != StringParser::PARSE_SUCCESS) return -1;
  // Entries in /proc/meminfo are in KB.
  return mem_total_kb * 1024L;
}

void MemInfo::Init() {
  // Read overcommit settings
  ParseOvercommit();

  // Read from /proc/meminfo
  ifstream meminfo("/proc/meminfo", ios::in);
  string line;
  while (meminfo.good() && !meminfo.eof()) {
    getline(meminfo, line);
    vector<string> fields;
    split(fields, line, is_any_of(" "), token_compress_on);
    // We expect lines such as, e.g., 'MemTotal: 16129508 kB'
    if (fields.size() < 3) continue;

    // Make sure that the format of the file does not change
    DCHECK_EQ(fields[2], "kB");

    if (fields[0].compare("MemTotal:") == 0) {
      physical_mem_ = ParseMemString(fields[1].data(), fields[1].size());
    } else if (fields[0].compare("CommitLimit:") == 0) {
      commit_limit_ = ParseMemString(fields[1].data(), fields[1].size());
    }
  }
  if (meminfo.is_open()) meminfo.close();

  if (physical_mem_ == -1) {
    LOG(WARNING) << "Could not determine amount of physical memory on this machine "
                 << "using /proc/meminfo.";
  }

  if (commit_limit_ == -1) {
    LOG(WARNING) << "Could not determine memory commit limit on this machine "
                 << "using /proc/meminfo.";
  }
  initialized_ = true;
}

void MemInfo::ParseOvercommit() {
  ifstream overcommit_s("/proc/sys/vm/overcommit_memory", ios::in);
  overcommit_s >> vm_overcommit_;
}

bool MemInfo::HaveSmaps() {
  MappedMemInfo result;
  ifstream smaps("/proc/self/smaps", ios::in);
  return smaps.good();
}

MappedMemInfo MemInfo::ParseSmaps() {
  MappedMemInfo result;
  ifstream smaps("/proc/self/smaps", ios::in);
  if (!smaps) {
    LOG_FIRST_N(INFO, 1) << "Could not open smaps";
    return result;
  }
  while (smaps) {
    string line;
    getline(smaps, line);
    if (line.empty()) continue;
    if (isdigit(line[0]) || (line[0] >= 'a' && line[0] <= 'f')) {
      // Line is the start of a new mapping, of form:
      // 561ceff9c000-561ceffa1000 rw-p 00000000 00:00 0
      // We distinguish this case by checking for lower-case hex digits.
      ++result.num_maps;
      continue;
    }
    // Line is in the form of <Name>:<spaces><value>, e.g.:
    // Size:         1084 kB
    // VmFlags: rd ex mr mw me dw
    size_t colon_pos = line.find(':');
    if (colon_pos == string::npos) continue;
    string name = line.substr(0, colon_pos);
    size_t non_space_after_colon_pos = line.find_first_not_of(" ", colon_pos + 1);
    if (non_space_after_colon_pos == string::npos) continue;
    // From the first non-space after the colon through the end of the string.
    string value = line.substr(non_space_after_colon_pos);

    // Use atol() to parse the value, ignoring " kB" suffix.
    if (name == "Size") {
      result.size_kb += atol(value.c_str());
    } else if (name == "Rss") {
      result.rss_kb += atol(value.c_str());
    } else if (name == "AnonHugePages") {
      result.anon_huge_pages_kb += atol(value.c_str());
    }
  }
  return result;
}

ThpConfig MemInfo::ParseThpConfig() {
  ThpConfig result;
  result.enabled = GetThpConfigVal("enabled");
  result.defrag = GetThpConfigVal("defrag");
  result.khugepaged_defrag = GetThpConfigVal("khugepaged/defrag");
  return result;
}

string MemInfo::GetThpConfigVal(const string& relative_path) {
  // This is the standard location for the configs.
  ifstream file("/sys/kernel/mm/transparent_hugepage/" + relative_path);
  if (!file) {
    // Some earlier versions of CentOS/RHEL put the configs in a different place.
    file.open("/sys/kernel/mm/redhat_transparent_hugepage/" + relative_path);
    if (!file) {
      LOG_FIRST_N(INFO, 1) << "Could not open thp config: " << relative_path;
      return "<unknown>";
    }
  }
  string result;
  getline(file, result);
  return result;
}

string MemInfo::DebugString() {
  DCHECK(initialized_);
  stringstream stream;
  stream << "Physical Memory: " << PrettyPrinter::Print(physical_mem_, TUnit::BYTES)
         << endl;
  stream << ParseThpConfig().DebugString();
  return stream.str();
}

string MappedMemInfo::DebugString() const {
  stringstream stream;
  stream << "Number of mappings: " << num_maps << endl;
  stream << "Total mapping (kB): " << size_kb << endl;
  stream << "RSS (kB): " << rss_kb << endl;
  stream << "Anon huge pages (kB): " << anon_huge_pages_kb << endl;
  return stream.str();
}

string ThpConfig::DebugString() const {
  stringstream stream;
  stream << "Transparent Huge Pages Config:" << endl;
  stream << "  enabled: " << enabled << endl;
  stream << "  defrag: " << defrag << endl;
  stream << "  khugepaged defrag: " << khugepaged_defrag << endl;
  return stream.str();
}
}
<|endoftext|>