<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018-2020 Couchbase, Inc.
 *
 *   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 "internal.h"

#include <iostream>
#include <vector>

#define LOGARGS(tracer, lvl) tracer->m_settings, "tracer", LCB_LOG_##lvl, __FILE__, __LINE__

using namespace lcb::trace;

LIBCOUCHBASE_API lcbtrace_TRACER *lcbtrace_new(lcb_INSTANCE *instance, uint64_t flags)
{
    if (instance == NULL || (flags & LCBTRACE_F_THRESHOLD) == 0) {
        return NULL;
    }
    return (new ThresholdLoggingTracer(instance))->wrap();
}

extern "C" {
static void tlt_destructor(lcbtrace_TRACER *wrapper)
{
    if (wrapper == NULL) {
        return;
    }
    if (wrapper->cookie) {
        ThresholdLoggingTracer *tracer = reinterpret_cast< ThresholdLoggingTracer * >(wrapper->cookie);
        tracer->do_flush_orphans();
        tracer->do_flush_threshold();
        delete tracer;
        wrapper->cookie = NULL;
    }
    delete wrapper;
}

static void tlt_report(lcbtrace_TRACER *wrapper, lcbtrace_SPAN *span)
{
    if (wrapper == NULL || wrapper->cookie == NULL) {
        return;
    }

    ThresholdLoggingTracer *tracer = reinterpret_cast< ThresholdLoggingTracer * >(wrapper->cookie);
    char *value = NULL;
    size_t nvalue;
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_SERVICE, &value, &nvalue) == LCB_SUCCESS) {
        if (strncmp(value, LCBTRACE_TAG_SERVICE_KV, nvalue) == 0) {
            if (lcbtrace_span_is_orphaned(span)) {
                tracer->add_orphan(span);
            } else {
                tracer->check_threshold(span);
            }
        }
    }
}
}

lcbtrace_TRACER *ThresholdLoggingTracer::wrap()
{
    if (m_wrapper) {
        return m_wrapper;
    }
    m_wrapper = new lcbtrace_TRACER();
    m_wrapper->version = 0;
    m_wrapper->flags = 0;
    m_wrapper->cookie = this;
    m_wrapper->destructor = tlt_destructor;
    m_wrapper->v.v0.report = tlt_report;
    return m_wrapper;
}

QueueEntry ThresholdLoggingTracer::convert(lcbtrace_SPAN *span)
{
    QueueEntry orphan;
    orphan.duration = span->duration();
    Json::Value entry;
    char *value;
    size_t nvalue;

    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_OPERATION_ID, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_operation_id"] = std::string(span->m_opname) + ":" + std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_LOCAL_ID, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_local_id"] = std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_LOCAL_ADDRESS, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_local_address"] = std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_PEER_ADDRESS, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_remote_address"] = std::string(value, value + nvalue);
    }
    uint64_t num;
    if (lcbtrace_span_get_tag_uint64(span, LCBTRACE_TAG_PEER_LATENCY, &num) == LCB_SUCCESS) {
        entry["server_us"] = (Json::UInt64)num;
    }
    entry["total_us"] = (Json::UInt64)orphan.duration;
    orphan.payload = Json::FastWriter().write(entry);
    return orphan;
}

void ThresholdLoggingTracer::add_orphan(lcbtrace_SPAN *span)
{
    m_orphans.push(convert(span));
}

void ThresholdLoggingTracer::check_threshold(lcbtrace_SPAN *span)
{
    if (span->duration() > m_settings->tracer_threshold[LCBTRACE_THRESHOLD_KV]) {
        m_threshold.push(convert(span));
    }
}

void ThresholdLoggingTracer::flush_queue(FixedSpanQueue &queue, const char *message, bool warn = false)
{
    Json::Value entries;
    entries["service"] = "kv";
    entries["count"] = (Json::UInt)queue.size();
    Json::Value top;
    while (!queue.empty()) {
        Json::Value entry;
        if (Json::Reader().parse(queue.top().payload, entry)) {
            top.append(entry);
        }
        queue.pop();
    }
    entries["top"] = top;
    std::string doc = Json::FastWriter().write(entries);
    if (doc.size() > 0 && doc[doc.size() - 1] == '\n') {
        doc[doc.size() - 1] = '\0';
    }
    if (warn) {
        lcb_log(LOGARGS(this, WARN), "%s: %s", message, doc.c_str());
    } else {
        lcb_log(LOGARGS(this, INFO), "%s: %s", message, doc.c_str());
    }
}

void ThresholdLoggingTracer::do_flush_orphans()
{
    if (m_orphans.empty()) {
        return;
    }
    flush_queue(m_orphans, "Orphan responses observed", true);
}

void ThresholdLoggingTracer::do_flush_threshold()
{
    if (m_threshold.empty()) {
        return;
    }
    flush_queue(m_threshold, "Operations over threshold");
}

void ThresholdLoggingTracer::flush_orphans()
{
    lcb_U32 tv = m_settings->tracer_orphaned_queue_flush_interval;
    if (tv == 0) {
        m_oflush.cancel();
    } else {
        m_oflush.rearm(tv);
    }
    do_flush_orphans();
}

void ThresholdLoggingTracer::flush_threshold()
{
    lcb_U32 tv = m_settings->tracer_threshold_queue_flush_interval;
    if (tv == 0) {
        m_tflush.cancel();
    } else {
        m_tflush.rearm(tv);
    }
    do_flush_threshold();
}

ThresholdLoggingTracer::ThresholdLoggingTracer(lcb_INSTANCE *instance)
    : m_wrapper(NULL), m_settings(instance->settings), m_orphans(LCBT_SETTING(instance, tracer_orphaned_queue_size)),
      m_threshold(LCBT_SETTING(instance, tracer_threshold_queue_size)), m_oflush(instance->iotable, this),
      m_tflush(instance->iotable, this)
{
    lcb_U32 tv = m_settings->tracer_orphaned_queue_flush_interval;
    if (tv > 0) {
        m_oflush.rearm(tv);
    }
    tv = m_settings->tracer_threshold_queue_flush_interval;
    if (tv > 0) {
        m_tflush.rearm(tv);
    }
}
<commit_msg>CCBC-1233: Updated RTO to independently specify operation_name.<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018-2020 Couchbase, Inc.
 *
 *   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 "internal.h"

#include <iostream>
#include <vector>

#define LOGARGS(tracer, lvl) tracer->m_settings, "tracer", LCB_LOG_##lvl, __FILE__, __LINE__

using namespace lcb::trace;

LIBCOUCHBASE_API lcbtrace_TRACER *lcbtrace_new(lcb_INSTANCE *instance, uint64_t flags)
{
    if (instance == NULL || (flags & LCBTRACE_F_THRESHOLD) == 0) {
        return NULL;
    }
    return (new ThresholdLoggingTracer(instance))->wrap();
}

extern "C" {
static void tlt_destructor(lcbtrace_TRACER *wrapper)
{
    if (wrapper == NULL) {
        return;
    }
    if (wrapper->cookie) {
        ThresholdLoggingTracer *tracer = reinterpret_cast< ThresholdLoggingTracer * >(wrapper->cookie);
        tracer->do_flush_orphans();
        tracer->do_flush_threshold();
        delete tracer;
        wrapper->cookie = NULL;
    }
    delete wrapper;
}

static void tlt_report(lcbtrace_TRACER *wrapper, lcbtrace_SPAN *span)
{
    if (wrapper == NULL || wrapper->cookie == NULL) {
        return;
    }

    ThresholdLoggingTracer *tracer = reinterpret_cast< ThresholdLoggingTracer * >(wrapper->cookie);
    char *value = NULL;
    size_t nvalue;
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_SERVICE, &value, &nvalue) == LCB_SUCCESS) {
        if (strncmp(value, LCBTRACE_TAG_SERVICE_KV, nvalue) == 0) {
            if (lcbtrace_span_is_orphaned(span)) {
                tracer->add_orphan(span);
            } else {
                tracer->check_threshold(span);
            }
        }
    }
}
}

lcbtrace_TRACER *ThresholdLoggingTracer::wrap()
{
    if (m_wrapper) {
        return m_wrapper;
    }
    m_wrapper = new lcbtrace_TRACER();
    m_wrapper->version = 0;
    m_wrapper->flags = 0;
    m_wrapper->cookie = this;
    m_wrapper->destructor = tlt_destructor;
    m_wrapper->v.v0.report = tlt_report;
    return m_wrapper;
}

QueueEntry ThresholdLoggingTracer::convert(lcbtrace_SPAN *span)
{
    QueueEntry orphan;
    orphan.duration = span->duration();
    Json::Value entry;
    char *value;
    size_t nvalue;

    entry["operation_name"] = std::string(span->m_opname);
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_OPERATION_ID, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_operation_id"] = std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_LOCAL_ID, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_local_id"] = std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_LOCAL_ADDRESS, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_local_address"] = std::string(value, value + nvalue);
    }
    if (lcbtrace_span_get_tag_str(span, LCBTRACE_TAG_PEER_ADDRESS, &value, &nvalue) == LCB_SUCCESS) {
        entry["last_remote_address"] = std::string(value, value + nvalue);
    }
    uint64_t num;
    if (lcbtrace_span_get_tag_uint64(span, LCBTRACE_TAG_PEER_LATENCY, &num) == LCB_SUCCESS) {
        entry["server_us"] = (Json::UInt64)num;
    }
    entry["total_us"] = (Json::UInt64)orphan.duration;
    orphan.payload = Json::FastWriter().write(entry);
    return orphan;
}

void ThresholdLoggingTracer::add_orphan(lcbtrace_SPAN *span)
{
    m_orphans.push(convert(span));
}

void ThresholdLoggingTracer::check_threshold(lcbtrace_SPAN *span)
{
    if (span->duration() > m_settings->tracer_threshold[LCBTRACE_THRESHOLD_KV]) {
        m_threshold.push(convert(span));
    }
}

void ThresholdLoggingTracer::flush_queue(FixedSpanQueue &queue, const char *message, bool warn = false)
{
    Json::Value entries;
    entries["service"] = "kv";
    entries["count"] = (Json::UInt)queue.size();
    Json::Value top;
    while (!queue.empty()) {
        Json::Value entry;
        if (Json::Reader().parse(queue.top().payload, entry)) {
            top.append(entry);
        }
        queue.pop();
    }
    entries["top"] = top;
    std::string doc = Json::FastWriter().write(entries);
    if (doc.size() > 0 && doc[doc.size() - 1] == '\n') {
        doc[doc.size() - 1] = '\0';
    }
    if (warn) {
        lcb_log(LOGARGS(this, WARN), "%s: %s", message, doc.c_str());
    } else {
        lcb_log(LOGARGS(this, INFO), "%s: %s", message, doc.c_str());
    }
}

void ThresholdLoggingTracer::do_flush_orphans()
{
    if (m_orphans.empty()) {
        return;
    }
    flush_queue(m_orphans, "Orphan responses observed", true);
}

