<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2012-2014 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file CDev.cpp
 *
 * Character device base class.
 */

#include "CDev.hpp"

#include <cstring>

#include "px4_posix.h"
#include "drivers/drv_device.h"

#if 1 // Disable poll debug ouput by default completely as it uses CPU cycles
#define DEVICE_POLL_DEBUG(FMT, ...)
#else
#define DEVICE_POLL_DEBUG(FMT, ...) DEVICE_DEBUG(FMT, ##__VA_ARGS__)
#endif

namespace device
{

CDev::CDev(const char *name, const char *devname) :
	Device(name),
	_devname(devname)
{
	DEVICE_DEBUG("CDev::CDev");

	int ret = px4_sem_init(&_lock, 0, 1);

	if (ret != 0) {
		PX4_WARN("SEM INIT FAIL: ret %d", ret);
	}
}

CDev::~CDev()
{
	DEVICE_DEBUG("CDev::~CDev");

	if (_registered) {
		unregister_driver(_devname);
	}

	if (_pollset) {
		delete[](_pollset);
	}

	px4_sem_destroy(&_lock);
}

int
CDev::register_class_devname(const char *class_devname)
{
	DEVICE_DEBUG("CDev::register_class_devname %s", class_devname);

	if (class_devname == nullptr) {
		return -EINVAL;
	}

	int class_instance = 0;
	int ret = -ENOSPC;

	while (class_instance < 4) {
		char name[32];
		snprintf(name, sizeof(name), "%s%d", class_devname, class_instance);
		ret = register_driver(name, &fops, 0666, (void *)this);

		if (ret == OK) {
			break;
		}

		class_instance++;
	}

	if (class_instance == 4) {
		return ret;
	}

	return class_instance;
}

int
CDev::unregister_class_devname(const char *class_devname, unsigned class_instance)
{
	DEVICE_DEBUG("CDev::unregister_class_devname");
	char name[32];
	snprintf(name, sizeof(name), "%s%u", class_devname, class_instance);
	return unregister_driver(name);
}

int
CDev::init()
{
	DEVICE_DEBUG("CDev::init");

	// base class init first
	int ret = Device::init();

	if (ret != PX4_OK) {
		goto out;
	}

	// now register the driver
	if (_devname != nullptr) {
		ret = register_driver(_devname, &fops, 0666, (void *)this);

		if (ret != PX4_OK) {
			goto out;
		}

		_registered = true;
	}

out:
	return ret;
}

/*
 * Default implementations of the character device interface
 */
int
CDev::open(file_t *filep)
{
	DEVICE_DEBUG("CDev::open");
	int ret = PX4_OK;

	lock();
	/* increment the open count */
	_open_count++;

	if (_open_count == 1) {

		/* first-open callback may decline the open */
		ret = open_first(filep);

		if (ret != PX4_OK) {
			_open_count--;
		}
	}

	unlock();

	return ret;
}

int
CDev::open_first(file_t *filep)
{
	DEVICE_DEBUG("CDev::open_first");
	return PX4_OK;
}

int
CDev::close(file_t *filep)
{
	DEVICE_DEBUG("CDev::close");
	int ret = PX4_OK;

	lock();

	if (_open_count > 0) {
		/* decrement the open count */
		_open_count--;

		/* callback cannot decline the close */
		if (_open_count == 0) {
			ret = close_last(filep);
		}

	} else {
		ret = -EBADF;
	}

	unlock();

	return ret;
}

int
CDev::close_last(file_t *filep)
{
	DEVICE_DEBUG("CDev::close_last");
	return PX4_OK;
}

ssize_t
CDev::read(file_t *filep, char *buffer, size_t buflen)
{
	DEVICE_DEBUG("CDev::read");
	return -ENOSYS;
}

ssize_t
CDev::write(file_t *filep, const char *buffer, size_t buflen)
{
	DEVICE_DEBUG("CDev::write");
	return -ENOSYS;
}

off_t
CDev::seek(file_t *filep, off_t offset, int whence)
{
	DEVICE_DEBUG("CDev::seek");
	return -ENOSYS;
}

int
CDev::ioctl(file_t *filep, int cmd, unsigned long arg)
{
	DEVICE_DEBUG("CDev::ioctl");
	int ret = -ENOTTY;

	switch (cmd) {

	/* fetch a pointer to the driver's private data */
	case DIOC_GETPRIV:
		*(void **)(uintptr_t)arg = (void *)this;
		ret = PX4_OK;
		break;

	case DEVIOCSPUBBLOCK:
		_pub_blocked = (arg != 0);
		ret = PX4_OK;
		break;

	case DEVIOCGPUBBLOCK:
		ret = _pub_blocked;
		break;

	case DEVIOCGDEVICEID:
		ret = (int)_device_id.devid;
		break;

	default:
		break;
	}

	return ret;
}

int
CDev::poll(file_t *filep, px4_pollfd_struct_t *fds, bool setup)
{
	DEVICE_POLL_DEBUG("CDev::Poll %s", setup ? "setup" : "teardown");
	int ret = PX4_OK;

	if (setup) {
		/*
		 * Save the file pointer in the pollfd for the subclass'
		 * benefit.
		 */
		fds->priv = (void *)filep;
		DEVICE_POLL_DEBUG("CDev::poll: fds->priv = %p", filep);

		/*
		 * Lock against poll_notify() and possibly other callers.
		 */
		ATOMIC_ENTER;

		/*
		 * Try to store the fds for later use and handle array resizing.
		 */
		while ((ret = store_poll_waiter(fds)) == -ENFILE) {

			// No free slot found. Resize the pollset. This is expensive, but it's only needed initially.

			if (_max_pollwaiters >= 256 / 2) { //_max_pollwaiters is uint8_t
				ret = -ENOMEM;
				break;
			}

			const uint8_t new_count = _max_pollwaiters > 0 ? _max_pollwaiters * 2 : 1;
			px4_pollfd_struct_t **prev_pollset = _pollset;

#ifdef __PX4_NUTTX
			// malloc uses a semaphore, we need to call it enabled IRQ's
			px4_leave_critical_section(flags);
#endif
			px4_pollfd_struct_t **new_pollset = new px4_pollfd_struct_t *[new_count];

#ifdef __PX4_NUTTX
			flags = px4_enter_critical_section();
#endif

			if (prev_pollset == _pollset) {
				// no one else updated the _pollset meanwhile, so we're good to go
				if (!new_pollset) {
					ret = -ENOMEM;
					break;
				}

				if (_max_pollwaiters > 0) {
					memset(new_pollset + _max_pollwaiters, 0, sizeof(px4_pollfd_struct_t *) * (new_count - _max_pollwaiters));
					memcpy(new_pollset, _pollset, sizeof(px4_pollfd_struct_t *) * _max_pollwaiters);
					delete[](_pollset);
				}

				_pollset = new_pollset;
				_pollset[_max_pollwaiters] = fds;
				_max_pollwaiters = new_count;

				// Success
				ret = PX4_OK;
				break;
			}

#ifdef __PX4_NUTTX
			px4_leave_critical_section(flags);
#endif
			// We have to retry
			delete[] new_pollset;
#ifdef __PX4_NUTTX
			flags = px4_enter_critical_section();
#endif
		}

		if (ret == PX4_OK) {

			/*
			 * Check to see whether we should send a poll notification
			 * immediately.
			 */
			fds->revents |= fds->events & poll_state(filep);

			/* yes? post the notification */
			if (fds->revents != 0) {
				px4_sem_post(fds->sem);
			}

		}

		ATOMIC_LEAVE;

	} else {
		ATOMIC_ENTER;
		/*
		 * Handle a teardown request.
		 */
		ret = remove_poll_waiter(fds);
		ATOMIC_LEAVE;
	}

	return ret;
}

void
CDev::poll_notify(pollevent_t events)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify events = %0x", events);

	/* lock against poll() as well as other wakeups */
	ATOMIC_ENTER;

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (nullptr != _pollset[i]) {
			poll_notify_one(_pollset[i], events);
		}
	}

	ATOMIC_LEAVE;
}

void
CDev::poll_notify_one(px4_pollfd_struct_t *fds, pollevent_t events)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify_one");

	/* update the reported event set */
	fds->revents |= fds->events & events;

	DEVICE_POLL_DEBUG(" Events fds=%p %0x %0x %0x", fds, fds->revents, fds->events, events);

	if (fds->revents != 0) {
		px4_sem_post(fds->sem);
	}
}

pollevent_t
CDev::poll_state(file_t *filep)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify");
	/* by default, no poll events to report */
	return 0;
}

int
CDev::store_poll_waiter(px4_pollfd_struct_t *fds)
{
	/*
	 * Look for a free slot.
	 */
	DEVICE_POLL_DEBUG("CDev::store_poll_waiter");

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (nullptr == _pollset[i]) {

			/* save the pollfd */
			_pollset[i] = fds;

			return PX4_OK;
		}
	}

	return -ENFILE;
}

