<commit_before>/*
 * opencog/cython/PyScheme.cc
 *
 * Copyright (C) 2013 by OpenCog Foundation
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "PyScheme.h"

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/server/CogServer.h>

using std::string;

using namespace opencog;

#ifdef HAVE_GUILE

// Use thread-local storage (TLS) in order to avoid repeatedly
// creating and destroying the evaluator.
static SchemeEval* get_evaluator(AtomSpace* as)
{
	static thread_local AtomSpace* current_as = NULL;
	static thread_local SchemeEval* evaluator = NULL;

	if (current_as != as) {
		current_as = as;
		if (evaluator) delete evaluator;
		evaluator = new SchemeEval(as);
	}

	return evaluator;
}

static void check_err(SchemeEval* evaluator, const std::string &s)
{
	if (evaluator->eval_error()) {
		throw RuntimeException(TRACE_INFO,
		       "Failed to execute '%s'", s.c_str());
	}

	if (evaluator->input_pending()) {
		throw RuntimeException(TRACE_INFO,
		      "Scheme syntax error in input: '%s'", s.c_str());
	}
}
#endif // HAVE_GUILE

// Convenience wrapper, for stand-alone usage.
std::string opencog::eval_scheme(AtomSpace& as, const std::string &s)
{
#ifdef HAVE_GUILE
	SchemeEval* evaluator = get_evaluator(&as);
	std::string scheme_return_value = evaluator->eval(s);
	check_err(evaluator, s);
	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
Handle opencog::eval_scheme_h(AtomSpace& as, const std::string &s)
{
#ifdef HAVE_GUILE
	SchemeEval* evaluator = get_evaluator(&as);
	Handle scheme_return_value = evaluator->eval_h(s);
	check_err(evaluator, s);
	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}
<commit_msg>python: slightly better error messages<commit_after>/*
 * opencog/cython/PyScheme.cc
 *
 * Copyright (C) 2013 by OpenCog Foundation
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "PyScheme.h"

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/server/CogServer.h>

using std::string;

using namespace opencog;

#ifdef HAVE_GUILE

// Use thread-local storage (TLS) in order to avoid repeatedly
// creating and destroying the evaluator.
static SchemeEval* get_evaluator(AtomSpace* as)
{
	static thread_local AtomSpace* current_as = NULL;
	static thread_local SchemeEval* evaluator = NULL;

	if (current_as != as) {
		current_as = as;
		if (evaluator) delete evaluator;
		evaluator = new SchemeEval(as);
	}

	return evaluator;
}

static void check_err(SchemeEval* evaluator, const std::string &s)
{
	if (evaluator->eval_error()) {
		throw RuntimeException(TRACE_INFO,
		       "Scheme: Failed to execute '%s'", s.c_str());
	}

	if (evaluator->input_pending()) {
		throw RuntimeException(TRACE_INFO,
		      "Scheme: Syntax error in input: '%s'", s.c_str());
	}
}
#endif // HAVE_GUILE

// Convenience wrapper, for stand-alone usage.
std::string opencog::eval_scheme(AtomSpace& as, const std::string &s)
{
#ifdef HAVE_GUILE
	SchemeEval* evaluator = get_evaluator(&as);
	std::string scheme_return_value = evaluator->eval(s);
	check_err(evaluator, s);
	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}

// Convenience wrapper, for stand-alone usage.
Handle opencog::eval_scheme_h(AtomSpace& as, const std::string &s)
{
#ifdef HAVE_GUILE
	SchemeEval* evaluator = get_evaluator(&as);
	Handle scheme_return_value = evaluator->eval_h(s);
	check_err(evaluator, s);
	return scheme_return_value;
#else // HAVE_GUILE
	return "Error: Compiled without Guile support";
#endif // HAVE_GUILE
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/test/test_server.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 10; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
    }
    EXPECT_EQ(title, GetActiveTabTitle());
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2 FLAKY_DNSError_GoBack2
#else
#define MAYBE_DNSError_GoBack2 DNSError_GoBack2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2AndForward FLAKY_DNSError_GoBack2AndForward
#else
#define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2Forward2 FLAKY_DNSError_GoBack2Forward2
#else
#define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

// Checks that the Link Doctor is not loaded when we receive an actual 404 page.
TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("page404.html"))));

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}
<commit_msg>Change bug reference for flaky test<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/test/test_server.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 10; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
    }
    EXPECT_EQ(title, GetActiveTabTitle());
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/79412
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2 FLAKY_DNSError_GoBack2
#else
#define MAYBE_DNSError_GoBack2 DNSError_GoBack2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/79412
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2AndForward FLAKY_DNSError_GoBack2AndForward
#else
#define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

// Flaky on Linux, see http://crbug.com/79412
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2Forward2 FLAKY_DNSError_GoBack2Forward2
#else
#define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

// Checks that the Link Doctor is not loaded when we receive an actual 404 page.
TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("page404.html"))));

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string>
#include <vector>
#include <limits>
#include "Halide.h"

using namespace Halide;

std::vector<std::string> messages;

extern "C" void halide_print(void *user_context, const char *message) {
    //printf("%s", message);
    messages.push_back(message);
}

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

int main(int argc, char **argv) {
    if (get_jit_target_from_environment().has_feature(Target::Profile)) {
        // The profiler adds lots of extra prints, so counting the
        // number of prints is not useful.
        printf("Skipping test because profiler is active\n");
        return 0;
    }

    Var x;

    {
        Func f;

        f(x) = print(x * x, "the answer is", 42.0f, "unsigned", cast<uint32_t>(145));
        f.set_custom_print(halide_print);
        Buffer<int32_t> result = f.realize(10);

        for (int32_t i = 0; i < 10; i++) {
            if (result(i) != i * i) {
                return -1;
            }
        }

        assert(messages.size() == 10);
        for (size_t i = 0; i < messages.size(); i++) {
            long square;
            float forty_two;
            unsigned long one_forty_five;

            int scan_count = sscanf(messages[i].c_str(), "%ld the answer is %f unsigned %lu",
                                    &square, &forty_two, &one_forty_five);
            assert(scan_count == 3);
            assert(square == static_cast<long long>(i * i));
            assert(forty_two == 42.0f);
            assert(one_forty_five == 145);
        }
    }

    messages.clear();

    {
        Func f;
        Param<int> param;
        param.set(127);

        // Test a string containing a printf format specifier (It should print it as-is).
        f(x) = print_when(x == 3, x * x, "g", 42.0f, "%s", param);
        f.set_custom_print(halide_print);
        Buffer<int32_t> result = f.realize(10);

        for (int32_t i = 0; i < 10; i++) {
            if (result(i) != i * i) {
                return -1;
            }
        }

        assert(messages.size() == 1);
        long nine;
        float forty_two;
        long p;

        int scan_count = sscanf(messages[0].c_str(), "%ld g %f %%s %ld",
                                &nine, &forty_two, &p);
        assert(scan_count == 3);
        assert(nine == 9);
        assert(forty_two == 42.0f);
        assert(p == 127);

    }

    messages.clear();

    {
        Func f;

        // Test a single message longer than 8K.
        std::vector<Expr> args;
        for (int i = 0; i < 500; i++) {
            uint64_t n = i;
            n *= n;
            n *= n;
            n *= n;
            n *= n;
            n += 100;
            int32_t hi = n >> 32;
            int32_t lo = n & 0xffffffff;
            args.push_back((cast<uint64_t>(hi) << 32) | lo);
            Expr dn = cast<double>((float)(n));
            args.push_back(dn);
        }
        f(x) = print(args);
        f.set_custom_print(halide_print);
        Buffer<uint64_t> result = f.realize(1);

        if (result(0) != 100) {
            return -1;
        }

        assert(messages.back().size() == 8191);
    }

    messages.clear();

    // Check that Halide's stringification of floats and doubles
    // matches %f and %e respectively.

    #ifndef _WIN32
    // msvc's library has different ideas about how %f and %e should come out.
    {
        Func f, g;

        const int N = 1000000;

        Expr e = reinterpret(Float(32), random_uint());
        // Make sure we cover some special values.
        e = select(x == 0, 0.0f,
                   x == 1, -0.0f,
                   x == 2, std::numeric_limits<float>::infinity(),
                   x == 3, -std::numeric_limits<float>::infinity(),
                   x == 4, std::numeric_limits<float>::quiet_NaN(),
                   x == 5, -std::numeric_limits<float>::quiet_NaN(),
                   e);
        e = select(x == 5, std::numeric_limits<float>::denorm_min(),
                   x == 6, -std::numeric_limits<float>::denorm_min(),
                   x == 7, std::numeric_limits<float>::min(),
                   x == 8, -std::numeric_limits<float>::min(),
                   x == 9, std::numeric_limits<float>::max(),
                   x == 10, -std::numeric_limits<float>::max(),
                   x == 11, 1.0f - 1.0f / (1 << 22),
                   e);

        f(x) = print(e);

        f.set_custom_print(halide_print);
        Buffer<float> imf = f.realize(N);

        assert(messages.size() == (size_t)N);

        char correct[1024];
        for (int i = 0; i < N; i++) {
            snprintf(correct, sizeof(correct), "%f\n", imf(i));
            // Some versions of the std library can emit some NaN patterns
            // as "-nan", due to sloppy conversion (or not) of the sign bit.
            // Halide considers all NaN's equivalent, so paper over this
            // noise in the test by normalizing all -nan -> nan.
            if (messages[i] == "-nan\n") messages[i] = "nan\n";
            if (!strcmp(correct, "-nan\n")) strcpy(correct, "nan\n");
            if (messages[i] != correct) {
                printf("float %d: %s vs %s for %10.20e\n", i, messages[i].c_str(), correct, imf(i));
                return -1;
            }
        }

        messages.clear();

        g(x) = print(reinterpret(Float(64), (cast<uint64_t>(random_uint()) << 32) | random_uint()));
        g.set_custom_print(halide_print);
        Buffer<double> img = g.realize(N);

        assert(messages.size() == (size_t)N);

        for (int i = 0; i < N; i++) {
            snprintf(correct, sizeof(correct), "%e\n", img(i));
            #ifdef __APPLE__
            if (messages[i] == "-nan\n") messages[i] = "nan\n";
            #endif
            if (messages[i] != correct) {
                printf("double %d: %s vs %s for %10.20e\n", i, messages[i].c_str(), correct, img(i));
                return -1;
            }
        }

    }
    #endif

    printf("Success!\n");
    return 0;
}
<commit_msg>Fix -nan output for test/print for doubles as well as floats (see a45f0be61c3c35197c0c74e81f46e828c26b31bb)<commit_after>#include <stdio.h>
#include <string>
#include <vector>
#include <limits>
#include "Halide.h"

using namespace Halide;

std::vector<std::string> messages;

extern "C" void halide_print(void *user_context, const char *message) {
    //printf("%s", message);
    messages.push_back(message);
}

#ifdef _MSC_VER
#define snprintf _snprintf
#endif

int main(int argc, char **argv) {
    if (get_jit_target_from_environment().has_feature(Target::Profile)) {
        // The profiler adds lots of extra prints, so counting the
        // number of prints is not useful.
        printf("Skipping test because profiler is active\n");
        return 0;
    }

    Var x;

    {
        Func f;

        f(x) = print(x * x, "the answer is", 42.0f, "unsigned", cast<uint32_t>(145));
        f.set_custom_print(halide_print);
        Buffer<int32_t> result = f.realize(10);

        for (int32_t i = 0; i < 10; i++) {
            if (result(i) != i * i) {
                return -1;
            }
        }

        assert(messages.size() == 10);
        for (size_t i = 0; i < messages.size(); i++) {
            long square;
            float forty_two;
            unsigned long one_forty_five;

            int scan_count = sscanf(messages[i].c_str(), "%ld the answer is %f unsigned %lu",
                                    &square, &forty_two, &one_forty_five);
            assert(scan_count == 3);
            assert(square == static_cast<long long>(i * i));
            assert(forty_two == 42.0f);
            assert(one_forty_five == 145);
        }
    }

    messages.clear();

    {
        Func f;
        Param<int> param;
        param.set(127);

        // Test a string containing a printf format specifier (It should print it as-is).
        f(x) = print_when(x == 3, x * x, "g", 42.0f, "%s", param);
        f.set_custom_print(halide_print);
        Buffer<int32_t> result = f.realize(10);

        for (int32_t i = 0; i < 10; i++) {
            if (result(i) != i * i) {
                return -1;
            }
        }

        assert(messages.size() == 1);
        long nine;
        float forty_two;
        long p;

        int scan_count = sscanf(messages[0].c_str(), "%ld g %f %%s %ld",
                                &nine, &forty_two, &p);
        assert(scan_count == 3);
        assert(nine == 9);
        assert(forty_two == 42.0f);
        assert(p == 127);

    }

    messages.clear();

    {
        Func f;

        // Test a single message longer than 8K.
        std::vector<Expr> args;
        for (int i = 0; i < 500; i++) {
            uint64_t n = i;
            n *= n;
            n *= n;
            n *= n;
            n *= n;
            n += 100;
            int32_t hi = n >> 32;
            int32_t lo = n & 0xffffffff;
            args.push_back((cast<uint64_t>(hi) << 32) | lo);
            Expr dn = cast<double>((float)(n));
            args.push_back(dn);
        }
        f(x) = print(args);
        f.set_custom_print(halide_print);
        Buffer<uint64_t> result = f.realize(1);

        if (result(0) != 100) {
            return -1;
        }

        assert(messages.back().size() == 8191);
    }

    messages.clear();

    // Check that Halide's stringification of floats and doubles
    // matches %f and %e respectively.

    #ifndef _WIN32
    // msvc's library has different ideas about how %f and %e should come out.
    {
        Func f, g;

        const int N = 1000000;

        Expr e = reinterpret(Float(32), random_uint());
        // Make sure we cover some special values.
        e = select(x == 0, 0.0f,
                   x == 1, -0.0f,
                   x == 2, std::numeric_limits<float>::infinity(),
                   x == 3, -std::numeric_limits<float>::infinity(),
                   x == 4, std::numeric_limits<float>::quiet_NaN(),
                   x == 5, -std::numeric_limits<float>::quiet_NaN(),
                   e);
        e = select(x == 5, std::numeric_limits<float>::denorm_min(),
                   x == 6, -std::numeric_limits<float>::denorm_min(),
                   x == 7, std::numeric_limits<float>::min(),
                   x == 8, -std::numeric_limits<float>::min(),
                   x == 9, std::numeric_limits<float>::max(),
                   x == 10, -std::numeric_limits<float>::max(),
                   x == 11, 1.0f - 1.0f / (1 << 22),
                   e);

        f(x) = print(e);

        f.set_custom_print(halide_print);
        Buffer<float> imf = f.realize(N);

        assert(messages.size() == (size_t)N);

        char correct[1024];
        for (int i = 0; i < N; i++) {
            snprintf(correct, sizeof(correct), "%f\n", imf(i));
            // Some versions of the std library can emit some NaN patterns
            // as "-nan", due to sloppy conversion (or not) of the sign bit.
            // Halide considers all NaN's equivalent, so paper over this
            // noise in the test by normalizing all -nan -> nan.
            if (messages[i] == "-nan\n") messages[i] = "nan\n";
            if (!strcmp(correct, "-nan\n")) strcpy(correct, "nan\n");
            if (messages[i] != correct) {
                printf("float %d: %s vs %s for %10.20e\n", i, messages[i].c_str(), correct, imf(i));
                return -1;
            }
        }

        messages.clear();

        g(x) = print(reinterpret(Float(64), (cast<uint64_t>(random_uint()) << 32) | random_uint()));
        g.set_custom_print(halide_print);
        Buffer<double> img = g.realize(N);

        assert(messages.size() == (size_t)N);

        for (int i = 0; i < N; i++) {
            snprintf(correct, sizeof(correct), "%e\n", img(i));
            // Some versions of the std library can emit some NaN patterns
            // as "-nan", due to sloppy conversion (or not) of the sign bit.
            // Halide considers all NaN's equivalent, so paper over this
            // noise in the test by normalizing all -nan -> nan.
            if (messages[i] == "-nan\n") messages[i] = "nan\n";
            if (!strcmp(correct, "-nan\n")) strcpy(correct, "nan\n");
            if (messages[i] != correct) {
                printf("double %d: %s vs %s for %10.20e\n", i, messages[i].c_str(), correct, img(i));
                return -1;
            }
        }

    }
    #endif

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The claire-common Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <claire/common/metrics/Histogram.h>

#include <math.h>
#include <limits.h>

#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>

#include <claire/common/strings/StringPrintf.h>
#include <claire/common/metrics/HistogramSamples.h>
#include <claire/common/metrics/BucketRanges.h>
#include <claire/common/metrics/SampleVector.h>
#include <claire/common/metrics/HistogramRecorder.h>
#include <claire/common/logging/Logging.h>

namespace claire {

const Histogram::Sample Histogram::kSampleTypeMax = INT_MAX;
const size_t Histogram::kBucketCountMax = 16384u;

typedef Histogram::Count Count;
typedef Histogram::Sample Sample;

Histogram* Histogram::FactoryGet(const std::string& name,
                                 Sample minimum,
                                 Sample maximum,
                                 size_t bucket_count)
{
    auto histogram = HistogramRecorder::instance()->FindHistogram(name);
    if (!histogram)
    {
        Histogram* tentative_histogram =
            new Histogram(name, minimum, maximum, bucket_count);
        histogram =
            HistogramRecorder::instance()->RegisterOrDeleteDuplicate(tentative_histogram);
    }

    return histogram;
}

Histogram::Histogram(const std::string& name,
                     Sample minimum,
                     Sample maximum,
                     size_t bucket_count__)
    : histogram_name_(name),
      bucket_ranges_(new BucketRanges(bucket_count__+1)),
      declared_min_(minimum),
      declared_max_(maximum)
{
    InitializeBucketRanges(minimum, maximum, bucket_ranges_.get());
    samples_.reset(new SampleVector(bucket_ranges_.get()));
}

Histogram::~Histogram() {}

void Histogram::InitializeBucketRanges(Sample minimum, Sample maximum, BucketRanges* ranges)
{
    double log_max = log(static_cast<double>(maximum));
    double log_ratio;
    double log_next;
    size_t bucket_index = 1;
    Sample current = minimum;
    ranges->set_range(bucket_index, current);
    size_t bucket_count = ranges->bucket_count();
    while (bucket_count > ++bucket_index)
    {
        double log_current;
        log_current = log(static_cast<double>(current));
        // Calculate the count'th root of the range.
        log_ratio = (log_max - log_current) / static_cast<double>(bucket_count - bucket_index);
        // See where the next bucket would start.
        log_next = log_current + log_ratio;
        Sample next;
        next = static_cast<int>(floor(exp(log_next) + 0.5));
        if (next > current)
            current = next;
        else
            ++current;  // Just do a narrow bucket, and keep trying.
        ranges->set_range(bucket_index, current);
    }
    ranges->set_range(ranges->bucket_count(), kSampleTypeMax);
}

Sample Histogram::ranges(size_t i) const
{
    return bucket_ranges_->range(i);
}

size_t Histogram::bucket_count() const
{
    return bucket_ranges_->bucket_count();
}

// static
bool Histogram::InspectConstructionArguments(const std::string& name,
                                             Sample* minimum,
                                             Sample* maximum,
                                             size_t* bucket_count)
{
    // Defensive code for backward compatibility.
    if (*minimum < 1)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
        *minimum = 1;
    }

    if (*maximum >= kSampleTypeMax)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
        *maximum = kSampleTypeMax - 1;
    }

    if (*bucket_count >= kBucketCountMax)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
        //         << *bucket_count;
        *bucket_count = kBucketCountMax - 1;
    }

    if (*minimum >= *maximum)
        return false;
    if (*bucket_count < 3)
        return false;
    if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
        return false;
    return true;
}

std::string Histogram::type() const
{
    return std::string("Histogram");
}

void Histogram::Add(int value)
{
    DCHECK_EQ(0, ranges(0));
    DCHECK_EQ(kSampleTypeMax, ranges(bucket_count()));

    if (value >= kSampleTypeMax)
        value = kSampleTypeMax - 1;
    if (value < 0)
        value = 0;
    samples_->Accumulate(value, 1);
}

std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const
{
    return std::move(std::unique_ptr<HistogramSamples>(SnapshotSampleVector().release()));
}

void Histogram::AddSamples(const HistogramSamples& samples)
{
    samples_->Add(samples);
}

// The following methods provide a graphical histogram display.
void Histogram::WriteHTMLGraph(std::string* output) const
{
    // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
    output->append("
");
    WriteAsciiImpl(true, "
", output);
    output->append("
");
}

void Histogram::WriteAscii(std::string* output) const
{
    WriteAsciiImpl(true, "\n", output);
}

void Histogram::WriteJSON(std::string* output) const
{
    rapidjson::Document doc;
    doc.SetObject();
    doc.AddMember("name", histogram_name().c_str(), doc.GetAllocator());

    auto snapshot = SnapshotSampleVector();
    doc.AddMember("count", snapshot->TotalCount(), doc.GetAllocator());
    doc.AddMember("sum", snapshot->sum(), doc.GetAllocator());

    doc.AddMember("type", type().c_str(), doc.GetAllocator());
    doc.AddMember("min", declared_min(), doc.GetAllocator());
    doc.AddMember("max", declared_max(), doc.GetAllocator());
    doc.AddMember("bucket_count", bucket_count(), doc.GetAllocator());

    rapidjson::Value buckets(rapidjson::kArrayType);
    for (size_t i = 0; i < bucket_count(); i++)
    {
        Sample count = snapshot->GetCountAtIndex(i);
        if (count > 0)
        {
            rapidjson::Value bucket_value;
            bucket_value.AddMember("low", ranges(i), doc.GetAllocator());

            if (i != bucket_count() - 1)
            {
                bucket_value.AddMember("high", ranges(i+1), doc.GetAllocator());
                bucket_value.AddMember("count", count, doc.GetAllocator());
            }
            buckets.PushBack(bucket_value, doc.GetAllocator());
        }
    }
    doc.AddMember("buckets", buckets, doc.GetAllocator());

    rapidjson::StringBuffer buffer;
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
    doc.Accept(writer);

    output->assign(buffer.GetString());
    return ;
}

bool Histogram::PrintEmptyBucket(size_t index) const
{
    return true;
}

// Use the actual bucket widths (like a linear histogram) until the widths get
// over some transition value, and then use that transition width.  Exponentials
// get so big so fast (and we don't expect to see a lot of entries in the large
// buckets), so we need this to make it possible to see what is going on and
// not have 0-graphical-height buckets.
double Histogram::GetBucketSize(Count current, size_t i) const
{
    DCHECK_GT(ranges(i + 1), ranges(i));
    static const double kTransitionWidth = 5;
    double denominator = ranges(i + 1) - ranges(i);
    if (denominator > kTransitionWidth)
        denominator = kTransitionWidth;  // Stop trying to normalize.
    return current/denominator;
}

const std::string Histogram::GetAsciiBucketRange(size_t i) const
{
    return GetSimpleAsciiBucketRange(ranges(i));
}

std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const
{
    std::unique_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
    samples->Add(*samples_);
    return std::move(samples);
}

const std::string Histogram::GetSimpleAsciiBucketRange(Sample sample) const
{
    std::string result;
    StringAppendF(&result, "%d", sample);
    return result;
}

void Histogram::WriteAsciiBucketGraph(double current_size,
                                      double max_size,
                                      std::string* output) const
{
    const int k_line_length = 72;  // Maximal horizontal width of graph.
    int x_count = static_cast<int>(k_line_length * (current_size / max_size) + 0.5);
    int x_remainder = k_line_length - x_count;

    while (0 < x_count--)
        output->append("-");
    output->append("O");
    while (0 < x_remainder--)
        output->append(" ");
}

void Histogram::WriteAsciiBucketValue(Count current,
                                      double scaled_sum,
                                      std::string* output) const
{
    StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
}

void Histogram::WriteAsciiImpl(bool graph_it,
                               const std::string& newline,
                               std::string* output) const
{
    // Get local (stack) copies of all effectively volatile class data so that we
    // are consistent across our output activities.
    auto snapshot = SnapshotSampleVector();
    Count sample_count = snapshot->TotalCount();

    WriteAsciiHeader(*snapshot, sample_count, output);
    output->append(newline);

    // Prepare to normalize graphical rendering of bucket contents.
    double max_size = 0;
    if (graph_it)
        max_size = GetPeakBucketSize(*snapshot);

    // Calculate space needed to print bucket range numbers.  Leave room to print
    // nearly the largest bucket range without sliding over the histogram.
    size_t largest_non_empty_bucket = bucket_count() - 1;
    while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket))
    {
        if (0 == largest_non_empty_bucket)
            break;  // All buckets are empty.
        --largest_non_empty_bucket;
    }

    // Calculate largest print width needed for any of our bucket range displays.
    size_t print_width = 1;
    for (size_t i = 0; i < bucket_count(); ++i)
    {
        if (snapshot->GetCountAtIndex(i))
        {
            size_t width = GetAsciiBucketRange(i).size() + 1;
            if (width > print_width)
                print_width = width;
        }
    }

    int64_t remaining = sample_count;
    int64_t past = 0;
    // Output the actual histogram graph.
    for (size_t i = 0; i < bucket_count(); ++i)
    {
        Count current = snapshot->GetCountAtIndex(i);
        if (!current && !PrintEmptyBucket(i))
            continue;
        remaining -= current;
        auto range = GetAsciiBucketRange(i);
        output->append(range);
        for (size_t j = 0; range.size() + j < print_width + 1; ++j)
            output->push_back(' ');
        if (0 == current && i < bucket_count() - 1 &&
            0 == snapshot->GetCountAtIndex(i + 1))
        {
            while (i < bucket_count() - 1 &&
                   0 == snapshot->GetCountAtIndex(i + 1))
            {
                ++i;
            }
            output->append("... ");
            output->append(newline);
            continue;  // No reason to plot emptiness.
        }
        double current_size = GetBucketSize(current, i);
        if (graph_it)
            WriteAsciiBucketGraph(current_size, max_size, output);
        WriteAsciiBucketContext(past, current, remaining, i, output);
        output->append(newline);
        past += current;
    }
    DCHECK_EQ(sample_count, past);
}

double Histogram::GetPeakBucketSize(const SampleVector& samples) const
{
    double max = 0;
    for (size_t i = 0; i < bucket_count() ; ++i)
    {
        double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
        if (current_size > max)
            max = current_size;
    }
    return max;
}

void Histogram::WriteAsciiHeader(const SampleVector& samples,
                                 Count sample_count,
                                 std::string* output) const
{
    StringAppendF(output,
                  "Histogram: %s recorded %d samples",
                  histogram_name().c_str(),
                  sample_count);
    if (0 == sample_count)
    {
        DCHECK_EQ(samples.sum(), 0);
    }
    else
    {
        double average = static_cast<double>(samples.sum()) / sample_count;
        StringAppendF(output, ", average = %.1f", average);
    }
}

void Histogram::WriteAsciiBucketContext(const int64_t past,
                                        const Count current,
                                        const int64_t remaining,
                                        const size_t i,
                                        std::string* output) const
{
    double scaled_sum = static_cast<double>(past + current + remaining) / 100.0;
    WriteAsciiBucketValue(current, scaled_sum, output);
    if (0 < i)
    {
        double percentage = static_cast<double>(past) / scaled_sum;
        StringAppendF(output, " {%3.1f%%}", percentage);
    }
}

} // namespace claire
<commit_msg>fix unique_ptr return syntax<commit_after>// Copyright (c) 2013 The claire-common Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <claire/common/metrics/Histogram.h>

#include <math.h>
#include <limits.h>

#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>

#include <claire/common/strings/StringPrintf.h>
#include <claire/common/metrics/HistogramSamples.h>
#include <claire/common/metrics/BucketRanges.h>
#include <claire/common/metrics/SampleVector.h>
#include <claire/common/metrics/HistogramRecorder.h>
#include <claire/common/logging/Logging.h>

namespace claire {

const Histogram::Sample Histogram::kSampleTypeMax = INT_MAX;
const size_t Histogram::kBucketCountMax = 16384u;

typedef Histogram::Count Count;
typedef Histogram::Sample Sample;

Histogram* Histogram::FactoryGet(const std::string& name,
                                 Sample minimum,
                                 Sample maximum,
                                 size_t bucket_count)
{
    auto histogram = HistogramRecorder::instance()->FindHistogram(name);
    if (!histogram)
    {
        Histogram* tentative_histogram =
            new Histogram(name, minimum, maximum, bucket_count);
        histogram =
            HistogramRecorder::instance()->RegisterOrDeleteDuplicate(tentative_histogram);
    }

    return histogram;
}

Histogram::Histogram(const std::string& name,
                     Sample minimum,
                     Sample maximum,
                     size_t bucket_count__)
    : histogram_name_(name),
      bucket_ranges_(new BucketRanges(bucket_count__+1)),
      declared_min_(minimum),
      declared_max_(maximum)
{
    InitializeBucketRanges(minimum, maximum, bucket_ranges_.get());
    samples_.reset(new SampleVector(bucket_ranges_.get()));
}

Histogram::~Histogram() {}

void Histogram::InitializeBucketRanges(Sample minimum, Sample maximum, BucketRanges* ranges)
{
    double log_max = log(static_cast<double>(maximum));
    double log_ratio;
    double log_next;
    size_t bucket_index = 1;
    Sample current = minimum;
    ranges->set_range(bucket_index, current);
    size_t bucket_count = ranges->bucket_count();
    while (bucket_count > ++bucket_index)
    {
        double log_current;
        log_current = log(static_cast<double>(current));
        // Calculate the count'th root of the range.
        log_ratio = (log_max - log_current) / static_cast<double>(bucket_count - bucket_index);
        // See where the next bucket would start.
        log_next = log_current + log_ratio;
        Sample next;
        next = static_cast<int>(floor(exp(log_next) + 0.5));
        if (next > current)
            current = next;
        else
            ++current;  // Just do a narrow bucket, and keep trying.
        ranges->set_range(bucket_index, current);
    }
    ranges->set_range(ranges->bucket_count(), kSampleTypeMax);
}

Sample Histogram::ranges(size_t i) const
{
    return bucket_ranges_->range(i);
}

size_t Histogram::bucket_count() const
{
    return bucket_ranges_->bucket_count();
}

// static
bool Histogram::InspectConstructionArguments(const std::string& name,
                                             Sample* minimum,
                                             Sample* maximum,
                                             size_t* bucket_count)
{
    // Defensive code for backward compatibility.
    if (*minimum < 1)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
        *minimum = 1;
    }

    if (*maximum >= kSampleTypeMax)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
        *maximum = kSampleTypeMax - 1;
    }

    if (*bucket_count >= kBucketCountMax)
    {
        //DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
        //         << *bucket_count;
        *bucket_count = kBucketCountMax - 1;
    }

    if (*minimum >= *maximum)
        return false;
    if (*bucket_count < 3)
        return false;
    if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
        return false;
    return true;
}

std::string Histogram::type() const
{
    return std::string("Histogram");
}

void Histogram::Add(int value)
{
    DCHECK_EQ(0, ranges(0));
    DCHECK_EQ(kSampleTypeMax, ranges(bucket_count()));

    if (value >= kSampleTypeMax)
        value = kSampleTypeMax - 1;
    if (value < 0)
        value = 0;
    samples_->Accumulate(value, 1);
}

std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const
{
    return std::unique_ptr<HistogramSamples>(SnapshotSampleVector().release());
}

void Histogram::AddSamples(const HistogramSamples& samples)
{
    samples_->Add(samples);
}

// The following methods provide a graphical histogram display.
void Histogram::WriteHTMLGraph(std::string* output) const
{
    // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
    output->append("
");
    WriteAsciiImpl(true, "
", output);
    output->append("
");
}

void Histogram::WriteAscii(std::string* output) const
{
    WriteAsciiImpl(true, "\n", output);
}

void Histogram::WriteJSON(std::string* output) const
{
    rapidjson::Document doc;
    doc.SetObject();
    doc.AddMember("name", histogram_name().c_str(), doc.GetAllocator());

    auto snapshot = SnapshotSampleVector();
    doc.AddMember("count", snapshot->TotalCount(), doc.GetAllocator());
    doc.AddMember("sum", snapshot->sum(), doc.GetAllocator());

    doc.AddMember("type", type().c_str(), doc.GetAllocator());
    doc.AddMember("min", declared_min(), doc.GetAllocator());
    doc.AddMember("max", declared_max(), doc.GetAllocator());
    doc.AddMember("bucket_count", bucket_count(), doc.GetAllocator());

    rapidjson::Value buckets(rapidjson::kArrayType);
    for (size_t i = 0; i < bucket_count(); i++)
    {
        Sample count = snapshot->GetCountAtIndex(i);
        if (count > 0)
        {
            rapidjson::Value bucket_value;
            bucket_value.AddMember("low", ranges(i), doc.GetAllocator());

            if (i != bucket_count() - 1)
            {
                bucket_value.AddMember("high", ranges(i+1), doc.GetAllocator());
                bucket_value.AddMember("count", count, doc.GetAllocator());
            }
            buckets.PushBack(bucket_value, doc.GetAllocator());
        }
    }
    doc.AddMember("buckets", buckets, doc.GetAllocator());

    rapidjson::StringBuffer buffer;
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
    doc.Accept(writer);

    output->assign(buffer.GetString());
    return ;
}

bool Histogram::PrintEmptyBucket(size_t index) const
{
    return true;
}

// Use the actual bucket widths (like a linear histogram) until the widths get
// over some transition value, and then use that transition width.  Exponentials
// get so big so fast (and we don't expect to see a lot of entries in the large
// buckets), so we need this to make it possible to see what is going on and
// not have 0-graphical-height buckets.
double Histogram::GetBucketSize(Count current, size_t i) const
{
    DCHECK_GT(ranges(i + 1), ranges(i));
    static const double kTransitionWidth = 5;
    double denominator = ranges(i + 1) - ranges(i);
    if (denominator > kTransitionWidth)
        denominator = kTransitionWidth;  // Stop trying to normalize.
    return current/denominator;
}

const std::string Histogram::GetAsciiBucketRange(size_t i) const
{
    return GetSimpleAsciiBucketRange(ranges(i));
}

std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const
{
    std::unique_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
    samples->Add(*samples_);
    return samples;
}

const std::string Histogram::GetSimpleAsciiBucketRange(Sample sample) const
{
    std::string result;
    StringAppendF(&result, "%d", sample);
    return result;
}

void Histogram::WriteAsciiBucketGraph(double current_size,
                                      double max_size,
                                      std::string* output) const
{
    const int k_line_length = 72;  // Maximal horizontal width of graph.
    int x_count = static_cast<int>(k_line_length * (current_size / max_size) + 0.5);
    int x_remainder = k_line_length - x_count;

    while (0 < x_count--)
        output->append("-");
    output->append("O");
    while (0 < x_remainder--)
        output->append(" ");
}

void Histogram::WriteAsciiBucketValue(Count current,
                                      double scaled_sum,
                                      std::string* output) const
{
    StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
}

void Histogram::WriteAsciiImpl(bool graph_it,
                               const std::string& newline,
                               std::string* output) const
{
    // Get local (stack) copies of all effectively volatile class data so that we
    // are consistent across our output activities.
    auto snapshot = SnapshotSampleVector();
    Count sample_count = snapshot->TotalCount();

    WriteAsciiHeader(*snapshot, sample_count, output);
    output->append(newline);

    // Prepare to normalize graphical rendering of bucket contents.
    double max_size = 0;
    if (graph_it)
        max_size = GetPeakBucketSize(*snapshot);

    // Calculate space needed to print bucket range numbers.  Leave room to print
    // nearly the largest bucket range without sliding over the histogram.
    size_t largest_non_empty_bucket = bucket_count() - 1;
    while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket))
    {
        if (0 == largest_non_empty_bucket)
            break;  // All buckets are empty.
        --largest_non_empty_bucket;
    }

    // Calculate largest print width needed for any of our bucket range displays.
    size_t print_width = 1;
    for (size_t i = 0; i < bucket_count(); ++i)
    {
        if (snapshot->GetCountAtIndex(i))
        {
            size_t width = GetAsciiBucketRange(i).size() + 1;
            if (width > print_width)
                print_width = width;
        }
    }

    int64_t remaining = sample_count;
    int64_t past = 0;
    // Output the actual histogram graph.
    for (size_t i = 0; i < bucket_count(); ++i)
    {
        Count current = snapshot->GetCountAtIndex(i);
        if (!current && !PrintEmptyBucket(i))
            continue;
        remaining -= current;
        auto range = GetAsciiBucketRange(i);
        output->append(range);
        for (size_t j = 0; range.size() + j < print_width + 1; ++j)
            output->push_back(' ');
        if (0 == current && i < bucket_count() - 1 &&
            0 == snapshot->GetCountAtIndex(i + 1))
        {
            while (i < bucket_count() - 1 &&
                   0 == snapshot->GetCountAtIndex(i + 1))
            {
                ++i;
            }
            output->append("... ");
            output->append(newline);
            continue;  // No reason to plot emptiness.
        }
        double current_size = GetBucketSize(current, i);
        if (graph_it)
            WriteAsciiBucketGraph(current_size, max_size, output);
        WriteAsciiBucketContext(past, current, remaining, i, output);
        output->append(newline);
        past += current;
    }
    DCHECK_EQ(sample_count, past);
}

double Histogram::GetPeakBucketSize(const SampleVector& samples) const
{
    double max = 0;
    for (size_t i = 0; i < bucket_count() ; ++i)
    {
        double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
        if (current_size > max)
            max = current_size;
    }
    return max;
}

void Histogram::WriteAsciiHeader(const SampleVector& samples,
                                 Count sample_count,
                                 std::string* output) const
{
    StringAppendF(output,
                  "Histogram: %s recorded %d samples",
                  histogram_name().c_str(),
                  sample_count);
    if (0 == sample_count)
    {
        DCHECK_EQ(samples.sum(), 0);
    }
    else
    {
        double average = static_cast<double>(samples.sum()) / sample_count;
        StringAppendF(output, ", average = %.1f", average);
    }
}

void Histogram::WriteAsciiBucketContext(const int64_t past,
                                        const Count current,
                                        const int64_t remaining,
                                        const size_t i,
                                        std::string* output) const
{
    double scaled_sum = static_cast<double>(past + current + remaining) / 100.0;
    WriteAsciiBucketValue(current, scaled_sum, output);
    if (0 < i)
    {
        double percentage = static_cast<double>(past) / scaled_sum;
        StringAppendF(output, " {%3.1f%%}", percentage);
    }
}

} // namespace claire
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "./vpx_config.h"
#include "vpx_ports/mem.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/encode_test_driver.h"
#include "test/register_state_check.h"
#include "test/video_source.h"

namespace libvpx_test {
void Encoder::InitEncoder(VideoSource *video) {
  vpx_codec_err_t res;
  const vpx_image_t *img = video->img();

  if (video->img() && !encoder_.priv) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    cfg_.g_timebase = video->timebase();
    cfg_.rc_twopass_stats_in = stats_->buf();

    res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
                             init_flags_);
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();

#if CONFIG_VP9_ENCODER
    if (CodecInterface() == &vpx_codec_vp9_cx_algo) {
      // Default to 1 tile column for VP9.
      const int log2_tile_columns = 0;
      res = vpx_codec_control_(&encoder_, VP9E_SET_TILE_COLUMNS,
                               log2_tile_columns);
      ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
    } else
#endif
#if CONFIG_VP10_ENCODER
    if (CodecInterface() == &vpx_codec_vp10_cx_algo) {
      // Default to 1 tile column for VP10. With CONFIG_EXT_TILE, the
      // default is already the largest possible tile size
#if !CONFIG_EXT_TILE
      const int log2_tile_columns = 0;
      res = vpx_codec_control_(&encoder_, VP9E_SET_TILE_COLUMNS,
                               log2_tile_columns);
      ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
#endif  // !CONFIG_EXT_TILE
    } else
#endif
    {
#if CONFIG_VP8_ENCODER
      if (CodecInterface() == &vpx_codec_vp8_cx_algo) {
        ASSERT_EQ(&vpx_codec_vp8_cx_algo, CodecInterface())
            << "Unknown Codec Interface";
      }
#endif
    }
  }
}

void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
  if (video->img())
    EncodeFrameInternal(*video, frame_flags);
  else
    Flush();

  // Handle twopass stats
  CxDataIterator iter = GetCxData();

  while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
    if (pkt->kind != VPX_CODEC_STATS_PKT)
      continue;

    stats_->Append(*pkt);
  }
}

void Encoder::EncodeFrameInternal(const VideoSource &video,
                                  const unsigned long frame_flags) {
  vpx_codec_err_t res;
  const vpx_image_t *img = video.img();

  // Handle frame resizing
  if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    res = vpx_codec_enc_config_set(&encoder_, &cfg_);
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
  }

  // Encode the frame
  API_REGISTER_STATE_CHECK(
      res = vpx_codec_encode(&encoder_, img, video.pts(), video.duration(),
                             frame_flags, deadline_));
  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

void Encoder::Flush() {
  const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
                                               deadline_);
  if (!encoder_.priv)
    ASSERT_EQ(VPX_CODEC_ERROR, res) << EncoderError();
  else
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

void EncoderTest::InitializeConfig() {
  const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
  dec_cfg_ = vpx_codec_dec_cfg_t();
  ASSERT_EQ(VPX_CODEC_OK, res);
}

void EncoderTest::SetMode(TestMode mode) {
  switch (mode) {
    case kRealTime:
      deadline_ = VPX_DL_REALTIME;
      break;

    case kOnePassGood:
    case kTwoPassGood:
      deadline_ = VPX_DL_GOOD_QUALITY;
      break;

    case kOnePassBest:
    case kTwoPassBest:
      deadline_ = VPX_DL_BEST_QUALITY;
      break;

    default:
      ASSERT_TRUE(false) << "Unexpected mode " << mode;
  }

  if (mode == kTwoPassGood || mode == kTwoPassBest)
    passes_ = 2;
  else
    passes_ = 1;
}

static bool compare_plane(const uint8_t *const buf1, const int stride1,
                          const uint8_t *const buf2, const int stride2,
                          const int w, const int h,
                          int *const mismatch_row,
                          int *const mismatch_col,
                          int *const mismatch_pix1,
                          int *const mismatch_pix2) {
  int r, c;

  for (r = 0; r < h; ++r) {
    for (c = 0; c < w; ++c) {
      const int pix1 = buf1[r * stride1 + c];
      const int pix2 = buf2[r * stride2 + c];

      if (pix1 != pix2) {
        if (mismatch_row != NULL)
          *mismatch_row = r;
        if (mismatch_col != NULL)
          *mismatch_col = c;
        if (mismatch_pix1 != NULL)
          *mismatch_pix1 = pix1;
        if (mismatch_pix2 != NULL)
          *mismatch_pix2 = pix2;
        return false;
      }
    }
  }

  return true;
}

// The function should return "true" most of the time, therefore no early
// break-out is implemented within the match checking process.
static bool compare_img(const vpx_image_t *img1,
                        const vpx_image_t *img2,
                        int *const mismatch_row,
                        int *const mismatch_col,
                        int *const mismatch_plane,
                        int *const mismatch_pix1,
                        int *const mismatch_pix2) {

  const unsigned int w_y = img1->d_w;
  const unsigned int h_y = img1->d_h;
  const unsigned int w_uv = ROUNDZ_POWER_OF_TWO(w_y, img1->x_chroma_shift);
  const unsigned int h_uv = ROUNDZ_POWER_OF_TWO(h_y, img1->y_chroma_shift);

  if (img1->fmt != img2->fmt
      || img1->cs != img2->cs
      || img1->d_w != img2->d_w
      || img1->d_h != img2->d_h) {
    if (mismatch_row != NULL)
      *mismatch_row = -1;
    if (mismatch_col != NULL)
      *mismatch_col = -1;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_Y],  img1->stride[VPX_PLANE_Y],
                     img2->planes[VPX_PLANE_Y],  img2->stride[VPX_PLANE_Y],
                     w_y, h_y,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_Y;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_U],  img1->stride[VPX_PLANE_U],
                     img2->planes[VPX_PLANE_U],  img2->stride[VPX_PLANE_U],
                     w_uv, h_uv,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_U;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_V],  img1->stride[VPX_PLANE_V],
                     img2->planes[VPX_PLANE_V],  img2->stride[VPX_PLANE_V],
                     w_uv, h_uv,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_U;
    return false;
  }

  return true;
}

void EncoderTest::MismatchHook(const vpx_image_t* img_enc,
                               const vpx_image_t* img_dec) {
  int mismatch_row;
  int mismatch_col;
  int mismatch_plane;
  int mismatch_pix_enc;
  int mismatch_pix_dec;

  ASSERT_FALSE(compare_img(img_enc, img_dec,
                           &mismatch_row, &mismatch_col,
                           &mismatch_plane,
                           &mismatch_pix_enc,
                           &mismatch_pix_dec));

  GTEST_FAIL()
    << "Encode/Decode mismatch found:"
    << std::endl
    << "  pixel value enc/dec: "  << mismatch_pix_enc << "/" << mismatch_pix_dec
    << std::endl
    << "                plane: " << mismatch_plane
    << std::endl
    << "              row/col: " << mismatch_row << "/" << mismatch_col
    << std::endl;
}

void EncoderTest::RunLoop(VideoSource *video) {
  vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();

  stats_.Reset();

  ASSERT_TRUE(passes_ == 1 || passes_ == 2);
  for (unsigned int pass = 0; pass < passes_; pass++) {
    last_pts_ = 0;

    if (passes_ == 1)
      cfg_.g_pass = VPX_RC_ONE_PASS;
    else if (pass == 0)
      cfg_.g_pass = VPX_RC_FIRST_PASS;
    else
      cfg_.g_pass = VPX_RC_LAST_PASS;

    BeginPassHook(pass);
    Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_,
                                                   &stats_);
    ASSERT_TRUE(encoder != NULL);

    video->Begin();
    encoder->InitEncoder(video);
    ASSERT_FALSE(::testing::Test::HasFatalFailure());

    unsigned long dec_init_flags = 0;  // NOLINT
    // Use fragment decoder if encoder outputs partitions.
    // NOTE: fragment decoder and partition encoder are only supported by VP8.
    if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION)
      dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS;
    Decoder* const decoder = codec_->CreateDecoder(dec_cfg, dec_init_flags, 0);
#if CONFIG_VP10 && CONFIG_EXT_TILE
    if (decoder->IsVP10()) {
      // Set dec_cfg.tile_row = -1 and dec_cfg.tile_col = -1 so that the whole
      // frame is decoded.
      decoder->Control(VP10_SET_DECODE_TILE_ROW, -1);
      decoder->Control(VP10_SET_DECODE_TILE_COL, -1);
    }
#endif

    bool again;
    for (again = true; again; video->Next()) {
      again = (video->img() != NULL);

      PreEncodeFrameHook(video);
      PreEncodeFrameHook(video, encoder);
      encoder->EncodeFrame(video, frame_flags_);

      CxDataIterator iter = encoder->GetCxData();

      bool has_cxdata = false;
      bool has_dxdata = false;
      while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
        pkt = MutateEncoderOutputHook(pkt);
        again = true;
        switch (pkt->kind) {
          case VPX_CODEC_CX_FRAME_PKT:
            has_cxdata = true;
            if (decoder && DoDecode()) {
              vpx_codec_err_t res_dec = decoder->DecodeFrame(
                  (const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz);

              if (!HandleDecodeResult(res_dec, *video, decoder))
                break;

              has_dxdata = true;
            }
            ASSERT_GE(pkt->data.frame.pts, last_pts_);
            last_pts_ = pkt->data.frame.pts;
            FramePktHook(pkt);
            break;

          case VPX_CODEC_PSNR_PKT:
            PSNRPktHook(pkt);
            break;

          default:
            break;
        }
      }

      // Flush the decoder when there are no more fragments.
      if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) {
        const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
        if (!HandleDecodeResult(res_dec, *video, decoder))
          break;
      }

      if (has_dxdata && has_cxdata) {
        const vpx_image_t *img_enc = encoder->GetPreviewFrame();
        DxDataIterator dec_iter = decoder->GetDxData();
        const vpx_image_t *img_dec = dec_iter.Next();
        if (img_enc && img_dec) {
          const bool res = compare_img(img_enc, img_dec,
                                       NULL, NULL, NULL, NULL, NULL);
          if (!res) {  // Mismatch
            MismatchHook(img_enc, img_dec);
          }
        }
        if (img_dec)
          DecompressedFrameHook(*img_dec, video->pts());
      }
      if (!Continue())
        break;
    }

    EndPassHook();

    if (decoder)
      delete decoder;
    delete encoder;

    if (!Continue())
      break;
  }
}

}  // namespace libvpx_test
<commit_msg>Fix false uninitialized warnings (GCC 5+).<commit_after>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "./vpx_config.h"
#include "vpx_ports/mem.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/encode_test_driver.h"
#include "test/register_state_check.h"
#include "test/video_source.h"

namespace libvpx_test {
void Encoder::InitEncoder(VideoSource *video) {
  vpx_codec_err_t res;
  const vpx_image_t *img = video->img();

  if (video->img() && !encoder_.priv) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    cfg_.g_timebase = video->timebase();
    cfg_.rc_twopass_stats_in = stats_->buf();

    res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
                             init_flags_);
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();

#if CONFIG_VP9_ENCODER
    if (CodecInterface() == &vpx_codec_vp9_cx_algo) {
      // Default to 1 tile column for VP9.
      const int log2_tile_columns = 0;
      res = vpx_codec_control_(&encoder_, VP9E_SET_TILE_COLUMNS,
                               log2_tile_columns);
      ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
    } else
#endif
#if CONFIG_VP10_ENCODER
    if (CodecInterface() == &vpx_codec_vp10_cx_algo) {
      // Default to 1 tile column for VP10. With CONFIG_EXT_TILE, the
      // default is already the largest possible tile size
#if !CONFIG_EXT_TILE
      const int log2_tile_columns = 0;
      res = vpx_codec_control_(&encoder_, VP9E_SET_TILE_COLUMNS,
                               log2_tile_columns);
      ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
#endif  // !CONFIG_EXT_TILE
    } else
#endif
    {
#if CONFIG_VP8_ENCODER
      if (CodecInterface() == &vpx_codec_vp8_cx_algo) {
        ASSERT_EQ(&vpx_codec_vp8_cx_algo, CodecInterface())
            << "Unknown Codec Interface";
      }
#endif
    }
  }
}

void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
  if (video->img())
    EncodeFrameInternal(*video, frame_flags);
  else
    Flush();

  // Handle twopass stats
  CxDataIterator iter = GetCxData();

  while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
    if (pkt->kind != VPX_CODEC_STATS_PKT)
      continue;

    stats_->Append(*pkt);
  }
}

void Encoder::EncodeFrameInternal(const VideoSource &video,
                                  const unsigned long frame_flags) {
  vpx_codec_err_t res;
  const vpx_image_t *img = video.img();

  // Handle frame resizing
  if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    res = vpx_codec_enc_config_set(&encoder_, &cfg_);
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
  }

  // Encode the frame
  API_REGISTER_STATE_CHECK(
      res = vpx_codec_encode(&encoder_, img, video.pts(), video.duration(),
                             frame_flags, deadline_));
  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

void Encoder::Flush() {
  const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
                                               deadline_);
  if (!encoder_.priv)
    ASSERT_EQ(VPX_CODEC_ERROR, res) << EncoderError();
  else
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

void EncoderTest::InitializeConfig() {
  const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
  dec_cfg_ = vpx_codec_dec_cfg_t();
  ASSERT_EQ(VPX_CODEC_OK, res);
}

void EncoderTest::SetMode(TestMode mode) {
  switch (mode) {
    case kRealTime:
      deadline_ = VPX_DL_REALTIME;
      break;

    case kOnePassGood:
    case kTwoPassGood:
      deadline_ = VPX_DL_GOOD_QUALITY;
      break;

    case kOnePassBest:
    case kTwoPassBest:
      deadline_ = VPX_DL_BEST_QUALITY;
      break;

    default:
      ASSERT_TRUE(false) << "Unexpected mode " << mode;
  }

  if (mode == kTwoPassGood || mode == kTwoPassBest)
    passes_ = 2;
  else
    passes_ = 1;
}

static bool compare_plane(const uint8_t *const buf1, const int stride1,
                          const uint8_t *const buf2, const int stride2,
                          const int w, const int h,
                          int *const mismatch_row,
                          int *const mismatch_col,
                          int *const mismatch_pix1,
                          int *const mismatch_pix2) {
  int r, c;

  for (r = 0; r < h; ++r) {
    for (c = 0; c < w; ++c) {
      const int pix1 = buf1[r * stride1 + c];
      const int pix2 = buf2[r * stride2 + c];

      if (pix1 != pix2) {
        if (mismatch_row != NULL)
          *mismatch_row = r;
        if (mismatch_col != NULL)
          *mismatch_col = c;
        if (mismatch_pix1 != NULL)
          *mismatch_pix1 = pix1;
        if (mismatch_pix2 != NULL)
          *mismatch_pix2 = pix2;
        return false;
      }
    }
  }

  return true;
}

// The function should return "true" most of the time, therefore no early
// break-out is implemented within the match checking process.
static bool compare_img(const vpx_image_t *img1,
                        const vpx_image_t *img2,
                        int *const mismatch_row,
                        int *const mismatch_col,
                        int *const mismatch_plane,
                        int *const mismatch_pix1,
                        int *const mismatch_pix2) {

  const unsigned int w_y = img1->d_w;
  const unsigned int h_y = img1->d_h;
  const unsigned int w_uv = ROUNDZ_POWER_OF_TWO(w_y, img1->x_chroma_shift);
  const unsigned int h_uv = ROUNDZ_POWER_OF_TWO(h_y, img1->y_chroma_shift);

  if (img1->fmt != img2->fmt
      || img1->cs != img2->cs
      || img1->d_w != img2->d_w
      || img1->d_h != img2->d_h) {
    if (mismatch_row != NULL)
      *mismatch_row = -1;
    if (mismatch_col != NULL)
      *mismatch_col = -1;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_Y],  img1->stride[VPX_PLANE_Y],
                     img2->planes[VPX_PLANE_Y],  img2->stride[VPX_PLANE_Y],
                     w_y, h_y,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_Y;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_U],  img1->stride[VPX_PLANE_U],
                     img2->planes[VPX_PLANE_U],  img2->stride[VPX_PLANE_U],
                     w_uv, h_uv,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_U;
    return false;
  }

  if (!compare_plane(img1->planes[VPX_PLANE_V],  img1->stride[VPX_PLANE_V],
                     img2->planes[VPX_PLANE_V],  img2->stride[VPX_PLANE_V],
                     w_uv, h_uv,
                     mismatch_row, mismatch_col,
                     mismatch_pix1, mismatch_pix2)) {
    if (mismatch_plane != NULL)
      *mismatch_plane = VPX_PLANE_U;
    return false;
  }

  return true;
}

void EncoderTest::MismatchHook(const vpx_image_t* img_enc,
                               const vpx_image_t* img_dec) {
  int mismatch_row = 0;
  int mismatch_col = 0;
  int mismatch_plane = 0;
  int mismatch_pix_enc = 0;
  int mismatch_pix_dec = 0;

  ASSERT_FALSE(compare_img(img_enc, img_dec,
                           &mismatch_row, &mismatch_col,
                           &mismatch_plane,
                           &mismatch_pix_enc,
                           &mismatch_pix_dec));

  GTEST_FAIL()
    << "Encode/Decode mismatch found:"
    << std::endl
    << "  pixel value enc/dec: "  << mismatch_pix_enc << "/" << mismatch_pix_dec
    << std::endl
    << "                plane: " << mismatch_plane
    << std::endl
    << "              row/col: " << mismatch_row << "/" << mismatch_col
    << std::endl;
}

void EncoderTest::RunLoop(VideoSource *video) {
  vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();

  stats_.Reset();

  ASSERT_TRUE(passes_ == 1 || passes_ == 2);
  for (unsigned int pass = 0; pass < passes_; pass++) {
    last_pts_ = 0;

    if (passes_ == 1)
      cfg_.g_pass = VPX_RC_ONE_PASS;
    else if (pass == 0)
      cfg_.g_pass = VPX_RC_FIRST_PASS;
    else
      cfg_.g_pass = VPX_RC_LAST_PASS;

    BeginPassHook(pass);
    Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_,
                                                   &stats_);
    ASSERT_TRUE(encoder != NULL);

    video->Begin();
    encoder->InitEncoder(video);
    ASSERT_FALSE(::testing::Test::HasFatalFailure());

    unsigned long dec_init_flags = 0;  // NOLINT
    // Use fragment decoder if encoder outputs partitions.
    // NOTE: fragment decoder and partition encoder are only supported by VP8.
    if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION)
      dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS;
    Decoder* const decoder = codec_->CreateDecoder(dec_cfg, dec_init_flags, 0);
#if CONFIG_VP10 && CONFIG_EXT_TILE
    if (decoder->IsVP10()) {
      // Set dec_cfg.tile_row = -1 and dec_cfg.tile_col = -1 so that the whole
      // frame is decoded.
      decoder->Control(VP10_SET_DECODE_TILE_ROW, -1);
      decoder->Control(VP10_SET_DECODE_TILE_COL, -1);
    }
#endif

    bool again;
    for (again = true; again; video->Next()) {
      again = (video->img() != NULL);

      PreEncodeFrameHook(video);
      PreEncodeFrameHook(video, encoder);
      encoder->EncodeFrame(video, frame_flags_);

      CxDataIterator iter = encoder->GetCxData();

      bool has_cxdata = false;
      bool has_dxdata = false;
      while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
        pkt = MutateEncoderOutputHook(pkt);
        again = true;
        switch (pkt->kind) {
          case VPX_CODEC_CX_FRAME_PKT:
            has_cxdata = true;
            if (decoder && DoDecode()) {
              vpx_codec_err_t res_dec = decoder->DecodeFrame(
                  (const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz);

              if (!HandleDecodeResult(res_dec, *video, decoder))
                break;

              has_dxdata = true;
            }
            ASSERT_GE(pkt->data.frame.pts, last_pts_);
            last_pts_ = pkt->data.frame.pts;
            FramePktHook(pkt);
            break;

          case VPX_CODEC_PSNR_PKT:
            PSNRPktHook(pkt);
            break;

          default:
            break;
        }
      }

      // Flush the decoder when there are no more fragments.
      if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) {
        const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
        if (!HandleDecodeResult(res_dec, *video, decoder))
          break;
      }

      if (has_dxdata && has_cxdata) {
        const vpx_image_t *img_enc = encoder->GetPreviewFrame();
        DxDataIterator dec_iter = decoder->GetDxData();
        const vpx_image_t *img_dec = dec_iter.Next();
        if (img_enc && img_dec) {
          const bool res = compare_img(img_enc, img_dec,
                                       NULL, NULL, NULL, NULL, NULL);
          if (!res) {  // Mismatch
            MismatchHook(img_enc, img_dec);
          }
        }
        if (img_dec)
          DecompressedFrameHook(*img_dec, video->pts());
      }
      if (!Continue())
        break;
    }

    EndPassHook();

    if (decoder)
      delete decoder;
    delete encoder;

    if (!Continue())
      break;
  }
}

}  // namespace libvpx_test
<|endoftext|>


<commit_before>//Copyright (c) 2012 Christian Schwarz
//
//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 "baseerrormeasure.h"

namespace errors {
    namespace baseerrormeasure {
        namespace BaseErrorMeasure {

            PyObject* initialize(PyObject* self, PyObject *originalTimeSeries, PyObject *calculatedTimesSeries)
            {
                if (0 < PySequence_Size(PyObject_GetAttrString(self, "_errorValues"))) {
                    PyErr_SetString(PyExc_StandardError, "An ErrorMeasure can only be initialized once.");
                    return NULL;
                }
                PyObject_CallMethodObjArgs(originalTimeSeries, PyString_FromString("sort_timeseries"), NULL);
                PyObject_CallMethodObjArgs(calculatedTimesSeries, PyString_FromString("sort_timeseries"), NULL);

                int index = 0;
                PyObject *orgPair, *calcPair, *local_error;
                PyObject *_errorValues = PyList_New(PyObject_Length(originalTimeSeries));
                PyObject *iterator1 = PyObject_GetIter(originalTimeSeries);

                while ((orgPair = PyIter_Next(iterator1))) {
                    PyObject *iterator2 = PyObject_GetIter(calculatedTimesSeries);
                    while ((calcPair = PyIter_Next(iterator2))) {
                        if (PyFloat_AsDouble(PySequence_GetItem(orgPair, 0)) != PyFloat_AsDouble(PySequence_GetItem(calcPair, 0))) {
                            continue;
                        }

                        local_error = PyObject_CallMethodObjArgs(self, PyString_FromString("local_error"), PySequence_GetItem(orgPair, 1), PySequence_GetItem(calcPair, 1), NULL);
                        if(!local_error) {
                            //NotImplemented Exception
                            return NULL;
                        }

                        PyList_SetItem(_errorValues, index, local_error);
                        ++index;

                        Py_DECREF(calcPair);
                    }
                    Py_DECREF(iterator2);
                    Py_DECREF(orgPair);
                }
                Py_DECREF(iterator1);

                _errorValues = PyList_GetSlice(_errorValues, 0, index); //Cut off trailing zeroes
                //return False, if the error cannot be calculated
                double _minimalErrorCalculationPercentage = PyFloat_AsDouble(PyObject_GetAttrString(self, "_minimalErrorCalculationPercentage"));
                if(PyList_Size(_errorValues) < (_minimalErrorCalculationPercentage * PyObject_Length(originalTimeSeries))) {
                    Py_RETURN_FALSE;
                }

                PyObject_SetAttrString(self, "_errorValues", _errorValues);
                Py_RETURN_TRUE;
            }

        }

        //BaseErrorMeasure::BaseErrorMeasure(int minimalErrorCalculationPercentage):
        //    _minimalErrorCalculationPercentage(minimalErrorCalculationPercentage)
        //{
        //
        //}
        //
        //BaseErrorMeasure::~BaseErrorMeasure() {
        //
        //}
    }
}
<commit_msg>masters beautification ;)<commit_after>//Copyright (c) 2012 Christian Schwarz
//
//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 "baseerrormeasure.h"

namespace errors {
    namespace baseerrormeasure {
        namespace BaseErrorMeasure {

            PyObject* initialize(PyObject* self, PyObject *originalTimeSeries, PyObject *calculatedTimesSeries)
            {
                if (0 < PySequence_Size(PyObject_GetAttrString(self, "_errorValues"))) {
                    PyErr_SetString(PyExc_StandardError, "An ErrorMeasure can only be initialized once.");
                    return NULL;
                }

                PyObject_CallMethodObjArgs(originalTimeSeries,    PyString_FromString("sort_timeseries"), NULL);
                PyObject_CallMethodObjArgs(calculatedTimesSeries, PyString_FromString("sort_timeseries"), NULL);

                int index = 0;
                PyObject* orgPair;
                PyObject* calcPair;
                PyObject* local_error;

                PyObject* _errorValues = PyList_New(PyObject_Length(originalTimeSeries));
                PyObject* iterator1 = PyObject_GetIter(originalTimeSeries);

                while ((orgPair = PyIter_Next(iterator1))) {

                    PyObject* iterator2 = PyObject_GetIter(calculatedTimesSeries);

                    while ((calcPair = PyIter_Next(iterator2))) {
                        if (PyFloat_AsDouble(PySequence_GetItem(orgPair, 0)) != PyFloat_AsDouble(PySequence_GetItem(calcPair, 0)))
                            continue;

                        local_error = PyObject_CallMethodObjArgs(self, PyString_FromString("local_error"), PySequence_GetItem(orgPair, 1), PySequence_GetItem(calcPair, 1), NULL);

                        //NotImplemented Exception
                        if(!local_error) {
                            PyErr_SetString(PyExc_NotImplementedError, "");
                            return NULL;
                        }

                        PyList_SetItem(_errorValues, index, local_error);
                        ++index;

                        Py_DECREF(calcPair);
                    }

                    Py_DECREF(iterator2);
                    Py_DECREF(orgPair);
                }

                Py_DECREF(iterator1);

                //Cut off trailing zeroes
                _errorValues = PyList_GetSlice(_errorValues, 0, index);

                //return False, if the error cannot be calculated
                double _minimalErrorCalculationPercentage = PyFloat_AsDouble(PyObject_GetAttrString(self, "_minimalErrorCalculationPercentage"));

                if(PyList_Size(_errorValues) < (_minimalErrorCalculationPercentage * PyObject_Length(originalTimeSeries)))
                    Py_RETURN_FALSE;

                PyObject_SetAttrString(self, "_errorValues", _errorValues);
                Py_RETURN_TRUE;
            }

        }
    }
}
<|endoftext|>