void ThresholdLoggingTracer::do_flush_threshold()
{
    if (m_threshold.empty()) {
        return;
    }
    flush_queue(m_threshold, "Operations over threshold");
}

void ThresholdLoggingTracer::flush_orphans()
{
    lcb_U32 tv = m_settings->tracer_orphaned_queue_flush_interval;
    if (tv == 0) {
        m_oflush.cancel();
    } else {
        m_oflush.rearm(tv);
    }
    do_flush_orphans();
}

void ThresholdLoggingTracer::flush_threshold()
{
    lcb_U32 tv = m_settings->tracer_threshold_queue_flush_interval;
    if (tv == 0) {
        m_tflush.cancel();
    } else {
        m_tflush.rearm(tv);
    }
    do_flush_threshold();
}

ThresholdLoggingTracer::ThresholdLoggingTracer(lcb_INSTANCE *instance)
    : m_wrapper(NULL), m_settings(instance->settings), m_orphans(LCBT_SETTING(instance, tracer_orphaned_queue_size)),
      m_threshold(LCBT_SETTING(instance, tracer_threshold_queue_size)), m_oflush(instance->iotable, this),
      m_tflush(instance->iotable, this)
{
    lcb_U32 tv = m_settings->tracer_orphaned_queue_flush_interval;
    if (tv > 0) {
        m_oflush.rearm(tv);
    }
    tv = m_settings->tracer_threshold_queue_flush_interval;
    if (tv > 0) {
        m_tflush.rearm(tv);
    }
}
<|endoftext|>


<commit_before>// clang-format off
// REQUIRES: lld

// Test that we can display function signatures with class types.
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
// RUN:     %p/Inputs/function-types-classes.lldbinit | FileCheck %s

// This is just some unimportant helpers needed so that we can get reference and
// rvalue-reference types into return values.
template<typename T>
struct MakeResult {
  static T result() {
    return T{};
  }
};

template<typename T>
struct MakeResult<T&> {
  static T& result() {
    static T t;
    return t;
  }
};

template<typename T>
struct MakeResult<T&&> {
  static T&& result() {
    static T t;
    return static_cast<T&&>(t);
  }
};

template<typename R>
R nullary() { return MakeResult<R>::result(); }

template<typename R, typename A, typename B>
R three(A a, B b) { return MakeResult<R>::result(); }

template<typename R, typename A, typename B, typename C>
R four(A a, B b, C c) { return MakeResult<R>::result(); }

struct S {};
class C {};
union U {};
enum E {};

namespace A {
  namespace B {
    // NS::NS
    struct S { };
  }

  struct C {
    // NS::Struct
    struct S {};
  };
}

struct B {
  struct A {
    // Struct::Struct
    struct S {};
  };
};

// clang (incorrectly) doesn't emit debug information for outer classes
// unless they are instantiated.  They should also be emitted if there
// is an inner class which is instantiated.
A::C ForceInstantiateAC;
B ForceInstantiateB;
B::A ForceInstantiateBA;

template<typename T>
struct TC {};

// const and volatile modifiers
auto a = &four<S, C*, U&, E&&>;
// CHECK: (S (*)(C *, U &, E &&)) a = {{.*}}
auto b = &four<E, const S*, const C&, const U&&>;
// CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}}
auto c = &four<U, volatile E*, volatile S&, volatile C&&>;
// CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}}
auto d = &four<C, const volatile U*, const volatile E&, const volatile S&&>;
// CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}}

// classes nested in namespaces and inner classes

auto e = &three<A::B::S*, B::A::S*, A::C::S&>;
// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}}
auto f = &three<A::C::S&, A::B::S*, B::A::S*>;
// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}}
auto g = &three<B::A::S*, A::C::S&, A::B::S*>;
// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}}

// parameter types that are themselves template instantiations.
auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>;
// CHECK: (TC<void> (*)(TC<int>, TC<struct TC<int>>, TC<struct A::B::S>)) h = {{.*}}

auto i = &nullary<A::B::S>;
// CHECK: (A::B::S (*)()) i = {{.*}}

// Make sure we can handle types that don't have complete debug info.
struct Incomplete;
auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
// CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}}

// CHECK: TranslationUnitDecl {{.*}}
// CHECK: |-CXXRecordDecl {{.*}} class C
// CHECK: |-CXXRecordDecl {{.*}} union U
// CHECK: |-EnumDecl {{.*}} E
// CHECK: |-CXXRecordDecl {{.*}} struct S
// CHECK: |-CXXRecordDecl {{.*}} struct B
// CHECK: | |-CXXRecordDecl {{.*}} struct A
// CHECK: | | |-CXXRecordDecl {{.*}} struct S
// CHECK: |-NamespaceDecl {{.*}} A
// CHECK: | |-CXXRecordDecl {{.*}} struct C
// CHECK: | | |-CXXRecordDecl {{.*}} struct S
// CHECK: | `-NamespaceDecl {{.*}} B
// CHECK: |   `-CXXRecordDecl {{.*}} struct S
// CHECK: |-CXXRecordDecl {{.*}} struct TC<int>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct TC<int>>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct A::B::S>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<void>
// CHECK: |-CXXRecordDecl {{.*}} struct Incomplete

int main(int argc, char **argv) {
  return 0;
}
<commit_msg>[NativePDB] Update function-types-classes test to check VarDecls.<commit_after>// clang-format off
// REQUIRES: lld

// Test that we can display function signatures with class types.
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
// RUN:     %p/Inputs/function-types-classes.lldbinit | FileCheck %s

// This is just some unimportant helpers needed so that we can get reference and
// rvalue-reference types into return values.
template<typename T>
struct MakeResult {
  static T result() {
    return T{};
  }
};

template<typename T>
struct MakeResult<T&> {
  static T& result() {
    static T t;
    return t;
  }
};

template<typename T>
struct MakeResult<T&&> {
  static T&& result() {
    static T t;
    return static_cast<T&&>(t);
  }
};

template<typename R>
R nullary() { return MakeResult<R>::result(); }

template<typename R, typename A, typename B>
R three(A a, B b) { return MakeResult<R>::result(); }

template<typename R, typename A, typename B, typename C>
R four(A a, B b, C c) { return MakeResult<R>::result(); }

struct S {};
class C {};
union U {};
enum E {};

namespace A {
  namespace B {
    // NS::NS
    struct S { };
  }

  struct C {
    // NS::Struct
    struct S {};
  };
}

struct B {
  struct A {
    // Struct::Struct
    struct S {};
  };
};

// clang (incorrectly) doesn't emit debug information for outer classes
// unless they are instantiated.  They should also be emitted if there
// is an inner class which is instantiated.
A::C ForceInstantiateAC;
B ForceInstantiateB;
B::A ForceInstantiateBA;

template<typename T>
struct TC {};

// const and volatile modifiers
auto a = &four<S, C*, U&, E&&>;
// CHECK: (S (*)(C *, U &, E &&)) a = {{.*}}
auto b = &four<E, const S*, const C&, const U&&>;
// CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}}
auto c = &four<U, volatile E*, volatile S&, volatile C&&>;
// CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}}
auto d = &four<C, const volatile U*, const volatile E&, const volatile S&&>;
// CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}}

// classes nested in namespaces and inner classes

auto e = &three<A::B::S*, B::A::S*, A::C::S&>;
// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}}
auto f = &three<A::C::S&, A::B::S*, B::A::S*>;
// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}}
auto g = &three<B::A::S*, A::C::S&, A::B::S*>;
// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}}

// parameter types that are themselves template instantiations.
auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>;
// CHECK: (TC<void> (*)(TC<int>, TC<TC<int>>, TC<A::B::S>)) h = {{.*}}

auto i = &nullary<A::B::S>;
// CHECK: (A::B::S (*)()) i = {{.*}}

// Make sure we can handle types that don't have complete debug info.
struct Incomplete;
auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
// CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}}

// CHECK: TranslationUnitDecl {{.*}}
// CHECK: |-CXXRecordDecl {{.*}} class C
// CHECK: |-CXXRecordDecl {{.*}} union U
// CHECK: |-EnumDecl {{.*}} E
// CHECK: |-CXXRecordDecl {{.*}} struct S
// CHECK: |-VarDecl {{.*}} a 'S (*)(C *, U &, E &&)'
// CHECK: |-VarDecl {{.*}} b 'E (*)(const S *, const C &, const U &&)'
// CHECK: |-VarDecl {{.*}} c 'U (*)(volatile E *, volatile S &, volatile C &&)'
// CHECK: |-VarDecl {{.*}} d 'C (*)(const volatile U *, const volatile E &, const volatile S &&)'
// CHECK: |-CXXRecordDecl {{.*}} struct B
// CHECK: | |-CXXRecordDecl {{.*}} struct A
// CHECK: | | |-CXXRecordDecl {{.*}} struct S
// CHECK: |-NamespaceDecl {{.*}} A
// CHECK: | |-CXXRecordDecl {{.*}} struct C
// CHECK: | | |-CXXRecordDecl {{.*}} struct S
// CHECK: | `-NamespaceDecl {{.*}} B
// CHECK: |   `-CXXRecordDecl {{.*}} struct S
// CHECK: |-VarDecl {{.*}} e 'A::B::S *(*)(B::A::S *, A::C::S &)'
// CHECK: |-VarDecl {{.*}} f 'A::C::S &(*)(A::B::S *, B::A::S *)'
// CHECK: |-VarDecl {{.*}} g 'B::A::S *(*)(A::C::S &, A::B::S *)'
// CHECK: |-CXXRecordDecl {{.*}} struct TC<int>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<TC<int>>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<A::B::S>
// CHECK: |-CXXRecordDecl {{.*}} struct TC<void>
// CHECK: |-VarDecl {{.*}} h 'TC<void> (*)(TC<int>, TC<TC<int>>, TC<A::B::S>)'
// CHECK: |-VarDecl {{.*}} i 'A::B::S (*)()'
// CHECK: |-CXXRecordDecl {{.*}} struct Incomplete
// CHECK: |-VarDecl {{.*}} incomplete 'Incomplete *(*)(Incomplete **, const Incomplete *)'

int main(int argc, char **argv) {
  return 0;
}
<|endoftext|>


<commit_before>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * 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.
*/

/*! \file SiconosCollisionManager.hpp
\brief A mechanics world is a Siconos InteractionManager that supports
  static contactors and dynamic contactors attached to special
  Dynamical Systems (BodyDS, derived from NewtonEulerDS) found in the
  NonSmoothDynamicalSystem.
*/

#ifndef SiconosCollisionManager_h
#define SiconosCollisionManager_h

#include <InteractionManager.hpp>
#include <SiconosContactor.hpp>
#include <SiconosCollisionQueryResult.hpp>

class SiconosCollisionManager : public InteractionManager
{
protected:
  /** serialization hooks
   */
  ACCEPT_SERIALIZATION(SiconosCollisionManager);

public:
  SiconosCollisionManager() : InteractionManager() {}
  virtual ~SiconosCollisionManager() {}