int
CDev::remove_poll_waiter(px4_pollfd_struct_t *fds)
{
	DEVICE_POLL_DEBUG("CDev::remove_poll_waiter");

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (fds == _pollset[i]) {

			_pollset[i] = nullptr;
			return PX4_OK;

		}
	}

	DEVICE_POLL_DEBUG("poll: bad fd state");
	return -EINVAL;
}

} // namespace device
<commit_msg>cdev: delete the prev_pollset in unlocked state<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2012-2014 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file CDev.cpp
 *
 * Character device base class.
 */

#include "CDev.hpp"

#include <cstring>

#include "px4_posix.h"
#include "drivers/drv_device.h"

#if 1 // Disable poll debug ouput by default completely as it uses CPU cycles
#define DEVICE_POLL_DEBUG(FMT, ...)
#else
#define DEVICE_POLL_DEBUG(FMT, ...) DEVICE_DEBUG(FMT, ##__VA_ARGS__)
#endif

namespace device
{

CDev::CDev(const char *name, const char *devname) :
	Device(name),
	_devname(devname)
{
	DEVICE_DEBUG("CDev::CDev");

	int ret = px4_sem_init(&_lock, 0, 1);

	if (ret != 0) {
		PX4_WARN("SEM INIT FAIL: ret %d", ret);
	}
}

CDev::~CDev()
{
	DEVICE_DEBUG("CDev::~CDev");

	if (_registered) {
		unregister_driver(_devname);
	}

	if (_pollset) {
		delete[](_pollset);
	}

	px4_sem_destroy(&_lock);
}

int
CDev::register_class_devname(const char *class_devname)
{
	DEVICE_DEBUG("CDev::register_class_devname %s", class_devname);

	if (class_devname == nullptr) {
		return -EINVAL;
	}

	int class_instance = 0;
	int ret = -ENOSPC;

	while (class_instance < 4) {
		char name[32];
		snprintf(name, sizeof(name), "%s%d", class_devname, class_instance);
		ret = register_driver(name, &fops, 0666, (void *)this);

		if (ret == OK) {
			break;
		}

		class_instance++;
	}

	if (class_instance == 4) {
		return ret;
	}

	return class_instance;
}

int
CDev::unregister_class_devname(const char *class_devname, unsigned class_instance)
{
	DEVICE_DEBUG("CDev::unregister_class_devname");
	char name[32];
	snprintf(name, sizeof(name), "%s%u", class_devname, class_instance);
	return unregister_driver(name);
}

int
CDev::init()
{
	DEVICE_DEBUG("CDev::init");

	// base class init first
	int ret = Device::init();

	if (ret != PX4_OK) {
		goto out;
	}

	// now register the driver
	if (_devname != nullptr) {
		ret = register_driver(_devname, &fops, 0666, (void *)this);

		if (ret != PX4_OK) {
			goto out;
		}

		_registered = true;
	}

out:
	return ret;
}

/*
 * Default implementations of the character device interface
 */
int
CDev::open(file_t *filep)
{
	DEVICE_DEBUG("CDev::open");
	int ret = PX4_OK;

	lock();
	/* increment the open count */
	_open_count++;

	if (_open_count == 1) {

		/* first-open callback may decline the open */
		ret = open_first(filep);

		if (ret != PX4_OK) {
			_open_count--;
		}
	}

	unlock();

	return ret;
}

int
CDev::open_first(file_t *filep)
{
	DEVICE_DEBUG("CDev::open_first");
	return PX4_OK;
}

int
CDev::close(file_t *filep)
{
	DEVICE_DEBUG("CDev::close");
	int ret = PX4_OK;

	lock();

	if (_open_count > 0) {
		/* decrement the open count */
		_open_count--;

		/* callback cannot decline the close */
		if (_open_count == 0) {
			ret = close_last(filep);
		}

	} else {
		ret = -EBADF;
	}

	unlock();

	return ret;
}

int
CDev::close_last(file_t *filep)
{
	DEVICE_DEBUG("CDev::close_last");
	return PX4_OK;
}

ssize_t
CDev::read(file_t *filep, char *buffer, size_t buflen)
{
	DEVICE_DEBUG("CDev::read");
	return -ENOSYS;
}

ssize_t
CDev::write(file_t *filep, const char *buffer, size_t buflen)
{
	DEVICE_DEBUG("CDev::write");
	return -ENOSYS;
}

off_t
CDev::seek(file_t *filep, off_t offset, int whence)
{
	DEVICE_DEBUG("CDev::seek");
	return -ENOSYS;
}

int
CDev::ioctl(file_t *filep, int cmd, unsigned long arg)
{
	DEVICE_DEBUG("CDev::ioctl");
	int ret = -ENOTTY;

	switch (cmd) {

	/* fetch a pointer to the driver's private data */
	case DIOC_GETPRIV:
		*(void **)(uintptr_t)arg = (void *)this;
		ret = PX4_OK;
		break;

	case DEVIOCSPUBBLOCK:
		_pub_blocked = (arg != 0);
		ret = PX4_OK;
		break;

	case DEVIOCGPUBBLOCK:
		ret = _pub_blocked;
		break;

	case DEVIOCGDEVICEID:
		ret = (int)_device_id.devid;
		break;

	default:
		break;
	}

	return ret;
}

int
CDev::poll(file_t *filep, px4_pollfd_struct_t *fds, bool setup)
{
	DEVICE_POLL_DEBUG("CDev::Poll %s", setup ? "setup" : "teardown");
	int ret = PX4_OK;

	if (setup) {
		/*
		 * Save the file pointer in the pollfd for the subclass'
		 * benefit.
		 */
		fds->priv = (void *)filep;
		DEVICE_POLL_DEBUG("CDev::poll: fds->priv = %p", filep);

		/*
		 * Lock against poll_notify() and possibly other callers (protect _pollset).
		 */
		ATOMIC_ENTER;

		/*
		 * Try to store the fds for later use and handle array resizing.
		 */
		while ((ret = store_poll_waiter(fds)) == -ENFILE) {

			// No free slot found. Resize the pollset. This is expensive, but it's only needed initially.

			if (_max_pollwaiters >= 256 / 2) { //_max_pollwaiters is uint8_t
				ret = -ENOMEM;
				break;
			}

			const uint8_t new_count = _max_pollwaiters > 0 ? _max_pollwaiters * 2 : 1;
			px4_pollfd_struct_t **prev_pollset = _pollset;

#ifdef __PX4_NUTTX
			// malloc uses a semaphore, we need to call it enabled IRQ's
			px4_leave_critical_section(flags);
#endif
			px4_pollfd_struct_t **new_pollset = new px4_pollfd_struct_t *[new_count];

#ifdef __PX4_NUTTX
			flags = px4_enter_critical_section();
#endif

			if (prev_pollset == _pollset) {
				// no one else updated the _pollset meanwhile, so we're good to go
				if (!new_pollset) {
					ret = -ENOMEM;
					break;
				}

				if (_max_pollwaiters > 0) {
					memset(new_pollset + _max_pollwaiters, 0, sizeof(px4_pollfd_struct_t *) * (new_count - _max_pollwaiters));
					memcpy(new_pollset, _pollset, sizeof(px4_pollfd_struct_t *) * _max_pollwaiters);
				}

				_pollset = new_pollset;
				_pollset[_max_pollwaiters] = fds;
				_max_pollwaiters = new_count;

				// free the previous _pollset (we need to unlock here which is fine because we don't access _pollset anymore)
#ifdef __PX4_NUTTX
				px4_leave_critical_section(flags);
#endif

				if (prev_pollset) {
					delete[](prev_pollset);
				}

#ifdef __PX4_NUTTX
				flags = px4_enter_critical_section();
#endif

				// Success
				ret = PX4_OK;
				break;
			}

#ifdef __PX4_NUTTX
			px4_leave_critical_section(flags);
#endif
			// We have to retry
			delete[] new_pollset;
#ifdef __PX4_NUTTX
			flags = px4_enter_critical_section();
#endif
		}

		if (ret == PX4_OK) {

			/*
			 * Check to see whether we should send a poll notification
			 * immediately.
			 */
			fds->revents |= fds->events & poll_state(filep);

			/* yes? post the notification */
			if (fds->revents != 0) {
				px4_sem_post(fds->sem);
			}

		}

		ATOMIC_LEAVE;

	} else {
		ATOMIC_ENTER;
		/*
		 * Handle a teardown request.
		 */
		ret = remove_poll_waiter(fds);
		ATOMIC_LEAVE;
	}

	return ret;
}

void
CDev::poll_notify(pollevent_t events)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify events = %0x", events);

	/* lock against poll() as well as other wakeups */
	ATOMIC_ENTER;

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (nullptr != _pollset[i]) {
			poll_notify_one(_pollset[i], events);
		}
	}

	ATOMIC_LEAVE;
}

void
CDev::poll_notify_one(px4_pollfd_struct_t *fds, pollevent_t events)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify_one");

	/* update the reported event set */
	fds->revents |= fds->events & events;

	DEVICE_POLL_DEBUG(" Events fds=%p %0x %0x %0x", fds, fds->revents, fds->events, events);

	if (fds->revents != 0) {
		px4_sem_post(fds->sem);
	}
}