  /** An opaque handle can be used to refer to a specific static
   * contactor set previously added to the collision manager. */
  typedef void* StaticContactorSetID;

  /** Remove a body from the collision detector. This must be done
   *  after removing a body from the NonSmoothDynamicalSystem
   *  otherwise contact will occur with a non-graph body which results
   *  in failure. */
  virtual void removeBody(const SP::BodyDS& body) {}

  /** Perform an intersection test on all shapes in the contactors and
   * return a vector of all results, ordered by distance from start.
   \param start The starting point of the line segment in inertial
                frame (world) coordinates.
   \param end The ending point of the line segment in inertial frame
              (world) coordinates.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  lineIntersectionQuery(const SiconosVector& start,
                        const SiconosVector& end,
                        bool closestOnly=false,
                        bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are within a sphere defined by a point and
   * a radius and return them in an ordered list based on distance to
   * the center.
   \param center The center of the sphere in inertial frame (world) coordinates.
   \param radius The radius of the sphere.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inSphereQuery(const SiconosVector& center,
                double radius,
                bool closestOnly=false,
                bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are within a box defined by a center point
   * and a dimensions (3-vector), and return them in an ordered list
   * based on distance to the center.
   \param center The center of the box in inertial frame (world)
   coordinates.
   \param dimensions The dimensions of the box (3-vector).
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inBoxQuery(const SiconosVector& center,
             const SiconosVector& dimensions,
             bool closestOnly=false,
             bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are inside a half-space, defined by a point
   * and a normal direction.
   \param point The point defining the boundary of the half-space.
   \param normal The normal pointing away from the surface of the half-space.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inHalfSpaceQuery(const SiconosVector& point,
                   const SiconosVector& normal,
                   bool closestOnly=false,
                   bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

public:
  virtual StaticContactorSetID insertStaticContactorSet(
    SP::SiconosContactorSet cs, SP::SiconosVector position = SP::SiconosVector()) = 0;

  virtual bool removeStaticContactorSet(StaticContactorSetID id) = 0;
};

#endif /* SiconosCollisionManager.hpp */
<commit_msg>[mechanics] make insert/removeStaticContactorSet not pure abstract<commit_after>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * 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.
*/

/*! \file SiconosCollisionManager.hpp
\brief A mechanics world is a Siconos InteractionManager that supports
  static contactors and dynamic contactors attached to special
  Dynamical Systems (BodyDS, derived from NewtonEulerDS) found in the
  NonSmoothDynamicalSystem.
*/

#ifndef SiconosCollisionManager_h
#define SiconosCollisionManager_h

#include <InteractionManager.hpp>
#include <SiconosContactor.hpp>
#include <SiconosCollisionQueryResult.hpp>

class SiconosCollisionManager : public InteractionManager
{
protected:
  /** serialization hooks
   */
  ACCEPT_SERIALIZATION(SiconosCollisionManager);

public:
  SiconosCollisionManager() : InteractionManager() {}
  virtual ~SiconosCollisionManager() {}

  /** An opaque handle can be used to refer to a specific static
   * contactor set previously added to the collision manager. */
  typedef void* StaticContactorSetID;

  /** Remove a body from the collision detector. This must be done
   *  after removing a body from the NonSmoothDynamicalSystem
   *  otherwise contact will occur with a non-graph body which results
   *  in failure. */
  virtual void removeBody(const SP::BodyDS& body) {}

  /** Perform an intersection test on all shapes in the contactors and
   * return a vector of all results, ordered by distance from start.
   \param start The starting point of the line segment in inertial
                frame (world) coordinates.
   \param end The ending point of the line segment in inertial frame
              (world) coordinates.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  lineIntersectionQuery(const SiconosVector& start,
                        const SiconosVector& end,
                        bool closestOnly=false,
                        bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are within a sphere defined by a point and
   * a radius and return them in an ordered list based on distance to
   * the center.
   \param center The center of the sphere in inertial frame (world) coordinates.
   \param radius The radius of the sphere.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inSphereQuery(const SiconosVector& center,
                double radius,
                bool closestOnly=false,
                bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are within a box defined by a center point
   * and a dimensions (3-vector), and return them in an ordered list
   * based on distance to the center.
   \param center The center of the box in inertial frame (world)
   coordinates.
   \param dimensions The dimensions of the box (3-vector).
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inBoxQuery(const SiconosVector& center,
             const SiconosVector& dimensions,
             bool closestOnly=false,
             bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

  /** Find all shapes that are inside a half-space, defined by a point
   * and a normal direction.
   \param point The point defining the boundary of the half-space.
   \param normal The normal pointing away from the surface of the half-space.
   \param closestOnly If true, indicates only interested in first
                      result closest to half-space boundary, max size
                      of returned vector = 1.
   \param sorted If true, results are sorted by distance.
   \return A vector of SiconosCollisionQueryResult that contain
           information about the query results.
  */
  virtual std::vector<SP::SiconosCollisionQueryResult>
  inHalfSpaceQuery(const SiconosVector& point,
                   const SiconosVector& normal,
                   bool closestOnly=false,
                   bool sorted=true)
    { return std::vector<SP::SiconosCollisionQueryResult>(); }

public:
  /** Insert a static contactor set */
  virtual StaticContactorSetID insertStaticContactorSet(
    SP::SiconosContactorSet cs, SP::SiconosVector position = SP::SiconosVector())
    { return (StaticContactorSetID)0; }

  /** Remove a static contactor set.
   * \param id An identifier returned by insertStaticContactorSet. */
  virtual bool removeStaticContactorSet(StaticContactorSetID id)
    { return !id; };
};

#endif /* SiconosCollisionManager.hpp */
<|endoftext|>


<commit_before>#if defined(TI_WITH_CUDA)
#if defined(min)
#undef min
#endif
#if defined(max)
#undef max
#endif
#include <memory>
#include <cuda_runtime_api.h>
#include <cuda.h>
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h>
#include <taichi/platform/cuda/cuda_utils.h>
#include <taichi/platform/cuda/cuda_context.h>
#include <taichi/program.h>
#include <taichi/context.h>
#include <taichi/system/timer.h>
#include "../tlang_util.h"
#include "jit_session.h"

TLANG_NAMESPACE_BEGIN

class JITModuleCUDA : public JITModule {
 private:
  CUmodule module;

 public:
  JITModuleCUDA(CUmodule module) : module(module) {
  }

  virtual void *lookup_function(const std::string &name) {
    // auto _ = cuda_context->get_guard();
    cuda_context->make_current();
    CUfunction func;
    auto t = Time::get_time();
    check_cuda_error(cuModuleGetFunction(&func, module, name.c_str()));
    t = Time::get_time() - t;
    TI_TRACE("Kernel {} compilation time: {}ms", name, t * 1000);
    return (void *)func;
  }
};

class JITSessionCUDA : public JITSession {
 public:
  llvm::DataLayout DL;

  JITSessionCUDA(llvm::DataLayout data_layout) : DL(data_layout) {
  }

  virtual JITModule *add_module(std::unique_ptr<llvm::Module> M) override {
    auto ptx = compile_module_to_ptx(M);
    // auto _ = cuda_context->get_guard();
    cuda_context->make_current();
    // Create module for object
    CUmodule cudaModule;
    TI_TRACE("PTX size: {:.2f}KB", ptx.size() / 1024.0);
    auto t = Time::get_time();
    TI_TRACE("Loading module...");
    auto _ = std::lock_guard<std::mutex>(cuda_context->lock);
    check_cuda_error(
        cuModuleLoadDataEx(&cudaModule, ptx.c_str(), 0, nullptr, nullptr));
    TI_TRACE("CUDA module load time : {}ms", (Time::get_time() - t) * 1000);
    // cudaModules.push_back(cudaModule);
    modules.push_back(std::make_unique<JITModuleCUDA>(cudaModule));
    return modules.back().get();
  }

  virtual llvm::DataLayout get_data_layout() override {
    return DL;
  }

  static std::string compile_module_to_ptx(
      std::unique_ptr<llvm::Module> &module);
};

std::string cuda_mattrs() {
  return "+ptx50";
}

std::string JITSessionCUDA::compile_module_to_ptx(
    std::unique_ptr<llvm::Module> &module) {
  // Part of this function is borrowed from Halide::CodeGen_PTX_Dev.cpp
  using namespace llvm;

  llvm::Triple triple(module->getTargetTriple());

  // Allocate target machine

  std::string err_str;
  const llvm::Target *target =
      TargetRegistry::lookupTarget(triple.str(), err_str);
  TI_ERROR_UNLESS(target, err_str);

  bool fast_math = get_current_program().config.fast_math;

  TargetOptions options;
  options.PrintMachineCode = 0;
  if (fast_math) {
    options.AllowFPOpFusion = FPOpFusion::Fast;
    // See NVPTXISelLowering.cpp
    // Setting UnsafeFPMath true will result in approximations such as
    // sqrt.approx in PTX for both f32 and f64
    options.UnsafeFPMath = 1;
    options.NoInfsFPMath = 1;
    options.NoNaNsFPMath = 1;
  } else {
    options.AllowFPOpFusion = FPOpFusion::Strict;
    options.UnsafeFPMath = 0;
    options.NoInfsFPMath = 0;
    options.NoNaNsFPMath = 0;
  }
  options.HonorSignDependentRoundingFPMathOption = 0;
  options.NoZerosInBSS = 0;
  options.GuaranteedTailCallOpt = 0;
  options.StackAlignmentOverride = 0;

  std::unique_ptr<TargetMachine> target_machine(target->createTargetMachine(
      triple.str(), cuda_context->get_mcpu(), cuda_mattrs(), options,
      llvm::Reloc::PIC_, llvm::CodeModel::Small, CodeGenOpt::Aggressive));

  TI_ERROR_UNLESS(target_machine.get(), "Could not allocate target machine!");

  module->setDataLayout(target_machine->createDataLayout());

  // Set up passes
  llvm::SmallString<8> outstr;
  raw_svector_ostream ostream(outstr);
  ostream.SetUnbuffered();

  legacy::FunctionPassManager function_pass_manager(module.get());
  legacy::PassManager module_pass_manager;

  module_pass_manager.add(createTargetTransformInfoWrapperPass(
      target_machine->getTargetIRAnalysis()));
  function_pass_manager.add(createTargetTransformInfoWrapperPass(
      target_machine->getTargetIRAnalysis()));

  // NVidia's libdevice library uses a __nvvm_reflect to choose
  // how to handle denormalized numbers. (The pass replaces calls
  // to __nvvm_reflect with a constant via a map lookup. The inliner
  // pass then resolves these situations to fast code, often a single
  // instruction per decision point.)
  //
  // The default is (more) IEEE like handling. FTZ mode flushes them
  // to zero. (This may only apply to single-precision.)
  //
  // The libdevice documentation covers other options for math accuracy
  // such as replacing division with multiply by the reciprocal and
  // use of fused-multiply-add, but they do not seem to be controlled
  // by this __nvvvm_reflect mechanism and may be flags to earlier compiler
  // passes.
  const auto kFTZDenorms = 1;

  // Insert a module flag for the FTZ handling.
  module->addModuleFlag(llvm::Module::Override, "nvvm-reflect-ftz",
                        kFTZDenorms);

  if (kFTZDenorms) {
    for (llvm::Function &fn : *module) {
      fn.addFnAttr("nvptx-f32ftz", "true");
    }
  }

  PassManagerBuilder b;
  b.OptLevel = 3;
  b.Inliner = createFunctionInliningPass(b.OptLevel, 0, false);
  b.LoopVectorize = false;
  b.SLPVectorize = false;

  target_machine->adjustPassManager(b);

  b.populateFunctionPassManager(function_pass_manager);
  b.populateModulePassManager(module_pass_manager);

  // Override default to generate verbose assembly.
  target_machine->Options.MCOptions.AsmVerbose = true;

  // Output string stream

  // Ask the target to add backend passes as necessary.
  bool fail = target_machine->addPassesToEmitFile(
      module_pass_manager, ostream, nullptr, TargetMachine::CGFT_AssemblyFile,
      true);

  TI_ERROR_IF(fail, "Failed to set up passes to emit PTX source\n");

  // Run optimization passes
  function_pass_manager.doInitialization();
  for (llvm::Module::iterator i = module->begin(); i != module->end(); i++) {
    function_pass_manager.run(*i);
  }
  function_pass_manager.doFinalization();
  module_pass_manager.run(*module);

  std::string buffer(outstr.begin(), outstr.end());

  // Null-terminate the ptx source
  buffer.push_back(0);
  return buffer;
}

std::unique_ptr<JITSession> create_llvm_jit_session_cuda(Arch arch) {
  TI_ASSERT(arch == Arch::cuda);
  // TODO: assuming CUDA has the same data layout as the host arch
  std::unique_ptr<llvm::orc::JITTargetMachineBuilder> jtmb;
  auto JTMB = llvm::orc::JITTargetMachineBuilder::detectHost();
  if (!JTMB)
    TI_ERROR("LLVM TargetMachineBuilder has failed.");
  jtmb = std::make_unique<llvm::orc::JITTargetMachineBuilder>(std::move(*JTMB));

  auto DL = jtmb->getDefaultDataLayoutForTarget();
  if (!DL) {
    TI_ERROR("LLVM TargetMachineBuilder has failed when getting data layout.");
  }
  return std::make_unique<JITSessionCUDA>(DL.get());
}

TLANG_NAMESPACE_END
#endif
<commit_msg>fix non-cuda build<commit_after>#if defined(min)
#undef min
#endif
#if defined(max)
#undef max
#endif
#include <memory>
#include <cuda_runtime_api.h>
#include <cuda.h>
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h>
#include <taichi/platform/cuda/cuda_utils.h>
#include <taichi/platform/cuda/cuda_context.h>
#include <taichi/program.h>
#include <taichi/context.h>
#include <taichi/system/timer.h>
#include "../tlang_util.h"
#include "jit_session.h"

TLANG_NAMESPACE_BEGIN

#if defined(TI_WITH_CUDA)
class JITModuleCUDA : public JITModule {
 private:
  CUmodule module;

 public:
  JITModuleCUDA(CUmodule module) : module(module) {
  }

  virtual void *lookup_function(const std::string &name) {
    // auto _ = cuda_context->get_guard();
    cuda_context->make_current();
    CUfunction func;
    auto t = Time::get_time();
    check_cuda_error(cuModuleGetFunction(&func, module, name.c_str()));
    t = Time::get_time() - t;
    TI_TRACE("Kernel {} compilation time: {}ms", name, t * 1000);
    return (void *)func;
  }
};

class JITSessionCUDA : public JITSession {
 public:
  llvm::DataLayout DL;

  JITSessionCUDA(llvm::DataLayout data_layout) : DL(data_layout) {
  }

  virtual JITModule *add_module(std::unique_ptr<llvm::Module> M) override {
    auto ptx = compile_module_to_ptx(M);
    // auto _ = cuda_context->get_guard();
    cuda_context->make_current();
    // Create module for object
    CUmodule cudaModule;
    TI_TRACE("PTX size: {:.2f}KB", ptx.size() / 1024.0);
    auto t = Time::get_time();
    TI_TRACE("Loading module...");
    auto _ = std::lock_guard<std::mutex>(cuda_context->lock);
    check_cuda_error(
        cuModuleLoadDataEx(&cudaModule, ptx.c_str(), 0, nullptr, nullptr));
    TI_TRACE("CUDA module load time : {}ms", (Time::get_time() - t) * 1000);
    // cudaModules.push_back(cudaModule);
    modules.push_back(std::make_unique<JITModuleCUDA>(cudaModule));
    return modules.back().get();
  }

  virtual llvm::DataLayout get_data_layout() override {
    return DL;
  }

  static std::string compile_module_to_ptx(
      std::unique_ptr<llvm::Module> &module);
};

std::string cuda_mattrs() {
  return "+ptx50";
}

std::string JITSessionCUDA::compile_module_to_ptx(
    std::unique_ptr<llvm::Module> &module) {
  // Part of this function is borrowed from Halide::CodeGen_PTX_Dev.cpp
  using namespace llvm;

  llvm::Triple triple(module->getTargetTriple());

  // Allocate target machine

  std::string err_str;
  const llvm::Target *target =
      TargetRegistry::lookupTarget(triple.str(), err_str);
  TI_ERROR_UNLESS(target, err_str);

  bool fast_math = get_current_program().config.fast_math;

  TargetOptions options;
  options.PrintMachineCode = 0;
  if (fast_math) {
    options.AllowFPOpFusion = FPOpFusion::Fast;
    // See NVPTXISelLowering.cpp
    // Setting UnsafeFPMath true will result in approximations such as
    // sqrt.approx in PTX for both f32 and f64
    options.UnsafeFPMath = 1;
    options.NoInfsFPMath = 1;
    options.NoNaNsFPMath = 1;
  } else {
    options.AllowFPOpFusion = FPOpFusion::Strict;
    options.UnsafeFPMath = 0;
    options.NoInfsFPMath = 0;
    options.NoNaNsFPMath = 0;
  }
  options.HonorSignDependentRoundingFPMathOption = 0;
  options.NoZerosInBSS = 0;
  options.GuaranteedTailCallOpt = 0;
  options.StackAlignmentOverride = 0;

  std::unique_ptr<TargetMachine> target_machine(target->createTargetMachine(
      triple.str(), cuda_context->get_mcpu(), cuda_mattrs(), options,
      llvm::Reloc::PIC_, llvm::CodeModel::Small, CodeGenOpt::Aggressive));

  TI_ERROR_UNLESS(target_machine.get(), "Could not allocate target machine!");

  module->setDataLayout(target_machine->createDataLayout());

  // Set up passes
  llvm::SmallString<8> outstr;
  raw_svector_ostream ostream(outstr);
  ostream.SetUnbuffered();

  legacy::FunctionPassManager function_pass_manager(module.get());
  legacy::PassManager module_pass_manager;

  module_pass_manager.add(createTargetTransformInfoWrapperPass(
      target_machine->getTargetIRAnalysis()));
  function_pass_manager.add(createTargetTransformInfoWrapperPass(
      target_machine->getTargetIRAnalysis()));

  // NVidia's libdevice library uses a __nvvm_reflect to choose
  // how to handle denormalized numbers. (The pass replaces calls
  // to __nvvm_reflect with a constant via a map lookup. The inliner
  // pass then resolves these situations to fast code, often a single
  // instruction per decision point.)
  //
  // The default is (more) IEEE like handling. FTZ mode flushes them
  // to zero. (This may only apply to single-precision.)
  //
  // The libdevice documentation covers other options for math accuracy
  // such as replacing division with multiply by the reciprocal and
  // use of fused-multiply-add, but they do not seem to be controlled
  // by this __nvvvm_reflect mechanism and may be flags to earlier compiler
  // passes.
  const auto kFTZDenorms = 1;

  // Insert a module flag for the FTZ handling.
  module->addModuleFlag(llvm::Module::Override, "nvvm-reflect-ftz",
                        kFTZDenorms);

  if (kFTZDenorms) {
    for (llvm::Function &fn : *module) {
      fn.addFnAttr("nvptx-f32ftz", "true");
    }
  }

  PassManagerBuilder b;
  b.OptLevel = 3;
  b.Inliner = createFunctionInliningPass(b.OptLevel, 0, false);
  b.LoopVectorize = false;
  b.SLPVectorize = false;

  target_machine->adjustPassManager(b);

  b.populateFunctionPassManager(function_pass_manager);
  b.populateModulePassManager(module_pass_manager);

  // Override default to generate verbose assembly.
  target_machine->Options.MCOptions.AsmVerbose = true;

  // Output string stream

  // Ask the target to add backend passes as necessary.
  bool fail = target_machine->addPassesToEmitFile(
      module_pass_manager, ostream, nullptr, TargetMachine::CGFT_AssemblyFile,
      true);

  TI_ERROR_IF(fail, "Failed to set up passes to emit PTX source\n");

  // Run optimization passes
  function_pass_manager.doInitialization();
  for (llvm::Module::iterator i = module->begin(); i != module->end(); i++) {
    function_pass_manager.run(*i);
  }
  function_pass_manager.doFinalization();
  module_pass_manager.run(*module);

  std::string buffer(outstr.begin(), outstr.end());

  // Null-terminate the ptx source
  buffer.push_back(0);
  return buffer;
}

std::unique_ptr<JITSession> create_llvm_jit_session_cuda(Arch arch) {
  TI_ASSERT(arch == Arch::cuda);
  // TODO: assuming CUDA has the same data layout as the host arch
  std::unique_ptr<llvm::orc::JITTargetMachineBuilder> jtmb;
  auto JTMB = llvm::orc::JITTargetMachineBuilder::detectHost();
  if (!JTMB)
    TI_ERROR("LLVM TargetMachineBuilder has failed.");
  jtmb = std::make_unique<llvm::orc::JITTargetMachineBuilder>(std::move(*JTMB));

  auto DL = jtmb->getDefaultDataLayoutForTarget();
  if (!DL) {
    TI_ERROR("LLVM TargetMachineBuilder has failed when getting data layout.");
  }
  return std::make_unique<JITSessionCUDA>(DL.get());
}
#else
std::unique_ptr<JITSession> create_llvm_jit_session_cuda(Arch arch) {
  TI_NOT_IMPLEMENTED
}
#endif

TLANG_NAMESPACE_END
<|endoftext|>


<commit_before>/* Copyright 2020 Google LLC

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

    https://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 "ml_metadata/tools/mlmd_bench/fill_types_workload.h"

#include <random>

#include "absl/memory/memory.h"
#include "absl/strings/substitute.h"
#include "ml_metadata/metadata_store/metadata_store.h"
#include "ml_metadata/metadata_store/types.h"
#include "ml_metadata/proto/metadata_store.pb.h"
#include "ml_metadata/proto/metadata_store_service.pb.h"
#include "ml_metadata/tools/mlmd_bench/proto/mlmd_bench.pb.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"

namespace ml_metadata {
namespace {

// A template function where the Type can be ArtifactType / ExecutionType /
// ContextType. It takes a `type_name` to generate a type and generates number
// of properties w.r.t. to the uniform distribution.
template <typename Type>
void GenerateRandomType(const std::string& type_name,
                        std::uniform_int_distribution<int64>& uniform_dist,
                        std::minstd_rand0& gen, Type* type, int64* curr_bytes) {
  // The random type name will be a random number.
  type->set_name(type_name);
  // The curr_bytes records the total transferred bytes for executing each work
  // item.
  *curr_bytes += type->name().size();
  // Generates the number of properties for each type
  // w.r.t. the uniform distribution
  const int64 num_properties = uniform_dist(gen);
  for (int64 i = 0; i < num_properties; i++) {
    (*type->mutable_properties())[absl::StrCat("p-", i)] = STRING;
    *curr_bytes += absl::StrCat("p-", i).size();
  }
}

// Gets the number of current types(num_curr_type) and total
// types(num_total_type) for later insert or update. Also updates the
// get_response for later update. Returns detailed error if query executions
// failed.
tensorflow::Status GetNumberOfTypes(const FillTypesConfig& fill_types_config,
                                    MetadataStore*& store, int64& num_curr_type,
                                    int64& num_total_type,
                                    GetTypeResponseType& get_response) {
  int64 num_artifact_type = 0, num_execution_type = 0, num_context_type = 0;
  switch (fill_types_config.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      get_response.emplace<GetArtifactTypesResponse>();
      TF_RETURN_IF_ERROR(store->GetArtifactTypes(
          /*request=*/{}, &absl::get<GetArtifactTypesResponse>(get_response)));
      num_artifact_type = absl::get<GetArtifactTypesResponse>(get_response)
                              .artifact_types_size();
      num_curr_type = num_artifact_type;
      break;
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      get_response.emplace<GetExecutionTypesResponse>();
      TF_RETURN_IF_ERROR(store->GetExecutionTypes(
          /*request=*/{}, &absl::get<GetExecutionTypesResponse>(get_response)));
      num_execution_type = absl::get<GetExecutionTypesResponse>(get_response)
                               .execution_types_size();
      num_curr_type = num_execution_type;
      break;
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      get_response.emplace<GetContextTypesResponse>();
      TF_RETURN_IF_ERROR(store->GetContextTypes(
          /*request=*/{}, &absl::get<GetContextTypesResponse>(get_response)));
      num_context_type =
          absl::get<GetContextTypesResponse>(get_response).context_types_size();
      num_curr_type = num_context_type;
      break;
    }
    default:
      LOG(FATAL) << "Wrong specification for FillTypes!";
  }
  num_total_type = num_artifact_type + num_execution_type + num_context_type;
  return tensorflow::Status::OK();
}