pollevent_t
CDev::poll_state(file_t *filep)
{
	DEVICE_POLL_DEBUG("CDev::poll_notify");
	/* by default, no poll events to report */
	return 0;
}

int
CDev::store_poll_waiter(px4_pollfd_struct_t *fds)
{
	/*
	 * Look for a free slot.
	 */
	DEVICE_POLL_DEBUG("CDev::store_poll_waiter");

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (nullptr == _pollset[i]) {

			/* save the pollfd */
			_pollset[i] = fds;

			return PX4_OK;
		}
	}

	return -ENFILE;
}

int
CDev::remove_poll_waiter(px4_pollfd_struct_t *fds)
{
	DEVICE_POLL_DEBUG("CDev::remove_poll_waiter");

	for (unsigned i = 0; i < _max_pollwaiters; i++) {
		if (fds == _pollset[i]) {

			_pollset[i] = nullptr;
			return PX4_OK;

		}
	}

	DEVICE_POLL_DEBUG("poll: bad fd state");
	return -EINVAL;
}

} // namespace device
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/lite/delegates/gpu/cl/kernels/mean.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"
#include "tensorflow/lite/delegates/gpu/common/util.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetMeanKernelCode(
    const OperationDef& op_def,
    const std::vector<ElementwiseOperation*>& linked_operations,
    const int3& work_group_size) {
  TensorCodeGenerator src_tensor(
      "src_data", WHSPoint{"src_size.x", "src_size.y", "src_size.z"},
      op_def.src_tensors[0]);
  TensorCodeGenerator dst_tensor("dst_data", WHSPoint{"1", "1", "src_size.z"},
                                 op_def.dst_tensors[0]);

  std::string c = GetCommonDefines(op_def.precision);
  const std::string wg_x = std::to_string(work_group_size.x);
  const std::string wg_y = std::to_string(work_group_size.y);
  c += "__kernel void main_function(\n";
  c += src_tensor.GetDeclaration(AccessType::READ);
  c += GetArgsDeclaration(linked_operations);
  c += dst_tensor.GetDeclaration(AccessType::WRITE) + ",\n";
  c += "    int4 src_size,           \n";
  c += "    float2 inv_multipliers   \n";
  c += ") {\n";
  c += "  __local float4 accum[" +
       std::to_string(work_group_size.x * work_group_size.y) + "];\n";
  c += "  int local_x = get_local_id(0);\n";
  c += "  int local_y = get_local_id(1);\n";
  c += "  int local_id = local_y * " + wg_x + " + local_x;\n";
  c += "  int S = get_global_id(2);\n";
  c += "  if (S >= src_size.z) return;\n";
  c += "  accum[local_id] = (float4)(0.0f);\n";
  c += "  for (int s_y = local_y; s_y < src_size.y; s_y += " + wg_y + ") {\n";
  c += "    for (int s_x = local_x; s_x < src_size.x; s_x += " + wg_x + ") {\n";
  c += "        accum[local_id] += " +
       src_tensor.ReadAsFloatWHS("s_x", "s_y", "S") + ";\n";
  c += "    }\n";
  c += "  }\n";
  c += "  accum[local_id] *= inv_multipliers.x;\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  const int total_size = work_group_size.x * work_group_size.y;
  int offset = 1;
  int reminder = total_size / 4;
  for (; reminder >= 8; reminder /= 4, offset *= 4) {
    c += "  if (local_id < " + std::to_string(reminder) + ") {\n";
    c += "    int t = local_id * " + std::to_string(offset * 4) + ";\n";
    c += "    float4 sum = accum[t + " + std::to_string(offset) + "];\n";
    c += "    sum += accum[t + " + std::to_string(offset * 2) + "];\n";
    c += "    sum += accum[t + " + std::to_string(offset * 3) + "];\n";
    c += "    accum[t] += sum;\n";
    c += "  }\n";
    c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  }
  c += "  float4 sum = accum[0];\n";
  reminder *= 4;
  for (int i = 1; i < reminder; ++i) {
    c += "  sum += accum[" + std::to_string(offset * i) + "];\n";
  }
  c += "  FLT4 result = TO_FLT4(sum * inv_multipliers.y);\n";
  c += PostProcess(linked_operations, {"result", "0", "0", "S"});
  c += "  " + dst_tensor.WriteWHS("result", "0", "0", "S");
  c += "}\n";
  return c;
}
}  // namespace

Mean::Mean(Mean&& operation)
    : GPUOperation(std::move(operation)),
      kernel_(std::move(operation.kernel_)),
      work_group_size_(operation.work_group_size_) {}

Mean& Mean::operator=(Mean&& operation) {
  if (this != &operation) {
    kernel_ = std::move(operation.kernel_);
    std::swap(work_group_size_, operation.work_group_size_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

absl::Status Mean::Compile(const CreationContext& creation_context) {
  if (creation_context.device->IsAdreno3xx()) {
    work_group_size_ = int3(16, 8, 1);
  }
  const auto code =
      GetMeanKernelCode(definition_, linked_operations_, work_group_size_);
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status Mean::BindArguments() {
  kernel_.ResetBindingCounter();
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(src_[0]->GetMemoryPtr()));
  RETURN_IF_ERROR(BindArgs(&kernel_, linked_operations_));
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(dst_[0]->GetMemoryPtrForWriting()));
  RETURN_IF_ERROR(kernel_.SetBytesAuto(src_[0]->GetWBatchedHSB()));
  const double total_size = src_[0]->Width() * src_[0]->Height();
  const double size_0 = work_group_size_.x * work_group_size_.y;
  const double size_1 = total_size / size_0;
  RETURN_IF_ERROR(kernel_.SetBytesAuto(float2(1.0 / size_1, 1.0 / size_0)));
  return absl::OkStatus();
}

int3 Mean::GetGridSize() const {
  const int grid_x = work_group_size_.x * dst_[0]->Batch();
  const int grid_y = work_group_size_.y;
  const int grid_z = dst_[0]->Slices();
  return int3(grid_x, grid_y, grid_z);
}

absl::Status Mean::AddToQueue(CLCommandQueue* queue) {
  RETURN_IF_ERROR(BindArguments());
  return queue->DispatchImplicit(kernel_, GetGridSize(), work_group_size_);
}

Mean CreateMean(const OperationDef& definition) { return Mean(definition); }

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Mean converted to new style.<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/lite/delegates/gpu/cl/kernels/mean.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"
#include "tensorflow/lite/delegates/gpu/common/util.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetMeanKernelCode(const OperationDef& op_def,
                              const int3& work_group_size, Arguments* args) {
  args->AddObjectRef(
      "src_tensor", AccessType::READ,
      absl::make_unique<TensorDescriptor>(op_def.src_tensors[0]));
  args->AddObjectRef(
      "dst_tensor", AccessType::WRITE,
      absl::make_unique<TensorDescriptor>(op_def.dst_tensors[0]));
  args->AddFloat("inv_multiplier_1");
  args->AddFloat("inv_multiplier_2");

  std::string c = GetCommonDefines(op_def.precision);
  const std::string wg_x = std::to_string(work_group_size.x);
  const std::string wg_y = std::to_string(work_group_size.y);
  c += "__kernel void main_function(\n";
  c += "$0) {\n";
  c += "  __local float4 accum[" +
       std::to_string(work_group_size.x * work_group_size.y) + "];\n";
  c += "  int local_x = get_local_id(0);\n";
  c += "  int local_y = get_local_id(1);\n";
  c += "  int local_id = local_y * " + wg_x + " + local_x;\n";
  if (op_def.dst_tensors[0].HasAxis(Axis::BATCH)) {
    c += "  int linear_id_2 = get_global_id(2);\n";
    c += "  int S = linear_id_2 / args.dst_tensor.Batch();\n";
    c += "  int B = linear_id_2 % args.dst_tensor.Batch();\n";
    c += "  args.dst_tensor.SetBatchRef(B);\n";
    c += "  args.src_tensor.SetBatchRef(B);\n";
  } else {
    c += "  int S = get_global_id(2);\n";
  }
  c += "  if (S >= args.dst_tensor.Slices()) return;\n";
  c += "  accum[local_id] = (float4)(0.0f);\n";
  c += "  for (int s_y = local_y; s_y < args.src_tensor.Height(); s_y += " +
       wg_y + ") {\n";
  c += "    for (int s_x = local_x; s_x < args.src_tensor.Width(); s_x += " +
       wg_x + ") {\n";
  c += "      accum[local_id] += args.src_tensor.Read<float>(s_x, s_y, S);\n";
  c += "    }\n";
  c += "  }\n";
  c += "  accum[local_id] *= args.inv_multiplier_1;\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  const int total_size = work_group_size.x * work_group_size.y;
  int offset = 1;
  int reminder = total_size / 4;
  for (; reminder >= 8; reminder /= 4, offset *= 4) {
    c += "  if (local_id < " + std::to_string(reminder) + ") {\n";
    c += "    int t = local_id * " + std::to_string(offset * 4) + ";\n";
    c += "    float4 sum = accum[t + " + std::to_string(offset) + "];\n";
    c += "    sum += accum[t + " + std::to_string(offset * 2) + "];\n";
    c += "    sum += accum[t + " + std::to_string(offset * 3) + "];\n";
    c += "    accum[t] += sum;\n";
    c += "  }\n";
    c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  }
  c += "  float4 sum = accum[0];\n";
  reminder *= 4;
  for (int i = 1; i < reminder; ++i) {
    c += "  sum += accum[" + std::to_string(offset * i) + "];\n";
  }
  c += "  FLT4 result = TO_FLT4(sum * args.inv_multiplier_2);\n";
  c += "  args.dst_tensor.Write(result, 0, 0, S);\n";
  c += "}\n";
  return c;
}
}  // namespace