// Inserts new types into the db if the current types inside db is not enough
// for update. Returns detailed error if query executions failed.
tensorflow::Status MakeUpTypesForUpdate(
    const FillTypesConfig& fill_types_config, MetadataStore*& store,
    int64 num_type_to_make_up) {
  FillTypesConfig make_up_config = fill_types_config;
  make_up_config.set_update(false);
  std::unique_ptr<FillTypes> make_up_fill_types;
  make_up_fill_types = absl::make_unique<FillTypes>(
      FillTypes(make_up_config, num_type_to_make_up));
  TF_RETURN_IF_ERROR(make_up_fill_types->SetUp(store));
  for (int64 i = 0; i < num_type_to_make_up; ++i) {
    OpStats op_stats;
    TF_RETURN_IF_ERROR(make_up_fill_types->RunOp(i, store, op_stats));
  }
  return tensorflow::Status::OK();
}

// A template function where the Type can be ArtifactType / ExecutionType /
// ContextType.
// Takes an existed type and generates a new type for later update accordingly.
// The updated type will have some new fields added and the number of new added
// fields will be generated w.r.t. the uniform distribution.
template <typename Type>
void UpdateType(std::uniform_int_distribution<int64>& uniform_dist,
                std::minstd_rand0& gen, const Type& existed_type,
                Type* updated_type, int64* curr_bytes) {
  // Except the new added fields, update_type will the same as existed_type.
  *updated_type = existed_type;
  *curr_bytes += existed_type.name().size();
  for (auto& pair : existed_type.properties()) {
    // pair.first is the property of existed_type.
    *curr_bytes += pair.first.size();
  }
  const int64 num_properties = uniform_dist(gen);
  for (int64 i = 0; i < num_properties; i++) {
    (*updated_type->mutable_properties())[absl::StrCat("add_p-", i)] = STRING;
    *curr_bytes += absl::StrCat("add_p-", i).size();
  }
}

}  // namespace

FillTypes::FillTypes(const FillTypesConfig& fill_types_config,
                     int64 num_operations)
    : fill_types_config_(fill_types_config), num_operations_(num_operations) {
  switch (fill_types_config_.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      name_ = "fill_artifact_type";
      break;
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      name_ = "fill_execution_type";
      break;
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      name_ = "fill_context_type";
      break;
    }
    default:
      LOG(FATAL) << "Wrong specification for FillTypes!";
  }
}

tensorflow::Status FillTypes::SetUpImpl(MetadataStore* store) {
  LOG(INFO) << "Setting up ...";

  int64 curr_bytes = 0;
  // Uniform distribution that describes the number of properties for each
  // generated types.
  UniformDistribution num_properties = fill_types_config_.num_properties();
  int64 min = num_properties.minimum();
  int64 max = num_properties.maximum();
  std::uniform_int_distribution<int64> uniform_dist{min, max};
  // The seed for the random generator is the time when the FillTypes is
  // created.
  std::minstd_rand0 gen(absl::ToUnixMillis(absl::Now()));

  // Gets the number of current types(num_curr_type) and total
  // types(num_total_type) for later insert or update.
  int64 num_curr_type = 0, num_total_type = 0;
  GetTypeResponseType get_response;
  TF_RETURN_IF_ERROR(GetNumberOfTypes(fill_types_config_, store, num_curr_type,
                                      num_total_type, get_response));

  // If the number of current types is less than the update number of
  // operations, calls MakeUpTypesForUpdate() for inserting new types into the
  // db for later update.
  if (fill_types_config_.update() && num_curr_type < num_operations_) {
    int64 num_type_to_make_up = num_operations_ - num_curr_type;
    TF_RETURN_IF_ERROR(
        MakeUpTypesForUpdate(fill_types_config_, store, num_type_to_make_up));
    // Updates the get_response to contain the up-to-date types inside db for
    // later update.
    TF_RETURN_IF_ERROR(GetNumberOfTypes(fill_types_config_, store,
                                        num_curr_type, num_total_type,
                                        get_response));
  }

  for (int64 i = num_total_type; i < num_total_type + num_operations_; i++) {
    curr_bytes = 0;
    int64 update_type_index = i - num_total_type;
    FillTypeWorkItemType put_request;
    const std::string type_name = absl::StrCat("type_", i);
    switch (fill_types_config_.specification()) {
      case FillTypesConfig::ARTIFACT_TYPE: {
        put_request.emplace<PutArtifactTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutArtifactTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ArtifactType>(
              uniform_dist, gen,
              absl::get<GetArtifactTypesResponse>(get_response)
                  .artifact_types()[update_type_index],
              absl::get<PutArtifactTypeRequest>(put_request)
                  .mutable_artifact_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ArtifactType>(
              type_name, uniform_dist, gen,
              absl::get<PutArtifactTypeRequest>(put_request)
                  .mutable_artifact_type(),
              &curr_bytes);
        }
        break;
      }
      case FillTypesConfig::EXECUTION_TYPE: {
        put_request.emplace<PutExecutionTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutExecutionTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ExecutionType>(
              uniform_dist, gen,
              absl::get<GetExecutionTypesResponse>(get_response)
                  .execution_types()[update_type_index],
              absl::get<PutExecutionTypeRequest>(put_request)
                  .mutable_execution_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ExecutionType>(
              type_name, uniform_dist, gen,
              absl::get<PutExecutionTypeRequest>(put_request)
                  .mutable_execution_type(),
              &curr_bytes);
        }
        break;
      }
      case FillTypesConfig::CONTEXT_TYPE: {
        put_request.emplace<PutContextTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutContextTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ContextType>(
              uniform_dist, gen,
              absl::get<GetContextTypesResponse>(get_response)
                  .context_types()[update_type_index],
              absl::get<PutContextTypeRequest>(put_request)
                  .mutable_context_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ContextType>(
              type_name, uniform_dist, gen,
              absl::get<PutContextTypeRequest>(put_request)
                  .mutable_context_type(),
              &curr_bytes);
        }
        break;
      }
      default:
        return tensorflow::errors::InvalidArgument("Wrong specification!");
    }
    // Updates work_items_.
    work_items_.emplace_back(put_request, curr_bytes);
  }
  return tensorflow::Status::OK();
}

// Executions of work items.
tensorflow::Status FillTypes::RunOpImpl(int64 i, MetadataStore* store) {
  switch (fill_types_config_.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      PutArtifactTypeRequest put_request =
          absl::get<PutArtifactTypeRequest>(work_items_[i].first);
      PutArtifactTypeResponse put_response;
      return store->PutArtifactType(put_request, &put_response);
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      PutExecutionTypeRequest put_request =
          absl::get<PutExecutionTypeRequest>(work_items_[i].first);
      PutExecutionTypeResponse put_response;
      return store->PutExecutionType(put_request, &put_response);
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      PutContextTypeRequest put_request =
          absl::get<PutContextTypeRequest>(work_items_[i].first);
      PutContextTypeResponse put_response;
      return store->PutContextType(put_request, &put_response);
    }
    default:
      return tensorflow::errors::InvalidArgument("Wrong specification!");
  }
  return tensorflow::errors::InvalidArgument(
      "Cannot execute the query due to wrong specification!");
}

tensorflow::Status FillTypes::TearDownImpl() {
  work_items_.clear();
  return tensorflow::Status::OK();
}

std::string FillTypes::GetName() { return name_; }

}  // namespace ml_metadata
<commit_msg>Fixs GetNumberOfTypes() for update mode of FillTypes.<commit_after>/* Copyright 2020 Google LLC

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

    https://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 "ml_metadata/tools/mlmd_bench/fill_types_workload.h"

#include <random>

#include "absl/memory/memory.h"
#include "absl/strings/substitute.h"
#include "ml_metadata/metadata_store/metadata_store.h"
#include "ml_metadata/metadata_store/types.h"
#include "ml_metadata/proto/metadata_store.pb.h"
#include "ml_metadata/proto/metadata_store_service.pb.h"
#include "ml_metadata/tools/mlmd_bench/proto/mlmd_bench.pb.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"

namespace ml_metadata {
namespace {

// A template function where the Type can be ArtifactType / ExecutionType /
// ContextType. It takes a `type_name` to generate a type and generates number
// of properties w.r.t. to the uniform distribution.
template <typename Type>
void GenerateRandomType(const std::string& type_name,
                        std::uniform_int_distribution<int64>& uniform_dist,
                        std::minstd_rand0& gen, Type* type, int64* curr_bytes) {
  // The random type name will be a random number.
  type->set_name(type_name);
  // The curr_bytes records the total transferred bytes for executing each work
  // item.
  *curr_bytes += type->name().size();
  // Generates the number of properties for each type
  // w.r.t. the uniform distribution
  const int64 num_properties = uniform_dist(gen);
  for (int64 i = 0; i < num_properties; i++) {
    (*type->mutable_properties())[absl::StrCat("p-", i)] = STRING;
    *curr_bytes += absl::StrCat("p-", i).size();
  }
}

// Gets the number of current types(num_curr_type) and total
// types(num_total_type) for later insert or update. Also updates the
// get_response for later update. Returns detailed error if query executions
// failed.
tensorflow::Status GetNumberOfTypes(const FillTypesConfig& fill_types_config,
                                    MetadataStore* store, int64& num_curr_type,
                                    int64& num_total_type,
                                    GetTypeResponseType& get_response) {
  GetArtifactTypesResponse get_artifact_type_response;
  TF_RETURN_IF_ERROR(store->GetArtifactTypes(
      /*request=*/{}, &get_artifact_type_response));
  int64 num_artifact_type = get_artifact_type_response.artifact_types_size();

  GetExecutionTypesResponse get_execution_type_response;
  TF_RETURN_IF_ERROR(store->GetExecutionTypes(
      /*request=*/{}, &get_execution_type_response));
  int64 num_execution_type = get_execution_type_response.execution_types_size();

  GetContextTypesResponse get_context_type_response;
  TF_RETURN_IF_ERROR(store->GetContextTypes(
      /*request=*/{}, &get_context_type_response));
  int64 num_context_type = get_context_type_response.context_types_size();

  switch (fill_types_config.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      num_curr_type = num_artifact_type;
      get_response.emplace<GetArtifactTypesResponse>(
          get_artifact_type_response);
      break;
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      num_curr_type = num_execution_type;
      get_response.emplace<GetExecutionTypesResponse>(
          get_execution_type_response);
      break;
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      num_curr_type = num_context_type;
      get_response.emplace<GetContextTypesResponse>(get_context_type_response);
      break;
    }
    default:
      LOG(FATAL) << "Wrong specification for FillTypes!";
  }

  num_total_type = num_artifact_type + num_execution_type + num_context_type;
  return tensorflow::Status::OK();
}

// Inserts new types into the db if the current types inside db is not enough
// for update. Returns detailed error if query executions failed.
tensorflow::Status MakeUpTypesForUpdate(
    const FillTypesConfig& fill_types_config, MetadataStore* store,
    int64 num_type_to_make_up) {
  FillTypesConfig make_up_config = fill_types_config;
  make_up_config.set_update(false);
  std::unique_ptr<FillTypes> make_up_fill_types;
  make_up_fill_types = absl::make_unique<FillTypes>(
      FillTypes(make_up_config, num_type_to_make_up));
  TF_RETURN_IF_ERROR(make_up_fill_types->SetUp(store));
  for (int64 i = 0; i < num_type_to_make_up; ++i) {
    OpStats op_stats;
    TF_RETURN_IF_ERROR(make_up_fill_types->RunOp(i, store, op_stats));
  }
  return tensorflow::Status::OK();
}

// A template function where the Type can be ArtifactType / ExecutionType /
// ContextType.
// Takes an existed type and generates a new type for later update accordingly.
// The updated type will have some new fields added and the number of new added
// fields will be generated w.r.t. the uniform distribution.
template <typename Type>
void UpdateType(std::uniform_int_distribution<int64>& uniform_dist,
                std::minstd_rand0& gen, const Type& existed_type,
                Type* updated_type, int64* curr_bytes) {
  // Except the new added fields, update_type will the same as existed_type.
  *updated_type = existed_type;
  *curr_bytes += existed_type.name().size();
  for (auto& pair : existed_type.properties()) {
    // pair.first is the property of existed_type.
    *curr_bytes += pair.first.size();
  }
  const int64 num_properties = uniform_dist(gen);
  for (int64 i = 0; i < num_properties; i++) {
    (*updated_type->mutable_properties())[absl::StrCat("add_p-", i)] = STRING;
    *curr_bytes += absl::StrCat("add_p-", i).size();
  }
}

}  // namespace

FillTypes::FillTypes(const FillTypesConfig& fill_types_config,
                     int64 num_operations)
    : fill_types_config_(fill_types_config), num_operations_(num_operations) {
  switch (fill_types_config_.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      name_ = "fill_artifact_type";
      break;
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      name_ = "fill_execution_type";
      break;
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      name_ = "fill_context_type";
      break;
    }
    default:
      LOG(FATAL) << "Wrong specification for FillTypes!";
  }
  if (fill_types_config_.update()) {
    name_ += "(update)";
  }
}

tensorflow::Status FillTypes::SetUpImpl(MetadataStore* store) {
  LOG(INFO) << "Setting up ...";

  int64 curr_bytes = 0;
  // Uniform distribution that describes the number of properties for each
  // generated types.
  UniformDistribution num_properties = fill_types_config_.num_properties();
  int64 min = num_properties.minimum();
  int64 max = num_properties.maximum();
  std::uniform_int_distribution<int64> uniform_dist{min, max};
  // The seed for the random generator is the time when the FillTypes is
  // created.
  std::minstd_rand0 gen(absl::ToUnixMillis(absl::Now()));

  // Gets the number of current types(num_curr_type) and total
  // types(num_total_type) for later insert or update.
  int64 num_curr_type = 0, num_total_type = 0;
  GetTypeResponseType get_response;
  TF_RETURN_IF_ERROR(GetNumberOfTypes(fill_types_config_, store, num_curr_type,
                                      num_total_type, get_response));

  // If the number of current types is less than the update number of
  // operations, calls MakeUpTypesForUpdate() for inserting new types into the
  // db for later update.
  if (fill_types_config_.update() && num_curr_type < num_operations_) {
    int64 num_type_to_make_up = num_operations_ - num_curr_type;
    TF_RETURN_IF_ERROR(
        MakeUpTypesForUpdate(fill_types_config_, store, num_type_to_make_up));
    // Updates the get_response to contain the up-to-date types inside db for
    // later update.
    TF_RETURN_IF_ERROR(GetNumberOfTypes(fill_types_config_, store,
                                        num_curr_type, num_total_type,
                                        get_response));
  }

  for (int64 i = num_total_type; i < num_total_type + num_operations_; i++) {
    curr_bytes = 0;
    int64 update_type_index = i - num_total_type;
    FillTypeWorkItemType put_request;
    const std::string type_name = absl::StrCat("type_", i);
    switch (fill_types_config_.specification()) {
      case FillTypesConfig::ARTIFACT_TYPE: {
        put_request.emplace<PutArtifactTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutArtifactTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ArtifactType>(
              uniform_dist, gen,
              absl::get<GetArtifactTypesResponse>(get_response)
                  .artifact_types()[update_type_index],
              absl::get<PutArtifactTypeRequest>(put_request)
                  .mutable_artifact_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ArtifactType>(
              type_name, uniform_dist, gen,
              absl::get<PutArtifactTypeRequest>(put_request)
                  .mutable_artifact_type(),
              &curr_bytes);
        }
        break;
      }
      case FillTypesConfig::EXECUTION_TYPE: {
        put_request.emplace<PutExecutionTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutExecutionTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ExecutionType>(
              uniform_dist, gen,
              absl::get<GetExecutionTypesResponse>(get_response)
                  .execution_types()[update_type_index],
              absl::get<PutExecutionTypeRequest>(put_request)
                  .mutable_execution_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ExecutionType>(
              type_name, uniform_dist, gen,
              absl::get<PutExecutionTypeRequest>(put_request)
                  .mutable_execution_type(),
              &curr_bytes);
        }
        break;
      }
      case FillTypesConfig::CONTEXT_TYPE: {
        put_request.emplace<PutContextTypeRequest>();
        if (fill_types_config_.update()) {
          // For update purpose, the can_add_fields field should be set to true.
          absl::get<PutContextTypeRequest>(put_request)
              .set_can_add_fields(true);
          UpdateType<ContextType>(
              uniform_dist, gen,
              absl::get<GetContextTypesResponse>(get_response)
                  .context_types()[update_type_index],
              absl::get<PutContextTypeRequest>(put_request)
                  .mutable_context_type(),
              &curr_bytes);
        } else {
          GenerateRandomType<ContextType>(
              type_name, uniform_dist, gen,
              absl::get<PutContextTypeRequest>(put_request)
                  .mutable_context_type(),
              &curr_bytes);
        }
        break;
      }
      default:
        return tensorflow::errors::InvalidArgument("Wrong specification!");
    }
    // Updates work_items_.
    work_items_.emplace_back(put_request, curr_bytes);
  }
  return tensorflow::Status::OK();
}

// Executions of work items.
tensorflow::Status FillTypes::RunOpImpl(int64 i, MetadataStore* store) {
  switch (fill_types_config_.specification()) {
    case FillTypesConfig::ARTIFACT_TYPE: {
      PutArtifactTypeRequest put_request =
          absl::get<PutArtifactTypeRequest>(work_items_[i].first);
      PutArtifactTypeResponse put_response;
      return store->PutArtifactType(put_request, &put_response);
    }
    case FillTypesConfig::EXECUTION_TYPE: {
      PutExecutionTypeRequest put_request =
          absl::get<PutExecutionTypeRequest>(work_items_[i].first);
      PutExecutionTypeResponse put_response;
      return store->PutExecutionType(put_request, &put_response);
    }
    case FillTypesConfig::CONTEXT_TYPE: {
      PutContextTypeRequest put_request =
          absl::get<PutContextTypeRequest>(work_items_[i].first);
      PutContextTypeResponse put_response;
      return store->PutContextType(put_request, &put_response);
    }
    default:
      return tensorflow::errors::InvalidArgument("Wrong specification!");
  }
  return tensorflow::errors::InvalidArgument(
      "Cannot execute the query due to wrong specification!");
}

tensorflow::Status FillTypes::TearDownImpl() {
  work_items_.clear();
  return tensorflow::Status::OK();
}

std::string FillTypes::GetName() { return name_; }

}  // namespace ml_metadata
<|endoftext|>