Mean::Mean(Mean&& operation)
    : GPUOperation(std::move(operation)),
      kernel_(std::move(operation.kernel_)),
      work_group_size_(operation.work_group_size_) {}

Mean& Mean::operator=(Mean&& operation) {
  if (this != &operation) {
    kernel_ = std::move(operation.kernel_);
    std::swap(work_group_size_, operation.work_group_size_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

absl::Status Mean::Compile(const CreationContext& creation_context) {
  if (creation_context.device->IsAdreno3xx()) {
    work_group_size_ = int3(16, 8, 1);
  }
  std::string code = GetMeanKernelCode(definition_, work_group_size_, &args_);
  std::string element_wise_code;
  RETURN_IF_ERROR(
      MergeOperations(linked_operations_, &args_, &element_wise_code));
  RETURN_IF_ERROR(args_.TransformToCLCode(creation_context.device->GetInfo(),
                                          {{"dst_tensor", element_wise_code}},
                                          &code));
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status Mean::BindArguments() {
  RETURN_IF_ERROR(args_.SetObjectRef("src_tensor", src_[0]));
  RETURN_IF_ERROR(args_.SetObjectRef("dst_tensor", dst_[0]));
  const double total_size = src_[0]->Width() * src_[0]->Height();
  const double size_0 = work_group_size_.x * work_group_size_.y;
  const double size_1 = total_size / size_0;
  RETURN_IF_ERROR(args_.SetFloat("inv_multiplier_1", 1.0 / size_1));
  RETURN_IF_ERROR(args_.SetFloat("inv_multiplier_2", 1.0 / size_0));
  RETURN_IF_ERROR(SetArguments(linked_operations_, &args_));
  return args_.Bind(kernel_.kernel());
}

int3 Mean::GetGridSize() const {
  const int grid_x = work_group_size_.x;
  const int grid_y = work_group_size_.y;
  const int grid_z = dst_[0]->Slices() * dst_[0]->Batch();
  return int3(grid_x, grid_y, grid_z);
}

absl::Status Mean::AddToQueue(CLCommandQueue* queue) {
  RETURN_IF_ERROR(BindArguments());
  return queue->DispatchImplicit(kernel_, GetGridSize(), work_group_size_);
}

Mean CreateMean(const OperationDef& definition) { return Mean(definition); }

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/kernels/kernel_runner.h"
#include "tensorflow/lite/micro/test_helpers.h"
#include "tensorflow/lite/micro/testing/micro_test.h"

namespace tflite {
namespace testing {
namespace {

constexpr float kTolerance = 1e-5;

constexpr int kOutputDimsCount = 4;

struct L2Pool2DTestParams {
  TfLitePadding padding = kTfLitePaddingValid;
  int stride_width = 2;
  int stride_height = 2;
  int filter_width = 2;
  int filter_height = 2;
  TfLiteFusedActivation activation = kTfLiteActNone;
  float compare_tolerance = kTolerance;
  //  output_dims_data is a TfLiteIntArray
  int output_dims_data[kOutputDimsCount + 1] = {kOutputDimsCount, 0, 0, 0, 0};
};

void ExecuteL2Pool2DTest(const L2Pool2DTestParams& params,
                         TfLiteTensor* tensors, int tensors_count) {
  constexpr int kInputArrayData[] = {1, 0};
  TfLiteIntArray* inputs_array = IntArrayFromInts(kInputArrayData);
  constexpr int kOutputArrayData[] = {1, 1};
  TfLiteIntArray* outputs_array = IntArrayFromInts(kOutputArrayData);

  TfLitePoolParams op_params = {};
  op_params.activation = params.activation;
  op_params.filter_height = params.filter_height;
  op_params.filter_width = params.filter_width;
  op_params.padding = params.padding;
  op_params.stride_height = params.stride_height;
  op_params.stride_width = params.stride_width;

  const TfLiteRegistration registration = tflite::Register_L2_POOL_2D();
  micro::KernelRunner runner(registration, tensors, tensors_count, inputs_array,
                             outputs_array, static_cast<void*>(&op_params));

  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
}

template <typename T>
void TestL2Pool2D(const L2Pool2DTestParams& params, const int* input_dims_data,
                  const T* input_data, const int* expected_dims_data,
                  const T* expected_data, T* output_data) {
  TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
  TfLiteIntArray* expected_dims = IntArrayFromInts(expected_dims_data);
  TfLiteIntArray* output_dims = IntArrayFromInts(params.output_dims_data);
  const int expected_count = ElementCount(*expected_dims);

  TfLiteTensor tensors[] = {
      CreateTensor(input_data, input_dims),
      CreateTensor(output_data, output_dims),
  };
  constexpr int tensors_count = std::extent<decltype(tensors)>::value;
  ExecuteL2Pool2DTest(params, tensors, tensors_count);

  for (int i = 0; i < expected_count; i++) {
    TF_LITE_MICRO_EXPECT_NEAR(expected_data[i], output_data[i],
                              params.compare_tolerance);
  }
  for (int i = 0; i < expected_dims->size; i++) {
    TF_LITE_MICRO_EXPECT_EQ(expected_dims->data[i], output_dims->data[i]);
  }
}

}  // namespace
}  // namespace testing
}  // namespace tflite

TF_LITE_MICRO_TESTS_BEGIN

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2Pool) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.5, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.compare_tolerance = 0;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -1, -6, 2,  4,  //
      -3, -2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.53553, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActRelu;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -0.1, -0.6, 2,  4,  //
      -0.3, -0.2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {0.353553, 1.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActReluN1To1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu6) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -0.1, -0.6, 2,  4,  //
      -0.3, -0.2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {0.353553, 6.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActRelu6;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingSame) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.5, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.padding = kTfLitePaddingSame;
  params.compare_tolerance = 0;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingSameStride1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 2, 4, 1};
  constexpr float kExpect[] = {3.5,     6.0,    6.5,     5.70088,
                               2.54951, 7.2111, 8.63134, 7.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.padding = kTfLitePaddingSame;
  params.compare_tolerance = 1e-4;
  params.stride_width = 1;
  params.stride_height = 1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingValidStride1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 3, 1};
  constexpr float kExpect[] = {3.5, 6.0, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.stride_width = 1;
  params.stride_height = 1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TESTS_END
<commit_msg>We should not be comparing floats with tolerance = 0.<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/kernels/kernel_runner.h"
#include "tensorflow/lite/micro/test_helpers.h"
#include "tensorflow/lite/micro/testing/micro_test.h"

namespace tflite {
namespace testing {
namespace {

constexpr float kTolerance = 1e-5;

constexpr int kOutputDimsCount = 4;

struct L2Pool2DTestParams {
  TfLitePadding padding = kTfLitePaddingValid;
  int stride_width = 2;
  int stride_height = 2;
  int filter_width = 2;
  int filter_height = 2;
  TfLiteFusedActivation activation = kTfLiteActNone;
  float compare_tolerance = kTolerance;
  //  output_dims_data is a TfLiteIntArray
  int output_dims_data[kOutputDimsCount + 1] = {kOutputDimsCount, 0, 0, 0, 0};
};

void ExecuteL2Pool2DTest(const L2Pool2DTestParams& params,
                         TfLiteTensor* tensors, int tensors_count) {
  constexpr int kInputArrayData[] = {1, 0};
  TfLiteIntArray* inputs_array = IntArrayFromInts(kInputArrayData);
  constexpr int kOutputArrayData[] = {1, 1};
  TfLiteIntArray* outputs_array = IntArrayFromInts(kOutputArrayData);

  TfLitePoolParams op_params = {};
  op_params.activation = params.activation;
  op_params.filter_height = params.filter_height;
  op_params.filter_width = params.filter_width;
  op_params.padding = params.padding;
  op_params.stride_height = params.stride_height;
  op_params.stride_width = params.stride_width;

  const TfLiteRegistration registration = tflite::Register_L2_POOL_2D();
  micro::KernelRunner runner(registration, tensors, tensors_count, inputs_array,
                             outputs_array, static_cast<void*>(&op_params));

  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
}

template <typename T>
void TestL2Pool2D(const L2Pool2DTestParams& params, const int* input_dims_data,
                  const T* input_data, const int* expected_dims_data,
                  const T* expected_data, T* output_data) {
  TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
  TfLiteIntArray* expected_dims = IntArrayFromInts(expected_dims_data);
  TfLiteIntArray* output_dims = IntArrayFromInts(params.output_dims_data);
  const int expected_count = ElementCount(*expected_dims);

  TfLiteTensor tensors[] = {
      CreateTensor(input_data, input_dims),
      CreateTensor(output_data, output_dims),
  };
  constexpr int tensors_count = std::extent<decltype(tensors)>::value;
  ExecuteL2Pool2DTest(params, tensors, tensors_count);

  for (int i = 0; i < expected_count; i++) {
    TF_LITE_MICRO_EXPECT_NEAR(expected_data[i], output_data[i],
                              params.compare_tolerance);
  }
  for (int i = 0; i < expected_dims->size; i++) {
    TF_LITE_MICRO_EXPECT_EQ(expected_dims->data[i], output_dims->data[i]);
  }
}

}  // namespace
}  // namespace testing
}  // namespace tflite

TF_LITE_MICRO_TESTS_BEGIN

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2Pool) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.5, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -1, -6, 2,  4,  //
      -3, -2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.53553, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActRelu;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -0.1, -0.6, 2,  4,  //
      -0.3, -0.2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {0.353553, 1.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActReluN1To1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolActivationRelu6) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      -0.1, -0.6, 2,  4,  //
      -0.3, -0.2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {0.353553, 6.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.activation = kTfLiteActRelu6;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingSame) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 2, 1};
  constexpr float kExpect[] = {3.5, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.padding = kTfLitePaddingSame;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingSameStride1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 2, 4, 1};
  constexpr float kExpect[] = {3.5,     6.0,    6.5,     5.70088,
                               2.54951, 7.2111, 8.63134, 7.0};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.padding = kTfLitePaddingSame;
  params.compare_tolerance = 1e-4;
  params.stride_width = 1;
  params.stride_height = 1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TEST(FloatPoolingOpTestL2PoolPaddingValidStride1) {
  constexpr int kInputDims[] = {4, 1, 2, 4, 1};
  constexpr float kInput[] = {
      0, 6, 2,  4,  //
      3, 2, 10, 7,  //
  };
  constexpr int kExpectDims[] = {4, 1, 1, 3, 1};
  constexpr float kExpect[] = {3.5, 6.0, 6.5};
  constexpr int kOutputCount = std::extent<decltype(kExpect)>::value;
  float output_data[kOutputCount];
  tflite::testing::L2Pool2DTestParams params;
  params.stride_width = 1;
  params.stride_height = 1;

  tflite::testing::TestL2Pool2D(params, kInputDims, kInput, kExpectDims,
                                kExpect, output_data);
}

TF_LITE_MICRO_TESTS_END
<|endoftext|>


<commit_before>// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep {i32 1,}
// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep {i32 2,}
// XFAIL: *
class A {
public:
  int x;
protected:
  int y;
private:
  int z;
};

A a;
<commit_msg>Re-enable test.<commit_after>// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep {i32 1,}
// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep {i32 2,}
class A {
public:
  int x;
protected:
  int y;
private:
  int z;
};

A a;
<|endoftext|>


<commit_before>#include "flakeref.hh"

#include <regex>

namespace nix {

// A Git ref (i.e. branch or tag name).
const static std::string refRegex = "[a-zA-Z0-9][a-zA-Z0-9_.-]*"; // FIXME: check

// A Git revision (a SHA-1 commit hash).
const static std::string revRegexS = "[0-9a-fA-F]{40}";
std::regex revRegex(revRegexS, std::regex::ECMAScript);

// A Git ref or revision.
const static std::string revOrRefRegex = "(?:(" + revRegexS + ")|(" + refRegex + "))";

// A rev ("e72daba8250068216d79d2aeef40d4d95aff6666"), or a ref
// optionally followed by a rev (e.g. "master" or
// "master/e72daba8250068216d79d2aeef40d4d95aff6666").
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegex + ")(?:/(" + revRegexS + "))?))";

const static std::string flakeAlias = "[a-zA-Z][a-zA-Z0-9_-]*";

// GitHub references.
const static std::string ownerRegex = "[a-zA-Z][a-zA-Z0-9_-]*";
const static std::string repoRegex = "[a-zA-Z][a-zA-Z0-9_-]*";

// URI stuff.
const static std::string schemeRegex = "(?:http|https|ssh|git|file)";
const static std::string authorityRegex = "[a-zA-Z0-9._~-]*";
const static std::string segmentRegex = "[a-zA-Z0-9._~-]+";
const static std::string pathRegex = "/?" + segmentRegex + "(?:/" + segmentRegex + ")*";
// FIXME: support escaping in query string.
// Note: '/' is not a valid query parameter, but so what...
const static std::string paramRegex = "[a-z]+=[/a-zA-Z0-9._-]*";

FlakeRef::FlakeRef(const std::string & uri, bool allowRelative)
{
    // FIXME: could combine this into one regex.

    static std::regex flakeRegex(
        "(?:flake:)?(" + flakeAlias + ")(?:/(?:" + refAndOrRevRegex + "))?",
        std::regex::ECMAScript);

    static std::regex githubRegex(
        "github:(" + ownerRegex + ")/(" + repoRegex + ")(?:/" + revOrRefRegex + ")?",
        std::regex::ECMAScript);

    static std::regex uriRegex(
        "((" + schemeRegex + "):" +
        "(?://(" + authorityRegex + "))?" +
        "(" + pathRegex + "))" +
        "(?:[?](" + paramRegex + "(?:&" + paramRegex + ")*))?",
        std::regex::ECMAScript);

    static std::regex refRegex2(refRegex, std::regex::ECMAScript);

    std::cmatch match;
    if (std::regex_match(uri.c_str(), match, flakeRegex)) {
        IsAlias d;
        d.alias = match[1];
        if (match[2].matched)
            rev = Hash(match[2], htSHA1);
        else if (match[3].matched) {
            ref = match[3];
            if (match[4].matched)
                rev = Hash(match[4], htSHA1);
        }
        data = d;
    }

    else if (std::regex_match(uri.c_str(), match, githubRegex)) {
        IsGitHub d;
        d.owner = match[1];
        d.repo = match[2];
        if (match[3].matched)
            rev = Hash(match[3], htSHA1);
        else if (match[4].matched) {
            ref = match[4];
        }
        data = d;
    }

    else if (std::regex_match(uri.c_str(), match, uriRegex)
        && (match[2] == "file" || hasSuffix(match[4], ".git")))
    {
        IsGit d;
        d.uri = match[1];
        for (auto & param : tokenizeString<Strings>(match[5], "&")) {
            auto n = param.find('=');
            assert(n != param.npos);
            std::string name(param, 0, n);
            std::string value(param, n + 1);
            if (name == "rev") {
                if (!std::regex_match(value, revRegex))
                    throw Error("invalid Git revision '%s'", value);
                rev = Hash(value, htSHA1);
            } else if (name == "ref") {
                if (!std::regex_match(value, refRegex2))
                    throw Error("invalid Git ref '%s'", value);
                ref = value;
            } else if (name == "dir") {
                // FIXME: validate value; should not contain relative paths
                subdir = value;
            } else
                // FIXME: should probably pass through unknown parameters
                throw Error("invalid Git flake reference parameter '%s', in '%s'", name, uri);
        }
        if (rev && !ref)
            throw Error("flake URI '%s' lacks a Git ref", uri);
        data = d;
    }

    else if (hasPrefix(uri, "/") || (allowRelative && (hasPrefix(uri, "./") || uri == "."))) {
        IsPath d;
        d.path = allowRelative ? absPath(uri) : canonPath(uri);
        data = d;
    }

    else
        throw Error("'%s' is not a valid flake reference", uri);
}

std::string FlakeRef::to_string() const
{
    std::string string;
    if (auto refData = std::get_if<FlakeRef::IsAlias>(&data))
        string = refData->alias;

    else if (auto refData = std::get_if<FlakeRef::IsGitHub>(&data)) {
        assert(!(ref && rev));
        string = "github:" + refData->owner + "/" + refData->repo;
    }

    else if (auto refData = std::get_if<FlakeRef::IsGit>(&data)) {
        assert(!rev || ref);
        string = refData->uri;
    }

    else if (auto refData = std::get_if<FlakeRef::IsPath>(&data))
        return refData->path;

    else abort();

    string += (ref ? "/" + *ref : "") +
              (rev ? "/" + rev->to_string(Base16, false) : "");
    if (subdir != "") string += "?dir=" + subdir;
    return string;
}

std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
{
    str << flakeRef.to_string();
    return str;
}

bool FlakeRef::isImmutable() const
{
    return (bool) rev;
}

FlakeRef FlakeRef::baseRef() const // Removes the ref and rev from a FlakeRef.
{
    FlakeRef result(*this);
    result.ref = std::nullopt;
    result.rev = std::nullopt;
    return result;
}
}
<commit_msg>Validate 'dir=' parameters<commit_after>#include "flakeref.hh"

#include <regex>

namespace nix {

// A Git ref (i.e. branch or tag name).
const static std::string refRegex = "[a-zA-Z0-9][a-zA-Z0-9_.-]*"; // FIXME: check

// A Git revision (a SHA-1 commit hash).
const static std::string revRegexS = "[0-9a-fA-F]{40}";
std::regex revRegex(revRegexS, std::regex::ECMAScript);

// A Git ref or revision.
const static std::string revOrRefRegex = "(?:(" + revRegexS + ")|(" + refRegex + "))";

// A rev ("e72daba8250068216d79d2aeef40d4d95aff6666"), or a ref
// optionally followed by a rev (e.g. "master" or
// "master/e72daba8250068216d79d2aeef40d4d95aff6666").
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegex + ")(?:/(" + revRegexS + "))?))";

const static std::string flakeAlias = "[a-zA-Z][a-zA-Z0-9_-]*";

// GitHub references.
const static std::string ownerRegex = "[a-zA-Z][a-zA-Z0-9_-]*";
const static std::string repoRegex = "[a-zA-Z][a-zA-Z0-9_-]*";

// URI stuff.
const static std::string schemeRegex = "(?:http|https|ssh|git|file)";
const static std::string authorityRegex = "[a-zA-Z0-9._~-]*";
const static std::string segmentRegex = "[a-zA-Z0-9._~-]+";
const static std::string pathRegex = "/?" + segmentRegex + "(?:/" + segmentRegex + ")*";
// FIXME: support escaping in query string.
// Note: '/' is not a valid query parameter, but so what...
const static std::string paramRegex = "[a-z]+=[/a-zA-Z0-9._-]*";

// 'dir' path elements cannot start with a '.'. We also reject
// potentially dangerous characters like ';'.
const static std::string subDirElemRegex = "(?:[a-zA-Z0-9_-]+[a-zA-Z0-9._-]*)";
const static std::string subDirRegex = subDirElemRegex + "(?:/" + subDirElemRegex + ")*";

FlakeRef::FlakeRef(const std::string & uri, bool allowRelative)
{
    // FIXME: could combine this into one regex.

    static std::regex flakeRegex(
        "(?:flake:)?(" + flakeAlias + ")(?:/(?:" + refAndOrRevRegex + "))?",
        std::regex::ECMAScript);

    static std::regex githubRegex(
        "github:(" + ownerRegex + ")/(" + repoRegex + ")(?:/" + revOrRefRegex + ")?",
        std::regex::ECMAScript);

    static std::regex uriRegex(
        "((" + schemeRegex + "):" +
        "(?://(" + authorityRegex + "))?" +
        "(" + pathRegex + "))" +
        "(?:[?](" + paramRegex + "(?:&" + paramRegex + ")*))?",
        std::regex::ECMAScript);

    static std::regex refRegex2(refRegex, std::regex::ECMAScript);

    static std::regex subDirRegex2(subDirRegex, std::regex::ECMAScript);

    std::cmatch match;
    if (std::regex_match(uri.c_str(), match, flakeRegex)) {
        IsAlias d;
        d.alias = match[1];
        if (match[2].matched)
            rev = Hash(match[2], htSHA1);
        else if (match[3].matched) {
            ref = match[3];
            if (match[4].matched)
                rev = Hash(match[4], htSHA1);
        }
        data = d;
    }

    else if (std::regex_match(uri.c_str(), match, githubRegex)) {
        IsGitHub d;
        d.owner = match[1];
        d.repo = match[2];
        if (match[3].matched)
            rev = Hash(match[3], htSHA1);
        else if (match[4].matched) {
            ref = match[4];
        }
        data = d;
    }

    else if (std::regex_match(uri.c_str(), match, uriRegex)
        && (match[2] == "file" || hasSuffix(match[4], ".git")))
    {
        IsGit d;
        d.uri = match[1];
        for (auto & param : tokenizeString<Strings>(match[5], "&")) {
            auto n = param.find('=');
            assert(n != param.npos);
            std::string name(param, 0, n);
            std::string value(param, n + 1);
            if (name == "rev") {
                if (!std::regex_match(value, revRegex))
                    throw Error("invalid Git revision '%s'", value);
                rev = Hash(value, htSHA1);
            } else if (name == "ref") {
                if (!std::regex_match(value, refRegex2))
                    throw Error("invalid Git ref '%s'", value);
                ref = value;
            } else if (name == "dir") {
                if (!std::regex_match(value, subDirRegex2))
                    throw Error("flake '%s' has invalid subdirectory '%s'", uri, value);
                subdir = value;
            } else
                // FIXME: should probably pass through unknown parameters
                throw Error("invalid Git flake reference parameter '%s', in '%s'", name, uri);
        }
        if (rev && !ref)
            throw Error("flake URI '%s' lacks a Git ref", uri);
        data = d;
    }

    else if (hasPrefix(uri, "/") || (allowRelative && (hasPrefix(uri, "./") || uri == "."))) {
        IsPath d;
        d.path = allowRelative ? absPath(uri) : canonPath(uri);
        data = d;
    }

    else
        throw Error("'%s' is not a valid flake reference", uri);
}

std::string FlakeRef::to_string() const
{
    std::string string;

    if (auto refData = std::get_if<FlakeRef::IsAlias>(&data))
        string = refData->alias;

    else if (auto refData = std::get_if<FlakeRef::IsGitHub>(&data)) {
        assert(!(ref && rev));
        string = "github:" + refData->owner + "/" + refData->repo;
    }

    else if (auto refData = std::get_if<FlakeRef::IsGit>(&data)) {
        assert(!rev || ref);
        string = refData->uri;
    }

    else if (auto refData = std::get_if<FlakeRef::IsPath>(&data))
        return refData->path;

    else abort();

    // FIXME: need to use ?rev etc. for IsGit URIs.
    string += (ref ? "/" + *ref : "") +
              (rev ? "/" + rev->to_string(Base16, false) : "");

    if (subdir != "") string += "?dir=" + subdir;

    return string;
}

std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
{
    str << flakeRef.to_string();
    return str;
}

bool FlakeRef::isImmutable() const
{
    return (bool) rev;
}

FlakeRef FlakeRef::baseRef() const // Removes the ref and rev from a FlakeRef.
{
    FlakeRef result(*this);
    result.ref = std::nullopt;
    result.rev = std::nullopt;
    return result;
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 libmv authors.
//
// 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.

#include "libmv/multiview/2DAffine.h"
#include <iostream>
namespace libmv {

bool Affine2D_FromCorrespondencesLinear(const Mat &x1, const Mat &x2,
                                            Mat3 *M)  {

  assert(2 == x1.rows());
  assert(2 <= x1.cols());
  assert(x1.rows() == x2.rows());
  assert(x1.cols() == x2.cols());

  int n = x1.cols();
  Mat A(4, 4);
  A.setZero();
  Mat B(4, 1);
  B.setZero();
  for (int i = 0; i < n; ++i) {
    int j=(i%2)*2;
    A(j,0) += -x1(1,i);
    A(j,1) +=  x1(0,i);
    A(j,2) +=  1.0;
    A(j,3) =  0.0;

    A(j+1,0) += x1(0,i);
    A(j+1,1) += x1(1,i);
    A(j+1,2) = 0.0;
    A(j+1,3) += 1.0;

    // x'
    B(j,0)   += x2(0,i);
    B(j+1,0) += x2(1,i);
  }
  // Does A is invertible ?
  if( fabs(A.determinant()) < 1e-1) {
     return false;
  }
  Mat res = A.inverse() * B;

  // Configure output matrix :
  (*M)(0,0) = res(1,0);   (*M)(0,1) = res(0,0);// cos sin
  (*M)(1,0) = -res(0,0);  (*M)(1,1) = res(1,0);// sin cos
  (*M)(0,2) = res(2,0);// tx
  (*M)(1,2) = res(3,0);// ty
  (*M)(2,0) = (*M)(2,1) = 0.0;
  // Force homogeneous coord
  (*M)(2,2) = 1.0;
  return true;
}

}
<commit_msg>Add comments and better constraint matrix.<commit_after>// Copyright (c) 2009 libmv authors.
//
// 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.

#include "libmv/multiview/2DAffine.h"
#include <iostream>
namespace libmv {

// Parametrisation
// cos -sin tx
// sin  cos ty
// 0    0   1

// It give the following system A x = B :
// | Xa -Ya 0 1 | | sin |   | Xb |
// | Xa  Ya 1 0 | | cos |   | Yb |
//                | tx  | =
//                | ty  |
// Scale can be estimated if the angle is known. Because x(0) = s * sin(angle).
bool Affine2D_FromCorrespondencesLinear(const Mat &x1, const Mat &x2,
                                            Mat3 *M)  {

  assert(2 == x1.rows());
  assert(2 <= x1.cols());
  assert(x1.rows() == x2.rows());
  assert(x1.cols() == x2.cols());

  const int n = x1.cols();
  Mat A = Mat::Zero(2*n, 4);
  Mat B = Mat::Zero(2*n, 1);
  for (int i = 0; i < n; ++i) {
    const int j=i*2;
    A(j,0) = -x1(1,i);
    A(j,1) =  x1(0,i);
    A(j,2) =  1.0;
    A(j,3) =  0.0;

    A(j+1,0) = x1(0,i);
    A(j+1,1) = x1(1,i);
    A(j+1,2) = 0.0;
    A(j+1,3) = 1.0;

    B(j,0)   = x2(0,i);
    B(j+1,0) = x2(1,i);
  }
  // Solve Ax=B
  Vec x;
  A.lu().solve(B, &x);

  // Configure output matrix :
  (*M)(0,0) = x(1);   (*M)(0,1) = x(0);// cos sin
  (*M)(1,0) = -x(0);  (*M)(1,1) = x(1);// sin cos
  (*M)(0,2) = x(2);// tx
  (*M)(1,2) = x(3);// ty
  (*M)(2,0) = (*M)(2,1) = 0.0;
  // Force homogeneous coord
  (*M)(2,2) = 1.0;
  return true;
}

}
<|endoftext|>


<commit_before>AliGenerator*  CreateGenerator();

void fastGen(Int_t nev = 1, char* filename = "galice.root")
{
//  Runloader

    AliRunLoader* rl = AliRunLoader::Open("galice.root","FASTRUN","recreate");

    rl->SetCompressionLevel(2);
    rl->SetNumberOfEventsPerFile(nev);
    rl->LoadKinematics("RECREATE");
    rl->MakeTree("E");
    gAlice->SetRunLoader(rl);

//  Create stack
    rl->MakeStack();
    AliStack* stack      = rl->Stack();

//  Header
    AliHeader* header = rl->GetHeader();
//
//  Create and Initialize Generator
    AliGenerator *gener = CreateGenerator();
    gener->Init();
    gener->SetStack(stack);

//
//                        Event Loop
//
    Int_t iev;

    for (iev = 0; iev < nev; iev++) {

	printf("\n \n Event number %d \n \n", iev);

//  Initialize event
	header->Reset(0,iev);
	rl->SetEventNumber(iev);
	stack->Reset();
	rl->MakeTree("K");
//	stack->ConnectTree();

//  Generate event
	gener->Generate();
//  Analysis
	Int_t npart = stack->GetNprimary();
	printf("Analyse %d Particles\n", npart);
	for (Int_t part=0; part<npart; part++) {
	    TParticle *MPart = stack->Particle(part);
	    Int_t mpart  = MPart->GetPdgCode();
	    printf("Particle %d\n", mpart);
	}

//  Finish event
	header->SetNprimary(stack->GetNprimary());
	header->SetNtrack(stack->GetNtrack());
//      I/O
//
	stack->FinishEvent();
	header->SetStack(stack);
	rl->WriteKinematics("OVERWRITE");
    } // event loop
//
//                         Termination
//  Generator
    gener->FinishRun();
//  Stack
    stack->FinishRun();
//  Write file
    gener->Write();
    rl->WriteHeader("OVERWRITE");
}

AliGenerator*  CreateGenerator()
{
    gener = new AliGenPythia(1);
//
//
//   vertex position and smearing
    gener->SetVertexSmear(kPerEvent);
//   structure function
    gener->SetStrucFunc(kGRVHO);
//   charm, beauty, charm_unforced, beauty_unforced, jpsi, jpsi_chi, mb
    gener->SetProcess(kPyJets);
//   Centre of mass energy
    gener->SetEnergyCMS(5500.);
//   Pt transfer of the hard scattering
    gener->SetPtHard(50.,50.2);
//   Initialize generator
    return gener;
}

<commit_msg>Write header correctly.<commit_after>AliGenerator*  CreateGenerator();

void fastGen(Int_t nev = 1, char* filename = "galice.root")
{
//  Runloader

    AliRunLoader* rl = AliRunLoader::Open("galice.root","FASTRUN","recreate");

    rl->SetCompressionLevel(2);
    rl->SetNumberOfEventsPerFile(nev);
    rl->LoadKinematics("RECREATE");
    rl->MakeTree("E");
    gAlice->SetRunLoader(rl);

//  Create stack
    rl->MakeStack();
    AliStack* stack      = rl->Stack();

//  Header
    AliHeader* header = rl->GetHeader();
//
//  Create and Initialize Generator
    AliGenerator *gener = CreateGenerator();
    gener->Init();
    gener->SetStack(stack);

//
//                        Event Loop
//
    Int_t iev;

    for (iev = 0; iev < nev; iev++) {

	printf("\n \n Event number %d \n \n", iev);

//  Initialize event
	header->Reset(0,iev);
	rl->SetEventNumber(iev);
	stack->Reset();
	rl->MakeTree("K");
//	stack->ConnectTree();

//  Generate event
	gener->Generate();
//  Analysis
	Int_t npart = stack->GetNprimary();
	printf("Analyse %d Particles\n", npart);
	for (Int_t part=0; part<npart; part++) {
	    TParticle *MPart = stack->Particle(part);
	    Int_t mpart  = MPart->GetPdgCode();
	    printf("Particle %d\n", mpart);
	}

//  Finish event
	header->SetNprimary(stack->GetNprimary());
	header->SetNtrack(stack->GetNtrack());
//      I/O
//
	stack->FinishEvent();
	header->SetStack(stack);
	rl->TreeE()->Fill();
	rl->WriteKinematics("OVERWRITE");

    } // event loop
//
//                         Termination
//  Generator
    gener->FinishRun();
//  Stack
    stack->FinishRun();
//  Write file
    rl->WriteHeader("OVERWRITE");
    gener->Write();
    rl->Write();

}

AliGenerator*  CreateGenerator()
{
    gener = new AliGenPythia(1);
//
//
//   vertex position and smearing
    gener->SetVertexSmear(kPerEvent);
//   structure function
    gener->SetStrucFunc(kGRVHO);
//   charm, beauty, charm_unforced, beauty_unforced, jpsi, jpsi_chi, mb
    gener->SetProcess(kPyJets);
//   Centre of mass energy
    gener->SetEnergyCMS(5500.);
//   Pt transfer of the hard scattering
    gener->SetPtHard(50.,50.2);
//   Initialize generator
    return gener;
}

<|endoftext|>


<commit_before>#ifndef LUNAR_SLAB_ALLOCATOR_MT
#define LUNAR_SLAB_ALLOCATOR_MT

/*
 * This allocator is MT-safe.
 */

#include <new>
#include <limits>

#include <stdlib.h>

#include "slab.hpp"
#include "lunar_rtm_lock.hpp"

namespace lunar {

template <typename T>
class slab_allocator_mt {
public:
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;

    template <typename U> struct rebind { typedef slab_allocator_mt<U> other; };
    slab_allocator_mt() throw()
    {
        rtm_transaction lock(rtm_lock);

        if (slab_allocator_mt<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator_mt<T>::m_refcnt++;
    }
    slab_allocator_mt(const slab_allocator_mt&) throw()
    {
        rtm_transaction lock(rtm_lock);

        if (slab_allocator_mt<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator_mt<T>::m_refcnt++;
    }

    template <typename U> slab_allocator_mt(const slab_allocator_mt<U>&) throw()
    {
        rtm_transaction lock(slab_allocator_mt<U>::rtm_lock);

        if (slab_allocator_mt<U>::m_refcnt == 0)
            slab_init(&slab_allocator_mt<U>::m_slab, sizeof(U));

        slab_allocator_mt<U>::m_refcnt++;
    }

    ~slab_allocator_mt() throw() {
        m_refcnt--;

        if (m_refcnt == 0)
            slab_destroy(&m_slab);
    }

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const * = 0) {
        if (s == 1) {
            return (pointer)slab_alloc(&m_slab);
        } else if (s >= 1) {
            pointer temp = (pointer)malloc(sizeof(void*) + s * sizeof(T));
            if (temp == nullptr)
                return nullptr;

            void **vp = (void**)temp;
            *vp = (void*)~(uint64_t)0;

            return (pointer)((char*)temp + sizeof(void*));
        } else {
            return nullptr;
        }
    }

    void deallocate(pointer p, size_type) {
        void **vp = (void**)((char*)p - sizeof(void*));

        if (*vp == (void*)~(uint64_t)0)
            free(vp);
        else
            slab_free(&m_slab, p);
    }

    size_type max_size() const throw() {
        return std::numeric_limits<size_t>::max() / sizeof(T);
    }

    void construct(pointer p, const T& val) {
        new((void *)p) T(val);
    }

    void destroy(pointer p) {
        p->~T();
    }

    static rtm_lock   m_rtm_lock;
    static uint64_t   m_refcnt;
    static slab_chain m_slab;
};

template <typename T> rtm_lock   slab_allocator_mt<T>::m_rtm_lock;
template <typename T> uint64_t   slab_allocator_mt<T>::m_refcnt = 0;
template <typename T> slab_chain slab_allocator_mt<T>::m_slab;

}

#endif // LUNAR_SLAB_ALLOCATOR_MT<commit_msg>lock when allocating and deallocating slab memory<commit_after>#ifndef LUNAR_SLAB_ALLOCATOR_MT
#define LUNAR_SLAB_ALLOCATOR_MT

/*
 * This allocator is MT-safe.
 */

#include <new>
#include <limits>

#include <stdlib.h>

#include "slab.hpp"
#include "lunar_rtm_lock.hpp"

namespace lunar {

template <typename T>
class slab_allocator_mt {
public:
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;

    template <typename U> struct rebind { typedef slab_allocator_mt<U> other; };
    slab_allocator_mt() throw()
    {
        rtm_transaction lock(rtm_lock);

        if (slab_allocator_mt<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator_mt<T>::m_refcnt++;
    }
    slab_allocator_mt(const slab_allocator_mt&) throw()
    {
        rtm_transaction lock(rtm_lock);

        if (slab_allocator_mt<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator_mt<T>::m_refcnt++;
    }

    template <typename U> slab_allocator_mt(const slab_allocator_mt<U>&) throw()
    {
        rtm_transaction lock(slab_allocator_mt<U>::rtm_lock);

        if (slab_allocator_mt<U>::m_refcnt == 0)
            slab_init(&slab_allocator_mt<U>::m_slab, sizeof(U));

        slab_allocator_mt<U>::m_refcnt++;
    }

    ~slab_allocator_mt() throw() {
        rtm_transaction lock(rtm_lock);

        m_refcnt--;

        if (m_refcnt == 0)
            slab_destroy(&m_slab);
    }

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const * = 0) {
        if (s == 1) {
            rtm_transaction lock(rtm_lock);
            return (pointer)slab_alloc(&m_slab);
        } else if (s >= 1) {
            pointer temp = (pointer)malloc(sizeof(void*) + s * sizeof(T));
            if (temp == nullptr)
                return nullptr;

            void **vp = (void**)temp;
            *vp = (void*)~(uint64_t)0;

            return (pointer)((char*)temp + sizeof(void*));
        } else {
            return nullptr;
        }
    }

    void deallocate(pointer p, size_type) {
        void **vp = (void**)((char*)p - sizeof(void*));

        if (*vp == (void*)~(uint64_t)0) {
            free(vp);
        } else {
            rtm_transaction lock(rtm_lock);
            slab_free(&m_slab, p);
        }
    }

    size_type max_size() const throw() {
        return std::numeric_limits<size_t>::max() / sizeof(T);
    }

    void construct(pointer p, const T& val) {
        new((void *)p) T(val);
    }

    void destroy(pointer p) {
        p->~T();
    }

    static rtm_lock   m_rtm_lock;
    static uint64_t   m_refcnt;
    static slab_chain m_slab;
};

template <typename T> rtm_lock   slab_allocator_mt<T>::m_rtm_lock;
template <typename T> uint64_t   slab_allocator_mt<T>::m_refcnt = 0;
template <typename T> slab_chain slab_allocator_mt<T>::m_slab;

}

#endif // LUNAR_SLAB_ALLOCATOR_MT<|endoftext|>


<commit_before>#include "ThreadsPool.h"

ThreadsPool::ThreadsPool(int thread_num,int request_max):_thread_num(thread_num),_conn_max(request_max),is_work(true){
    threads.clear();
    threads.resize(_thread_num);
    for(int i=0; i< _thread_num; i++){
        std::cout<<"create thread "<<i<<"."<<std::endl;
        if(pthread_create(&threads[i],NULL,worker,this)!=0){
            threads.clear();
            break;
        }
        else if(pthread_detach(threads[i])){
            threads.clear();
            break;
        }
    }
    std::cout<<"threads create complete."<<std::endl;
}

ThreadsPool::~ThreadsPool(){
    threads.clear();
	while(!conn_pool.empty()){
		conn_pool.pop();
	}
	req_pool.clear();
	res_pool.clear();
    is_work = false;
}

bool ThreadsPool::add(int conn,char *read_buff,int buff_size,int req_or_res){
    locker.lock();
    if(conn_pool.size() >= _conn_max){
        locker.unlock();
        return false;
    }
	if(req_or_res == 0){//request
		connection con;
		con.conn = conn;
		con.request_or_response = 0;
		conn_pool.push(con);

		//add to request pool
		std::map<int,Request*>::iterator it;
		it = req_pool.find(conn);
		std::cout<<"inin"<<std::endl;
		if(it != req_pool.end()){//found
			int old_size = req_pool[conn]->content_size;
			char *old_buff = req_pool[conn]->content;
			char *new_buff = new char[old_size+buff_size];
			strncpy(new_buff,old_buff,old_size);
			strncpy(new_buff+old_size,read_buff,buff_size);
			delete[] old_buff;
			req_pool[conn]->content = new_buff;
			req_pool[conn]->content_size = old_size+buff_size;
			return true;
		}
		else{
			Request *r;
			request_init(r);
			r->content_size = buff_size;
			r->content = read_buff;
			std::cout<<"insert null"<<std::endl;
			req_pool.insert(std::make_pair<int,Request*>(conn,r));
			std::cout<<"insert null"<<std::endl;
			return true;
		}

	}
    locker.unlock();
    status_queue.post();
    return true;
}

void* ThreadsPool::worker(void* arg){
    ThreadsPool *tp = (ThreadsPool*)arg;
    tp->run();
    return tp;
}

void ThreadsPool::run(){
    while(is_work){
        status_queue.wait();
        locker.lock();
        if(conn_pool.empty()){
            locker.unlock();
            continue;
        }
		connection c = conn_pool.front();
		conn_pool.pop();
		if(c.request_or_response == 0){//request
			std::map<int,Request*>::iterator it;
			it = req_pool.find(c.conn);
			if(it!=req_pool.end()){//found
				Request *req = it->second;
				//parser request
			}
			else{
				continue;
			}
		}

        locker.unlock();
        //if(c){
        //    std::cout<<"ok"<<std::endl;
            //r->process();
        //}
    }
}

<commit_msg>add main<commit_after>#include "ThreadsPool.h"

ThreadsPool::ThreadsPool(int thread_num,int request_max):_thread_num(thread_num),_conn_max(request_max),is_work(true){
    threads.clear();
    threads.resize(_thread_num);
    for(int i=0; i< _thread_num; i++){
        std::cout<<"create thread "<<i<<"."<<std::endl;
        if(pthread_create(&threads[i],NULL,worker,this)!=0){
            threads.clear();
            break;
        }
        else if(pthread_detach(threads[i])){
            threads.clear();
            break;
        }
    }
    std::cout<<"threads create complete."<<std::endl;
}

ThreadsPool::~ThreadsPool(){
    threads.clear();
	while(!conn_pool.empty()){
		conn_pool.pop();
	}
	req_pool.clear();
	res_pool.clear();
    is_work = false;
}

bool ThreadsPool::add(int conn,char *read_buff,int buff_size,int req_or_res){
    locker.lock();
    if(conn_pool.size() >= _conn_max){
        locker.unlock();
        return false;
    }
	if(req_or_res == 0){//request
		connection con;
		con.conn = conn;
		con.request_or_response = 0;
		conn_pool.push(con);

		//add to request pool
		std::map<int,Request*>::iterator it;
		it = req_pool.find(conn);
		std::cout<<"inin"<<std::endl;
		if(it != req_pool.end()){//found
			int old_size = req_pool[conn]->content_size;
			char *old_buff = req_pool[conn]->content;
			char *new_buff = new char[old_size+buff_size];
			strncpy(new_buff,old_buff,old_size);
			strncpy(new_buff+old_size,read_buff,buff_size);
			delete[] old_buff;
			req_pool[conn]->content = new_buff;
			req_pool[conn]->content_size = old_size+buff_size;
			return true;
		}
		else{
			std::cout<<"insert"<<std::endl;
			Request *r;
			request_init(r);
			r->content_size = buff_size;
			r->content = read_buff;
			std::cout<<"insert null"<<std::endl;
			req_pool.insert(std::make_pair<int,Request*>(conn,r));
			std::cout<<"insert null"<<std::endl;
			return true;
		}

	}
    locker.unlock();
    status_queue.post();
    return true;
}

void* ThreadsPool::worker(void* arg){
    ThreadsPool *tp = (ThreadsPool*)arg;
    tp->run();
    return tp;
}

void ThreadsPool::run(){
    while(is_work){
        status_queue.wait();
        locker.lock();
        if(conn_pool.empty()){
            locker.unlock();
            continue;
        }
		connection c = conn_pool.front();
		conn_pool.pop();
		if(c.request_or_response == 0){//request
			std::map<int,Request*>::iterator it;
			it = req_pool.find(c.conn);
			if(it!=req_pool.end()){//found
				Request *req = it->second;
				//parser request
			}
			else{
				continue;
			}
		}

        locker.unlock();
        //if(c){
        //    std::cout<<"ok"<<std::endl;
            //r->process();
        //}
    }
}

<|endoftext|>