<commit_before>//===-- tsan_interface_ann.cc -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_interface_ann.h"
#include "tsan_mutex.h"
#include "tsan_placement_new.h"
#include "tsan_report.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_flags.h"

#define CALLERPC ((uptr)__builtin_return_address(0))

using namespace __tsan;  // NOLINT

namespace __tsan {

class ScopedAnnotation {
 public:
  ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
                   uptr pc)
      : thr_(thr)
      , in_rtl_(thr->in_rtl) {
    CHECK_EQ(thr_->in_rtl, 0);
    FuncEntry(thr_, pc);
    thr_->in_rtl++;
    DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
  }

  ~ScopedAnnotation() {
    thr_->in_rtl--;
    CHECK_EQ(in_rtl_, thr_->in_rtl);
    FuncExit(thr_);
  }
 private:
  ThreadState *const thr_;
  const int in_rtl_;
};

#define SCOPED_ANNOTATION(typ) \
    if (!flags()->enable_annotations) \
      return; \
    ThreadState *thr = cur_thread(); \
    StatInc(thr, StatAnnotation); \
    StatInc(thr, Stat##typ); \
    ScopedAnnotation sa(thr, __FUNCTION__, f, l, \
        (uptr)__builtin_return_address(0)); \
    const uptr pc = (uptr)&__FUNCTION__; \
    (void)pc; \
/**/

static const int kMaxDescLen = 128;

struct ExpectRace {
  ExpectRace *next;
  ExpectRace *prev;
  int hitcount;
  uptr addr;
  uptr size;
  char *file;
  int line;
  char desc[kMaxDescLen];
};

struct DynamicAnnContext {
  Mutex mtx;
  ExpectRace expect;
  ExpectRace benign;

  DynamicAnnContext()
    : mtx(MutexTypeAnnotations, StatMtxAnnotations) {
  }
};

static DynamicAnnContext *dyn_ann_ctx;
static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGN(64);

static void AddExpectRace(ExpectRace *list,
    char *f, int l, uptr addr, uptr size, char *desc) {
  ExpectRace *race = list->next;
  for (; race != list; race = race->next) {
    if (race->addr == addr && race->size == size)
      return;
  }
  race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
  race->hitcount = 0;
  race->addr = addr;
  race->size = size;
  race->file = f;
  race->line = l;
  race->desc[0] = 0;
  if (desc) {
    int i = 0;
    for (; i < kMaxDescLen - 1 && desc[i]; i++)
      race->desc[i] = desc[i];
    race->desc[i] = 0;
  }
  race->prev = list;
  race->next = list->next;
  race->next->prev = race;
  list->next = race;
}

static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
  for (ExpectRace *race = list->next; race != list; race = race->next) {
    uptr maxbegin = max(race->addr, addr);
    uptr minend = min(race->addr + race->size, addr + size);
    if (maxbegin < minend)
      return race;
  }
  return 0;
}

static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
  ExpectRace *race = FindRace(list, addr, size);
  if (race == 0)
    return false;
  DPrintf("Hit expected/benign race: %s addr=%lx:%d %s:%d\n",
      race->desc, race->addr, (int)race->size, race->file, race->line);
  race->hitcount++;
  return true;
}

static void InitList(ExpectRace *list) {
  list->next = list;
  list->prev = list;
}

void InitializeDynamicAnnotations() {
  dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;
  InitList(&dyn_ann_ctx->expect);
  InitList(&dyn_ann_ctx->benign);
}

bool IsExpectedReport(uptr addr, uptr size) {
  Lock lock(&dyn_ann_ctx->mtx);
  if (CheckContains(&dyn_ann_ctx->expect, addr, size))
    return true;
  if (CheckContains(&dyn_ann_ctx->benign, addr, size))
    return true;
  return false;
}

}  // namespace __tsan

using namespace __tsan;  // NOLINT

extern "C" {
void AnnotateHappensBefore(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensBefore);
  Release(cur_thread(), CALLERPC, addr);
}

void AnnotateHappensAfter(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensAfter);
  Acquire(cur_thread(), CALLERPC, addr);
}

void AnnotateCondVarSignal(char *f, int l, uptr cv) {
  SCOPED_ANNOTATION(AnnotateCondVarSignal);
}

void AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
  SCOPED_ANNOTATION(AnnotateCondVarSignalAll);
}

void AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
  SCOPED_ANNOTATION(AnnotateMutexIsNotPHB);
}

void AnnotateCondVarWait(char *f, int l, uptr cv, uptr lock) {
  SCOPED_ANNOTATION(AnnotateCondVarWait);
}

void AnnotateRWLockCreate(char *f, int l, uptr lock) {
  SCOPED_ANNOTATION(AnnotateRWLockCreate);
}

void AnnotateRWLockDestroy(char *f, int l, uptr lock) {
  SCOPED_ANNOTATION(AnnotateRWLockDestroy);
}

void AnnotateRWLockAcquired(char *f, int l, uptr lock, uptr is_w) {
  SCOPED_ANNOTATION(AnnotateRWLockAcquired);
}

void AnnotateRWLockReleased(char *f, int l, uptr lock, uptr is_w) {
  SCOPED_ANNOTATION(AnnotateRWLockReleased);
}

void AnnotateTraceMemory(char *f, int l, uptr mem) {
  SCOPED_ANNOTATION(AnnotateTraceMemory);
}

void AnnotateFlushState(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateFlushState);
}

void AnnotateNewMemory(char *f, int l, uptr mem, uptr size) {
  SCOPED_ANNOTATION(AnnotateNewMemory);
}

void AnnotateNoOp(char *f, int l, uptr mem) {
  SCOPED_ANNOTATION(AnnotateNoOp);
}

static void ReportMissedExpectedRace(ExpectRace *race) {
  Printf("==================\n");
  Printf("WARNING: ThreadSanitizer: missed expected data race\n");
  Printf("  %s addr=%lx %s:%d\n",
      race->desc, race->addr, race->file, race->line);
  Printf("==================\n");
}

void AnnotateFlushExpectedRaces(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
  Lock lock(&dyn_ann_ctx->mtx);
  while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
    ExpectRace *race = dyn_ann_ctx->expect.next;
    if (race->hitcount == 0) {
      CTX()->nmissed_expected++;
      ReportMissedExpectedRace(race);
    }
    race->prev->next = race->next;
    race->next->prev = race->prev;
    internal_free(race);
  }
}

void AnnotateEnableRaceDetection(char *f, int l, int enable) {
  SCOPED_ANNOTATION(AnnotateEnableRaceDetection);
  // FIXME: Reconsider this functionality later. It may be irrelevant.
}

void AnnotateMutexIsUsedAsCondVar(char *f, int l, uptr mu) {
  SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar);
}

void AnnotatePCQGet(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQGet);
}

void AnnotatePCQPut(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQPut);
}

void AnnotatePCQDestroy(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQDestroy);
}

void AnnotatePCQCreate(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQCreate);
}

void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) {
  SCOPED_ANNOTATION(AnnotateExpectRace);
  Lock lock(&dyn_ann_ctx->mtx);
  AddExpectRace(&dyn_ann_ctx->expect,
                f, l, mem, 1, desc);
  DPrintf("Add expected race: %s addr=%lx %s:%d\n", desc, mem, f, l);
}

static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
  Lock lock(&dyn_ann_ctx->mtx);
  AddExpectRace(&dyn_ann_ctx->benign,
                f, l, mem, size, desc);
  DPrintf("Add benign race: %s addr=%lx %s:%d\n", desc, mem, f, l);
}

// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
void AnnotateBenignRaceSized(char *f, int l, uptr mem, uptr size, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
  BenignRaceImpl(f, l, mem, size, desc);
}

void AnnotateBenignRace(char *f, int l, uptr mem, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRace);
  BenignRaceImpl(f, l, mem, 1, desc);
}

void AnnotateIgnoreReadsBegin(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
  IgnoreCtl(cur_thread(), false, true);
}

void AnnotateIgnoreReadsEnd(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
  IgnoreCtl(cur_thread(), false, false);
}

void AnnotateIgnoreWritesBegin(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
  IgnoreCtl(cur_thread(), true, true);
}

void AnnotateIgnoreWritesEnd(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
  IgnoreCtl(cur_thread(), true, false);
}

void AnnotatePublishMemoryRange(char *f, int l, uptr addr, uptr size) {
  SCOPED_ANNOTATION(AnnotatePublishMemoryRange);
}

void AnnotateUnpublishMemoryRange(char *f, int l, uptr addr, uptr size) {
  SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange);
}

void AnnotateThreadName(char *f, int l, char *name) {
  SCOPED_ANNOTATION(AnnotateThreadName);
}

void WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensBefore);
}

void WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensAfter);
}

void WTFAnnotateBenignRaceSized(char *f, int l, uptr mem, uptr sz, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
}

int RunningOnValgrind() {
  return 0;
}

double ValgrindSlowdown(void) {
  return 10.0;
}

const char *ThreadSanitizerQuery(const char *query) {
  if (internal_strcmp(query, "pure_happens_before") == 0)
    return "1";
  else
    return "0";
}
}  // extern "C"
<commit_msg>tsan: ValgrindSlowdown() should be weak for some time<commit_after>//===-- tsan_interface_ann.cc -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_interface_ann.h"
#include "tsan_mutex.h"
#include "tsan_placement_new.h"
#include "tsan_report.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_flags.h"

#define CALLERPC ((uptr)__builtin_return_address(0))

using namespace __tsan;  // NOLINT

namespace __tsan {

class ScopedAnnotation {
 public:
  ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
                   uptr pc)
      : thr_(thr)
      , in_rtl_(thr->in_rtl) {
    CHECK_EQ(thr_->in_rtl, 0);
    FuncEntry(thr_, pc);
    thr_->in_rtl++;
    DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
  }

  ~ScopedAnnotation() {
    thr_->in_rtl--;
    CHECK_EQ(in_rtl_, thr_->in_rtl);
    FuncExit(thr_);
  }
 private:
  ThreadState *const thr_;
  const int in_rtl_;
};

#define SCOPED_ANNOTATION(typ) \
    if (!flags()->enable_annotations) \
      return; \
    ThreadState *thr = cur_thread(); \
    StatInc(thr, StatAnnotation); \
    StatInc(thr, Stat##typ); \
    ScopedAnnotation sa(thr, __FUNCTION__, f, l, \
        (uptr)__builtin_return_address(0)); \
    const uptr pc = (uptr)&__FUNCTION__; \
    (void)pc; \
/**/

static const int kMaxDescLen = 128;

struct ExpectRace {
  ExpectRace *next;
  ExpectRace *prev;
  int hitcount;
  uptr addr;
  uptr size;
  char *file;
  int line;
  char desc[kMaxDescLen];
};

struct DynamicAnnContext {
  Mutex mtx;
  ExpectRace expect;
  ExpectRace benign;

  DynamicAnnContext()
    : mtx(MutexTypeAnnotations, StatMtxAnnotations) {
  }
};

static DynamicAnnContext *dyn_ann_ctx;
static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGN(64);

static void AddExpectRace(ExpectRace *list,
    char *f, int l, uptr addr, uptr size, char *desc) {
  ExpectRace *race = list->next;
  for (; race != list; race = race->next) {
    if (race->addr == addr && race->size == size)
      return;
  }
  race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
  race->hitcount = 0;
  race->addr = addr;
  race->size = size;
  race->file = f;
  race->line = l;
  race->desc[0] = 0;
  if (desc) {
    int i = 0;
    for (; i < kMaxDescLen - 1 && desc[i]; i++)
      race->desc[i] = desc[i];
    race->desc[i] = 0;
  }
  race->prev = list;
  race->next = list->next;
  race->next->prev = race;
  list->next = race;
}

static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
  for (ExpectRace *race = list->next; race != list; race = race->next) {
    uptr maxbegin = max(race->addr, addr);
    uptr minend = min(race->addr + race->size, addr + size);
    if (maxbegin < minend)
      return race;
  }
  return 0;
}

static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
  ExpectRace *race = FindRace(list, addr, size);
  if (race == 0)
    return false;
  DPrintf("Hit expected/benign race: %s addr=%lx:%d %s:%d\n",
      race->desc, race->addr, (int)race->size, race->file, race->line);
  race->hitcount++;
  return true;
}

static void InitList(ExpectRace *list) {
  list->next = list;
  list->prev = list;
}

void InitializeDynamicAnnotations() {
  dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;
  InitList(&dyn_ann_ctx->expect);
  InitList(&dyn_ann_ctx->benign);
}

bool IsExpectedReport(uptr addr, uptr size) {
  Lock lock(&dyn_ann_ctx->mtx);
  if (CheckContains(&dyn_ann_ctx->expect, addr, size))
    return true;
  if (CheckContains(&dyn_ann_ctx->benign, addr, size))
    return true;
  return false;
}

}  // namespace __tsan

using namespace __tsan;  // NOLINT

extern "C" {
void AnnotateHappensBefore(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensBefore);
  Release(cur_thread(), CALLERPC, addr);
}

void AnnotateHappensAfter(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensAfter);
  Acquire(cur_thread(), CALLERPC, addr);
}

void AnnotateCondVarSignal(char *f, int l, uptr cv) {
  SCOPED_ANNOTATION(AnnotateCondVarSignal);
}

void AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
  SCOPED_ANNOTATION(AnnotateCondVarSignalAll);
}

void AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
  SCOPED_ANNOTATION(AnnotateMutexIsNotPHB);
}

void AnnotateCondVarWait(char *f, int l, uptr cv, uptr lock) {
  SCOPED_ANNOTATION(AnnotateCondVarWait);
}

void AnnotateRWLockCreate(char *f, int l, uptr lock) {
  SCOPED_ANNOTATION(AnnotateRWLockCreate);
}

void AnnotateRWLockDestroy(char *f, int l, uptr lock) {
  SCOPED_ANNOTATION(AnnotateRWLockDestroy);
}

void AnnotateRWLockAcquired(char *f, int l, uptr lock, uptr is_w) {
  SCOPED_ANNOTATION(AnnotateRWLockAcquired);
}

void AnnotateRWLockReleased(char *f, int l, uptr lock, uptr is_w) {
  SCOPED_ANNOTATION(AnnotateRWLockReleased);
}

void AnnotateTraceMemory(char *f, int l, uptr mem) {
  SCOPED_ANNOTATION(AnnotateTraceMemory);
}

void AnnotateFlushState(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateFlushState);
}

void AnnotateNewMemory(char *f, int l, uptr mem, uptr size) {
  SCOPED_ANNOTATION(AnnotateNewMemory);
}

void AnnotateNoOp(char *f, int l, uptr mem) {
  SCOPED_ANNOTATION(AnnotateNoOp);
}

static void ReportMissedExpectedRace(ExpectRace *race) {
  Printf("==================\n");
  Printf("WARNING: ThreadSanitizer: missed expected data race\n");
  Printf("  %s addr=%lx %s:%d\n",
      race->desc, race->addr, race->file, race->line);
  Printf("==================\n");
}

void AnnotateFlushExpectedRaces(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
  Lock lock(&dyn_ann_ctx->mtx);
  while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
    ExpectRace *race = dyn_ann_ctx->expect.next;
    if (race->hitcount == 0) {
      CTX()->nmissed_expected++;
      ReportMissedExpectedRace(race);
    }
    race->prev->next = race->next;
    race->next->prev = race->prev;
    internal_free(race);
  }
}

void AnnotateEnableRaceDetection(char *f, int l, int enable) {
  SCOPED_ANNOTATION(AnnotateEnableRaceDetection);
  // FIXME: Reconsider this functionality later. It may be irrelevant.
}

void AnnotateMutexIsUsedAsCondVar(char *f, int l, uptr mu) {
  SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar);
}

void AnnotatePCQGet(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQGet);
}

void AnnotatePCQPut(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQPut);
}

void AnnotatePCQDestroy(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQDestroy);
}

void AnnotatePCQCreate(char *f, int l, uptr pcq) {
  SCOPED_ANNOTATION(AnnotatePCQCreate);
}

void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) {
  SCOPED_ANNOTATION(AnnotateExpectRace);
  Lock lock(&dyn_ann_ctx->mtx);
  AddExpectRace(&dyn_ann_ctx->expect,
                f, l, mem, 1, desc);
  DPrintf("Add expected race: %s addr=%lx %s:%d\n", desc, mem, f, l);
}

static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
  Lock lock(&dyn_ann_ctx->mtx);
  AddExpectRace(&dyn_ann_ctx->benign,
                f, l, mem, size, desc);
  DPrintf("Add benign race: %s addr=%lx %s:%d\n", desc, mem, f, l);
}

// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
void AnnotateBenignRaceSized(char *f, int l, uptr mem, uptr size, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
  BenignRaceImpl(f, l, mem, size, desc);
}

void AnnotateBenignRace(char *f, int l, uptr mem, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRace);
  BenignRaceImpl(f, l, mem, 1, desc);
}

void AnnotateIgnoreReadsBegin(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
  IgnoreCtl(cur_thread(), false, true);
}

void AnnotateIgnoreReadsEnd(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
  IgnoreCtl(cur_thread(), false, false);
}

void AnnotateIgnoreWritesBegin(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
  IgnoreCtl(cur_thread(), true, true);
}

void AnnotateIgnoreWritesEnd(char *f, int l) {
  SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
  IgnoreCtl(cur_thread(), true, false);
}

void AnnotatePublishMemoryRange(char *f, int l, uptr addr, uptr size) {
  SCOPED_ANNOTATION(AnnotatePublishMemoryRange);
}

void AnnotateUnpublishMemoryRange(char *f, int l, uptr addr, uptr size) {
  SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange);
}

void AnnotateThreadName(char *f, int l, char *name) {
  SCOPED_ANNOTATION(AnnotateThreadName);
}

void WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensBefore);
}

void WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
  SCOPED_ANNOTATION(AnnotateHappensAfter);
}

void WTFAnnotateBenignRaceSized(char *f, int l, uptr mem, uptr sz, char *desc) {
  SCOPED_ANNOTATION(AnnotateBenignRaceSized);
}

int RunningOnValgrind() {
  return 0;
}

double __attribute__((weak)) ValgrindSlowdown(void) {
  return 10.0;
}

const char *ThreadSanitizerQuery(const char *query) {
  if (internal_strcmp(query, "pure_happens_before") == 0)
    return "1";
  else
    return "0";
}
}  // extern "C"
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/

#include "test.hh"

namespace pegtl
{
   namespace
   {
      std::string u32s( const char32_t u )
      {
         return std::string( reinterpret_cast< const char * >( & u ), sizeof( u ) );
      }

   } //

   void unit_test()
   {
      verify_rule< utf32::any >( __LINE__, __FILE__, "", result_type::LOCAL_FAILURE, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff", result_type::LOCAL_FAILURE, 1 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff\xff", result_type::LOCAL_FAILURE, 2 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff\xff\xff", result_type::LOCAL_FAILURE, 3 );

      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 1 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x00ff ) + " ", result_type::SUCCESS, 1 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x0100 ) + "  ", result_type::SUCCESS, 2 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x0fff ) + "   ", result_type::SUCCESS, 3 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x1000 ) + "    ", result_type::SUCCESS, 4 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0xfffe ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0xffff ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x100000 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x10fffe ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x10ffff ), result_type::SUCCESS, 0 );

      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x110000 ), result_type::LOCAL_FAILURE, 4 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x110000 ) + u32s( 0 ), result_type::LOCAL_FAILURE, 8 );

      verify_rule< utf32::one< 0x20 > >( __LINE__, __FILE__, u32s( 0x20 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::one< 0x10fedc > >( __LINE__, __FILE__, u32s( 0x10fedc ), result_type::SUCCESS, 0 );
   }

} // pegtl

#include "main.hh"
<commit_msg>More tests<commit_after>// Copyright (c) 2014-2015 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/

#include "test.hh"

namespace pegtl
{
   namespace
   {
      std::string u32s( const char32_t u )
      {
         return std::string( reinterpret_cast< const char * >( & u ), sizeof( u ) );
      }

   } //

   void unit_test()
   {
      verify_rule< utf32::any >( __LINE__, __FILE__, "", result_type::LOCAL_FAILURE, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff", result_type::LOCAL_FAILURE, 1 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff\xff", result_type::LOCAL_FAILURE, 2 );
      verify_rule< utf32::any >( __LINE__, __FILE__, "\xff\xff\xff", result_type::LOCAL_FAILURE, 3 );

      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 1 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x00ff ) + " ", result_type::SUCCESS, 1 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x0100 ) + "  ", result_type::SUCCESS, 2 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x0fff ) + "   ", result_type::SUCCESS, 3 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x1000 ) + "    ", result_type::SUCCESS, 4 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0xfffe ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0xffff ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x100000 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x10fffe ), result_type::SUCCESS, 0 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x10ffff ), result_type::SUCCESS, 0 );

      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x110000 ), result_type::LOCAL_FAILURE, 4 );
      verify_rule< utf32::any >( __LINE__, __FILE__, u32s( 0x110000 ) + u32s( 0 ), result_type::LOCAL_FAILURE, 8 );

      verify_rule< utf32::one< 0x20 > >( __LINE__, __FILE__, u32s( 0x20 ), result_type::SUCCESS, 0 );
      verify_rule< utf32::one< 0x20ac > >( __LINE__, __FILE__, u32s( 0x20ac ), result_type::SUCCESS, 0 );
      verify_rule< utf32::one< 0x10fedc > >( __LINE__, __FILE__, u32s( 0x10fedc ), result_type::SUCCESS, 0 );
   }

} // pegtl

#include "main.hh"
<|endoftext|>