Beispiel #1
0
    def archive_set_numbers(archive, location_count, global_defs_count):
        assert (location_count * 2 <= global_defs_count)
        glob_def_writer = _otf2.Archive_GetGlobalDefWriter(archive)
        for loc in range(location_count):
            name = "Location #{}".format(loc)
            _otf2.GlobalDefWriter_WriteString(glob_def_writer, loc, name)
            _otf2.GlobalDefWriter_WriteLocation(glob_def_writer, loc, loc,
                                                _otf2.LOCATION_TYPE_CPU_THREAD,
                                                0, loc)
        # now we have writen location_count locations and
        # 2 * location_count definitions
        for fake_string in range(location_count,
                                 global_defs_count - location_count):
            _otf2.GlobalDefWriter_WriteString(glob_def_writer, fake_string,
                                              "fake{}".format(fake_string))

        _otf2.Archive_CloseGlobalDefWriter(archive, glob_def_writer)
def write_global_definitions(archive):
    global_def_writer = _otf2.Archive_GetGlobalDefWriter(archive)

    _otf2.GlobalDefWriter_WriteClockProperties(global_def_writer, 1, 0, 2)

    # GlobalDefWriter, StringRef, const char*
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 0, "")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 1, "Master Process")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 2, "Main Thread")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 3, "My Function")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 4, "other function")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 5,
                                      "compute something")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 6, "myHost")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 7, "node")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 8, "Temperature")
    _otf2.GlobalDefWriter_WriteString(global_def_writer, 9, "C")

    # GlobalDefWriter, RegionRef, StringRef, StringRef, StringRef, RegionRole,
    # Paradigm, RegionFlag, StringRef, uint32_t, uint32_t
    _otf2.GlobalDefWriter_WriteRegion(global_def_writer, 0, 3, 4, 5,
                                      _otf2.REGION_ROLE_FUNCTION,
                                      _otf2.PARADIGM_USER,
                                      _otf2.REGION_FLAG_NONE, 0, 0, 0)
    # GlobalDefWriter, SystemTreeNodeRef, StringRef, StringRef, SystemTreeNodeRef
    _otf2.GlobalDefWriter_WriteSystemTreeNode(global_def_writer, 0, 6, 7,
                                              _otf2.UNDEFINED_SYSTEM_TREE_NODE)
    # GlobalDefWriter, LocationGroupRef, StringRef, LocationGroupType, SystemTreeNodeRef
    _otf2.GlobalDefWriter_WriteLocationGroup(global_def_writer, 0, 1,
                                             _otf2.LOCATION_GROUP_TYPE_PROCESS,
                                             0)
    # GlobalDefWriter, LocationRef, StringRef, LocationType, uint64_t, LocationGroupRef
    _otf2.GlobalDefWriter_WriteLocation(global_def_writer, 0, 2,
                                        _otf2.LOCATION_TYPE_CPU_THREAD, 2, 0)

    write_paradigm(global_def_writer)
    def write_trace(self):
        archive_path = "%s/%s" % (self.tmp_dirname, self.archive_name)
        archive = _otf2.Archive_Open(archive_path, "trace_files",
                                     _otf2.FILEMODE_WRITE, 256 * 1024,
                                     _otf2.UNDEFINED_UINT64,
                                     _otf2.SUBSTRATE_POSIX,
                                     _otf2.COMPRESSION_NONE)

        flush_callbacks = _otf2.FlushCallbacks(pre_flush=pre_flush,
                                               post_flush=post_flush)
        _otf2.Archive_SetFlushCallbacks(archive,
                                        flushCallbacks=flush_callbacks,
                                        flushData=None)

        _otf2.Archive_SetSerialCollectiveCallbacks(archive)

        _otf2.Archive_SetDescription(
            archive, description="OTF2 trace for integrity test.")
        _otf2.Archive_SetCreator(archive, creator="OTF2_Integrity")

        _otf2.Archive_SetDefChunkSize(archive, 4 * 1024 * 1024)

        global_def_writer = _otf2.Archive_GetGlobalDefWriter(archive)

        _otf2.GlobalDefWriter_WriteString(global_def_writer, 0, "Process")

        for location in self.locations:
            _otf2.GlobalDefWriter_WriteLocation(global_def_writer, location, 0,
                                                _otf2.LOCATION_TYPE_CPU_THREAD,
                                                self.num_events * 6, 0)

        _otf2.GlobalDefWriter_WriteString(global_def_writer, 1, "MPI_Send")
        _otf2.GlobalDefWriter_WriteString(global_def_writer, 2,
                                          "Send an MPI message")

        _otf2.GlobalDefWriter_WriteString(global_def_writer, 3, "MPI_Recv")
        _otf2.GlobalDefWriter_WriteString(global_def_writer, 4,
                                          "Receive an MPI message")

        _otf2.GlobalDefWriter_WriteRegion(global_def_writer, 0, 1, 1, 2,
                                          _otf2.REGION_ROLE_UNKNOWN,
                                          _otf2.PARADIGM_UNKNOWN,
                                          _otf2.REGION_FLAG_NONE, 0, 0, 0)
        _otf2.GlobalDefWriter_WriteRegion(global_def_writer, 1, 3, 3, 4,
                                          _otf2.REGION_ROLE_UNKNOWN,
                                          _otf2.PARADIGM_UNKNOWN,
                                          _otf2.REGION_FLAG_NONE, 0, 0, 0)

        _otf2.Archive_CloseGlobalDefWriter(archive, global_def_writer)

        _otf2.Archive_OpenDefFiles(archive)

        for location in self.locations:
            def_writer = _otf2.Archive_GetDefWriter(archive, location)
            _otf2.Archive_CloseDefWriter(archive, def_writer)

        _otf2.Archive_CloseDefFiles(archive)

        _otf2.Archive_OpenEvtFiles(archive)

        for _ in range(self.num_events):
            for location in self.locations:
                evt_writer = _otf2.Archive_GetEvtWriter(archive, location)

                ts = get_time()

                _otf2.EvtWriter_Enter(evt_writer, None, ts, 0)
                _otf2.EvtWriter_MpiSend(evt_writer, None, ts, location, 0, 42,
                                        1024)
                _otf2.EvtWriter_Leave(evt_writer, None, get_time(), 0)

                _otf2.EvtWriter_Enter(evt_writer, None, get_time(), 1)
                ts = get_time()
                _otf2.EvtWriter_MpiRecv(evt_writer, None, ts, location, 0, 42,
                                        1024)
                _otf2.EvtWriter_Leave(evt_writer, None, ts, 1)

        for location in self.locations:
            evt_writer = _otf2.Archive_GetEvtWriter(archive, location)
            _otf2.Archive_CloseEvtWriter(archive, evt_writer)

        _otf2.Archive_CloseEvtFiles(archive)

        _otf2.Archive_Close(archive)
Beispiel #4
0
def main():
    archive_name = "TestTrace"

    # Array used to store metric values */
    metric_values = (_otf2.MetricValue * NUM_OF_METRICS)()

    # If you add new metrics please adapt also the array of metric types
    # and the routine to generate random metric values. */

    # Array of metric types */
    metric_types = [
        _otf2.TYPE_UINT64, _otf2.TYPE_DOUBLE, _otf2.TYPE_INT64,
        _otf2.TYPE_DOUBLE, _otf2.TYPE_INT64
    ]

    # Initialize accumulated metric */
    metric_values[0].unsigned_int = 0
    metric_values[1].floating_point = 12.5
    metric_values[2].signed_int = 1
    metric_values[3].floating_point = 10.0
    metric_values[4].unsigned_int = 1

    # Distribute metric members to its classes */
    metric_members_of_class_1 = [METRIC_A, METRIC_B]
    metric_members_of_class_2 = [METRIC_C]
    metric_members_of_class_3 = [METRIC_D]
    metric_members_of_class_4 = [METRIC_E]

    # Array of offsets needed to get correct type or values of a metric in corresponding arrays. */
    metric_classes_offsets = [0, 2, 3, 4, 4]

    # The collection of metric classes of instances for which we write metric events */
    class MetricWriteParameter:
        def __init__(self, id_, offset, count, record_for_location):
            self.id = id_
            self.metric_types = metric_types[offset:offset + count]
            self.metric_values = metric_values[offset:offset + count]
            self.record_for_location = record_for_location

    # FIXME missing class 4
    metric_write_parameters = [
        MetricWriteParameter(METRIC_CLASS_1, metric_classes_offsets[0],
                             len(metric_members_of_class_1),
                             record_for_all_locations),
        MetricWriteParameter(METRIC_CLASS_2, metric_classes_offsets[1],
                             len(metric_members_of_class_2),
                             record_for_all_locations),
        MetricWriteParameter(METRIC_CLASS_3, metric_classes_offsets[2],
                             len(metric_members_of_class_3),
                             record_for_all_locations),
        MetricWriteParameter(METRIC_INSTANCE_1, metric_classes_offsets[3],
                             len(metric_members_of_class_4),
                             record_for_location_0)
    ]

    def create_new_metric_values():
        metric_values[0].unsigned_int += 1
        metric_values[1].floating_point += 12.5
        metric_values[2].unsigned_int = -metric_values[2].unsigned_int
        metric_values[3].floating_point += 10.0
        metric_values[4].unsigned_int += 1

    def write_metrics(new, metric_time, metric_rank, metric_thread):
        if new:
            create_new_metric_values()

        for metric_write_parameter in metric_write_parameters:
            if metric_write_parameter.record_for_location(
                    metric_rank, metric_thread):
                _otf2.EvtWriter_Metric(evt_writer, None, metric_time,
                                       metric_write_parameter.id,
                                       metric_write_parameter.metric_types,
                                       metric_write_parameter.metric_values)

    # Calculate number of MPI ranks and OpenMP threads. */
    num_ranks = 1
    num_threads = 1

    if otf2_MPI:
        num_ranks = otf2_LOCATIONS
        archive_path = "otf2_trace_gen_trace_mpi_{}_{}{}".format(
            num_ranks, otf2_EVENTS, "_attr" if otf2_ATTRIBUTES else "")
    elif otf2_OPENMP:
        num_threads = otf2_LOCATIONS
        archive_path = "otf2_trace_gen_trace_omp_{}_{}{}".format(
            num_threads, otf2_EVENTS, "_attr" if otf2_ATTRIBUTES else "")
    elif otf2_HYBRID:
        if (otf2_LOCATIONS % 4) == 0:
            num_threads = 4
        elif (otf2_LOCATIONS % 3) == 0:
            num_threads = 3
        elif (otf2_LOCATIONS % 2) == 0:
            num_threads = 2
        else:
            # FIXME shadow
            for num_threads in range(5, otf2_LOCATIONS):
                if (otf2_LOCATIONS % num_threads) == 0:
                    break

        num_ranks = otf2_LOCATIONS // num_threads
        archive_path = "otf2_trace_gen_trace_mpi_omp_{}x{}_{}{}".format(
            num_ranks, num_threads, otf2_EVENTS,
            "_attr" if otf2_ATTRIBUTES else "")
    else:
        raise RuntimeError("No paradigm set")

    print("\nGenerating an OTF2 test archive")
    print("with {} rank(s) and {} thread(s) each ({} locations total)".format(
        num_ranks, num_threads, otf2_LOCATIONS))
    print("to {}/{}.otf2\n".format(archive_path, archive_name))

    if os.path.isdir(archive_path):
        for i in itertools.count():
            archive_path_backup = "{}_bk_{}".format(archive_path, i)
            if not os.path.exists(archive_path_backup):
                os.rename(archive_path, archive_path_backup)
                break

    # Create new archive handle. */
    archive = _otf2.Archive_Open(archive_path, archive_name,
                                 _otf2.FILEMODE_WRITE, 1024 * 1024,
                                 4 * 1024 * 1024, _otf2.SUBSTRATE_POSIX,
                                 _otf2.COMPRESSION_NONE)

    flush_callbacks = _otf2.FlushCallbacks(pre_flush=pre_flush,
                                           post_flush=post_flush)
    _otf2.Archive_SetFlushCallbacks(archive, flush_callbacks, None)

    # Set description, and creator. */
    _otf2.Archive_SetSerialCollectiveCallbacks(archive)
    _otf2.Archive_SetDescription(
        archive, "Simple OTF2 trace archive to valid reader components")
    _otf2.Archive_SetCreator(archive, "otf2_trace_gen")

    # Generate location IDs. Just to have non-consecutive location IDs. */
    locations = []
    mpi_ranks = []
    master_threads = []
    for rank in range(num_ranks):
        for thread in range(num_threads):
            locations.append((rank << 16) + thread)
        mpi_ranks.append(rank)
        master_threads.append(rank << 16)

    _otf2.Archive_OpenEvtFiles(archive)

    # Create local event writer. */
    # Create an attribute list. */
    attributes = None
    if otf2_ATTRIBUTES:
        attributes = _otf2.AttributeList_New()

    t = get_time()
    for rank in range(num_ranks):
        evt_writer = _otf2.Archive_GetEvtWriter(archive, master_threads[rank])

        # Enter main. */
        write_metrics(True, t, rank, 0)
        add_attributes(attributes)
        _otf2.EvtWriter_Enter(evt_writer, attributes, t, REGION_MAIN)

    for event in range(otf2_EVENTS):
        t = get_time()
        # FIXME - this makes no sense
        if not otf2_OPENMP:
            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])

                # Write enter MPI_Send. */
                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Enter(evt_writer, attributes, t,
                                      REGION_MPI_SEND)
                _otf2.EvtWriter_MpiSend(evt_writer, None, t,
                                        (rank + 1) % num_ranks, rank, 0, 1024)

                t = get_time()

                # Write leave MPI_Send. */
                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Leave(evt_writer, attributes, t,
                                      REGION_MPI_SEND)

                # Immediately enter the MPI_Recv */
                t = get_time()

                # Write enter MPI_Recv. */
                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Enter(evt_writer, attributes, t,
                                      REGION_MPI_RECV)

        if not otf2_OPENMP:
            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])

                _otf2.EvtWriter_MpiRecv(evt_writer, None, t,
                                        (rank + num_ranks - 1) % num_ranks,
                                        rank, 0, 1024)

                # Write enter MPI_Recv. */
                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Leave(evt_writer, attributes, t,
                                      REGION_MPI_RECV)

                # MPI Barrier. */
                t = get_time()

                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Enter(evt_writer, attributes, t,
                                      REGION_MPI_BARRIER)

                _otf2.EvtWriter_MpiCollectiveBegin(evt_writer, None, t)

        # End all started MPI_Barrier */
        t = get_time()
        if not otf2_OPENMP:
            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])
                _otf2.EvtWriter_MpiCollectiveEnd(evt_writer, None, t,
                                                 _otf2.COLLECTIVE_OP_BARRIER,
                                                 rank, _otf2.UNDEFINED_UINT32,
                                                 0, 0)

                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Leave(evt_writer, attributes, t,
                                      REGION_MPI_BARRIER)

        # If in OpenMP or Hybrid mode. */
        if not otf2_MPI:
            t_enter = get_time()
            t_leave = get_time()

            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])
                # At this point the master creates a team of several parallel threads */
                _otf2.EvtWriter_OmpFork(evt_writer, attributes, t_enter,
                                        num_threads)

            for rank in range(num_ranks):
                for thread in range(num_threads):
                    evt_writer = _otf2.Archive_GetEvtWriter(
                        archive, locations[num_threads * rank + thread])

                    # Enter OpenMP parallel  loop (outer region). */
                    write_metrics(True, t_enter, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Enter(evt_writer, attributes, t_enter,
                                          REGION_OPENMP_PARALLEL)

                    # Enter OpenMP parallel loop  (inner region). */
                    write_metrics(False, t_enter, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Enter(evt_writer, attributes, t_enter,
                                          REGION_OPENMP_LOOP)

                    # Enter OpenMP implicit barrier. */
                    write_metrics(False, t_enter, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Enter(evt_writer, attributes, t_enter,
                                          REGION_OPENMP_IMPLICIT_BARRIER)

            for rank in range(num_ranks):
                for thread in range(num_threads):
                    evt_writer = _otf2.Archive_GetEvtWriter(
                        archive, locations[num_threads * rank + thread])

                    # Leave OpenMP implicit barrier. */
                    write_metrics(True, t_leave, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Leave(evt_writer, attributes, t_leave,
                                          REGION_OPENMP_IMPLICIT_BARRIER)

                    # Leave OpenMP parallel loop (inner region). */
                    write_metrics(False, t_leave, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Leave(evt_writer, attributes, t_leave,
                                          REGION_OPENMP_LOOP)

                    # Leave OpenMP parallel loop (outer region). */
                    write_metrics(False, t_leave, rank, thread)
                    add_attributes(attributes)
                    _otf2.EvtWriter_Leave(evt_writer, attributes, t_leave,
                                          REGION_OPENMP_PARALLEL)

            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])
                # All threads have finished execution of statements in parallel region.
                # Now they synchronize and terminates. Only the master continues execution. */
                t_leave = get_time()
                _otf2.EvtWriter_OmpJoin(evt_writer, attributes, t_leave)

        if not otf2_OPENMP:
            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])

                t = get_time()

                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Enter(evt_writer, attributes, t,
                                      REGION_MPI_BARRIER)

                _otf2.EvtWriter_MpiCollectiveBegin(evt_writer, None, t)

        # End all started MPI_Barrier */
        t = get_time()
        if not otf2_OPENMP:
            for rank in range(num_ranks):
                evt_writer = _otf2.Archive_GetEvtWriter(
                    archive, master_threads[rank])

                _otf2.EvtWriter_MpiCollectiveEnd(evt_writer, None, t,
                                                 _otf2.COLLECTIVE_OP_BARRIER,
                                                 rank, _otf2.UNDEFINED_UINT32,
                                                 0, 0)

                write_metrics(True, t, rank, 0)
                add_attributes(attributes)
                _otf2.EvtWriter_Leave(evt_writer, attributes, t,
                                      REGION_MPI_BARRIER)

    t = get_time()
    for rank in range(num_ranks):
        evt_writer = _otf2.Archive_GetEvtWriter(archive, master_threads[rank])

        # Leave main. */
        write_metrics(True, t, rank, 0)
        add_attributes(attributes)
        _otf2.EvtWriter_Leave(evt_writer, attributes, t, REGION_MAIN)

    # last timestamp */
    t = get_time()
    number_of_events_per_location = []
    for rank in range(num_ranks):
        for thread in range(num_threads):
            evt_writer = _otf2.Archive_GetEvtWriter(
                archive, locations[num_threads * rank + thread])

            n = _otf2.EvtWriter_GetNumberOfEvents(evt_writer)
            number_of_events_per_location.append(n)

            _otf2.Archive_CloseEvtWriter(archive, evt_writer)

    _otf2.Archive_CloseEvtFiles(archive)

    # Write the global and local definitions. */
    glob_def_writer = _otf2.Archive_GetGlobalDefWriter(archive)

    # Write the timerange of the trace */
    _otf2.GlobalDefWriter_WriteClockProperties(glob_def_writer, 1, 0, t)

    _otf2.GlobalDefWriter_WriteString(glob_def_writer, STRING_EMPTY, "")

    string = STRING_EMPTY + 1

    # Write paradigm definitions */
    if otf2_MPI or otf2_HYBRID:
        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "MPI")

        _otf2.GlobalDefWriter_WriteParadigm(glob_def_writer,
                                            _otf2.PARADIGM_MPI, string,
                                            _otf2.PARADIGM_CLASS_PROCESS)

        string += 1

        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                          "MPI_COMM_${id}")

        value = _otf2.AttributeValue()
        value.stringRef = string
        string += 1
        _otf2.GlobalDefWriter_WriteParadigmProperty(
            glob_def_writer, _otf2.PARADIGM_MPI,
            _otf2.PARADIGM_PROPERTY_COMM_NAME_TEMPLATE, _otf2.TYPE_STRING,
            value)

        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                          "MPI_WIN_${id}")

        value.stringRef = string
        string += 1
        _otf2.GlobalDefWriter_WriteParadigmProperty(
            glob_def_writer, _otf2.PARADIGM_MPI,
            _otf2.PARADIGM_PROPERTY_RMA_WIN_NAME_TEMPLATE, _otf2.TYPE_STRING,
            value)

        (type_, value) = _otf2.AttributeValue_SetBoolean(_otf2.FALSE)
        _otf2.GlobalDefWriter_WriteParadigmProperty(
            glob_def_writer, _otf2.PARADIGM_OPENMP,
            _otf2.PARADIGM_PROPERTY_RMA_ONLY, type_, value)

    if otf2_OPENMP or otf2_HYBRID:
        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "OpenMP")

        _otf2.GlobalDefWriter_WriteParadigm(
            glob_def_writer, _otf2.PARADIGM_OPENMP, string,
            _otf2.PARADIGM_CLASS_THREAD_FORK_JOIN)
        string += 1

        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                          "OMP Thread Team ${id}")

        value = _otf2.AttributeValue()
        value.stringRef = string
        string += 1
        # FIXME seems like a bad idea to write a hardcoded number 4 here
        _otf2.GlobalDefWriter_WriteParadigmProperty(glob_def_writer,
                                                    _otf2.PARADIGM_OPENMP, 4,
                                                    _otf2.TYPE_STRING, value)

    # Write system tree definitions. */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Rack 0")

    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string + 1, "Rack")

    _otf2.GlobalDefWriter_WriteSystemTreeNode(glob_def_writer, 0, string,
                                              string + 1,
                                              _otf2.UNDEFINED_SYSTEM_TREE_NODE)

    string += 2

    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Blade")

    string_blade = string
    string += 1

    for rank in range(num_ranks // 2):
        name_buffer = "Blade #{}".format(rank)

        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, name_buffer)

        _otf2.GlobalDefWriter_WriteSystemTreeNode(glob_def_writer, rank + 1,
                                                  string, string_blade, 0)
        string += 1

    # Write location group and location definitions. */
    for rank in range(num_ranks):
        name_buffer = "Process {}".format(rank)
        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, name_buffer)

        _otf2.GlobalDefWriter_WriteLocationGroup(
            glob_def_writer, rank, string, _otf2.LOCATION_GROUP_TYPE_PROCESS,
            (rank // 2) + 1)
        string += 1

        for thread in range(num_threads):
            name_buffer = "Thread {}.{}".format(rank, thread)
            _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                              name_buffer)

            _otf2.GlobalDefWriter_WriteLocation(
                glob_def_writer, locations[rank * num_threads + thread],
                string, _otf2.LOCATION_TYPE_CPU_THREAD,
                number_of_events_per_location[rank * num_threads + thread],
                rank)
            string += 1

    # Write region definition for "main". */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "main (mangled name)")
    string += 1
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "main (demangled name)")

    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_MAIN, string,
                                      string - 1, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)
    string += 1

    # Write region definition for an all-threads function. */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "!$omp parallelfor")
    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_OPENMP_PARALLEL,
                                      string, string, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)

    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_OPENMP_LOOP,
                                      string, string, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)
    string += 1

    # Write region definition for OpenMP implicit barrier. */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "!$omp implicit barrier")

    _otf2.GlobalDefWriter_WriteRegion(
        glob_def_writer, REGION_OPENMP_IMPLICIT_BARRIER, string, string,
        STRING_EMPTY, _otf2.REGION_ROLE_UNKNOWN, _otf2.PARADIGM_UNKNOWN,
        _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0, 0)
    string += 1

    # Write region definition for "MPI_Send". */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "MPI_Send")

    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_MPI_SEND, string,
                                      string, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)
    string += 1

    # Write region definition for "MPI_Recv". */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "MPI_Recv")

    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_MPI_RECV, string,
                                      string, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)
    string += 1

    # Write region definition for "MPI_Barrier". */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "MPI_Barrier")

    _otf2.GlobalDefWriter_WriteRegion(glob_def_writer, REGION_MPI_BARRIER,
                                      string, string, STRING_EMPTY,
                                      _otf2.REGION_ROLE_UNKNOWN,
                                      _otf2.PARADIGM_UNKNOWN,
                                      _otf2.REGION_FLAG_NONE, STRING_EMPTY, 0,
                                      0)
    string += 1

    # Define the list of locations which are mpi ranks */
    _otf2.GlobalDefWriter_WriteGroup(glob_def_writer, GROUP_MPI_LOCATIONS,
                                     STRING_EMPTY,
                                     _otf2.GROUP_TYPE_COMM_LOCATIONS,
                                     _otf2.PARADIGM_MPI, _otf2.GROUP_FLAG_NONE,
                                     master_threads)

    # Define the MPI group for MPI_COMM_WORLD */
    _otf2.GlobalDefWriter_WriteGroup(glob_def_writer, GROUP_MPI_COMM_WORLD,
                                     STRING_EMPTY, _otf2.GROUP_TYPE_COMM_GROUP,
                                     _otf2.PARADIGM_MPI, _otf2.GROUP_FLAG_NONE,
                                     mpi_ranks)

    # Define the MPI group for COMM_SELF like communicators */
    _otf2.GlobalDefWriter_WriteGroup(glob_def_writer, GROUP_MPI_COMM_SELF,
                                     STRING_EMPTY, _otf2.GROUP_TYPE_COMM_SELF,
                                     _otf2.PARADIGM_MPI, _otf2.GROUP_FLAG_NONE,
                                     [])

    # Define a group that includes all locations. It will be used by metric instance. */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "All locations")

    _otf2.GlobalDefWriter_WriteGroup(glob_def_writer, GROUP_ALL_LOCATIONS,
                                     string, _otf2.GROUP_TYPE_LOCATIONS,
                                     _otf2.PARADIGM_UNKNOWN,
                                     _otf2.GROUP_FLAG_NONE, locations)
    string += 1

    # Define MPI_COMM_WORD */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "My MPI_COMM_WORLD communicator")
    _otf2.GlobalDefWriter_WriteComm(glob_def_writer, MPI_COMM_MPI_COMM_WORLD,
                                    string, GROUP_MPI_COMM_WORLD,
                                    _otf2.UNDEFINED_COMM)
    string += 1

    # Define MPI_COMM_SELF */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                      "My MPI_COMM_SELF communicator")
    _otf2.GlobalDefWriter_WriteComm(glob_def_writer, MPI_COMM_MPI_COMM_SELF,
                                    string, GROUP_MPI_COMM_SELF,
                                    _otf2.UNDEFINED_COMM)
    string += 1

    # Write member definition of first metric */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Metric_A")
    string += 1

    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "FLOPS")
    _otf2.GlobalDefWriter_WriteMetricMember(glob_def_writer, METRIC_A,
                                            string - 1, STRING_EMPTY,
                                            _otf2.METRIC_TYPE_PAPI,
                                            _otf2.METRIC_ACCUMULATED_START,
                                            metric_types[0],
                                            _otf2.BASE_DECIMAL, 0, string)
    string += 1

    # Write member definition of second metric */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Metric_B")
    string += 1
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "s")

    _otf2.GlobalDefWriter_WriteMetricMember(glob_def_writer, METRIC_B,
                                            string - 1, STRING_EMPTY,
                                            _otf2.METRIC_TYPE_OTHER,
                                            _otf2.METRIC_ABSOLUTE_POINT,
                                            metric_types[1],
                                            _otf2.BASE_DECIMAL, -6, string)
    string += 1

    # Write member definition of third metric */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Metric_C")
    string += 1
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "apples")

    _otf2.GlobalDefWriter_WriteMetricMember(glob_def_writer, METRIC_C,
                                            string - 1, STRING_EMPTY,
                                            _otf2.METRIC_TYPE_OTHER,
                                            _otf2.METRIC_RELATIVE_LAST,
                                            metric_types[2],
                                            _otf2.BASE_DECIMAL, 0, string)
    string += 1

    # Write member definition of fourth metric */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Metric_D")
    string += 1
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "pears")

    _otf2.GlobalDefWriter_WriteMetricMember(glob_def_writer, METRIC_D,
                                            string - 1, STRING_EMPTY,
                                            _otf2.METRIC_TYPE_OTHER,
                                            _otf2.METRIC_ABSOLUTE_POINT,
                                            metric_types[3],
                                            _otf2.BASE_DECIMAL, 0, string)
    string += 1

    # Write member definition of fifth metric */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Metric_E")
    string += 1
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "cherries")

    _otf2.GlobalDefWriter_WriteMetricMember(glob_def_writer, METRIC_E,
                                            string - 1, STRING_EMPTY,
                                            _otf2.METRIC_TYPE_OTHER,
                                            _otf2.METRIC_ABSOLUTE_POINT,
                                            metric_types[4],
                                            _otf2.BASE_DECIMAL, 0, string)
    string += 1

    # Define metric classes and instances */
    _otf2.GlobalDefWriter_WriteMetricClass(glob_def_writer, METRIC_CLASS_1,
                                           metric_members_of_class_1,
                                           _otf2.METRIC_SYNCHRONOUS_STRICT,
                                           _otf2.RECORDER_KIND_CPU)
    _otf2.GlobalDefWriter_WriteMetricClass(glob_def_writer, METRIC_CLASS_2,
                                           metric_members_of_class_2,
                                           _otf2.METRIC_SYNCHRONOUS_STRICT,
                                           _otf2.RECORDER_KIND_CPU)

    _otf2.GlobalDefWriter_WriteMetricClass(glob_def_writer, METRIC_CLASS_3,
                                           metric_members_of_class_3,
                                           _otf2.METRIC_SYNCHRONOUS_STRICT,
                                           _otf2.RECORDER_KIND_CPU)

    _otf2.GlobalDefWriter_WriteMetricClass(glob_def_writer, METRIC_CLASS_4,
                                           metric_members_of_class_4,
                                           _otf2.METRIC_ASYNCHRONOUS,
                                           _otf2.RECORDER_KIND_ABSTRACT)

    # We can define an instance with differing recorder and scope.
    # In this example metric values are valid for all locationa
    # but are recorded on first location. */
    _otf2.GlobalDefWriter_WriteMetricInstance(glob_def_writer,
                                              METRIC_INSTANCE_1,
                                              METRIC_CLASS_4, locations[0],
                                              _otf2.SCOPE_GROUP,
                                              GROUP_ALL_LOCATIONS)

    # write attribute defs */
    if otf2_ATTRIBUTES:
        for a, attribute_def in enumerate(attribute_defs):
            _otf2.GlobalDefWriter_WriteString(glob_def_writer, string,
                                              attribute_def.name)
            _otf2.GlobalDefWriter_WriteAttribute(glob_def_writer, a, string,
                                                 STRING_EMPTY,
                                                 attribute_def.type)
            string += 1

    # create a sub communicator of MPI_COMM_WORLD and embed an hyper cube. */
    num_cube_ranks = gpot(num_ranks)
    cube_ranks = list(range(num_cube_ranks))

    # Define the MPI group for the hyper cube */
    _otf2.GlobalDefWriter_WriteGroup(glob_def_writer, GROUP_MPI_COMM_CUBE,
                                     STRING_EMPTY, _otf2.GROUP_TYPE_COMM_GROUP,
                                     _otf2.PARADIGM_MPI, _otf2.GROUP_FLAG_NONE,
                                     cube_ranks)

    # Define MPI_COMM_MPI_COMM_CUBE */
    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "MPI_COMM_CUBE")
    _otf2.GlobalDefWriter_WriteComm(glob_def_writer, MPI_COMM_MPI_COMM_CUBE,
                                    string, GROUP_MPI_COMM_WORLD,
                                    MPI_COMM_MPI_COMM_WORLD)

    string += 1

    num_cube_dims = 0
    cube_dim = 1
    while cube_dim < num_cube_ranks:
        name = "Cube {}".format(cube_dim)
        _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, name)
        _otf2.GlobalDefWriter_WriteCartDimension(glob_def_writer,
                                                 num_cube_dims, string, 2,
                                                 _otf2.CART_PERIODIC_FALSE)
        string += 1
        num_cube_dims += 1
        cube_dim <<= 1

    cube_dimensions = [
        _otf2.CartDimensionRef(cube_dim) for cube_dim in range(num_cube_dims)
    ]

    _otf2.GlobalDefWriter_WriteString(glob_def_writer, string, "Hyper Cube")
    _otf2.GlobalDefWriter_WriteCartTopology(glob_def_writer, 0, string,
                                            MPI_COMM_MPI_COMM_CUBE,
                                            cube_dimensions)
    string += 1

    for rank in range(num_cube_ranks):
        cube_coordinates = [
            1 if rank & (2**cube_dim) else 0
            for cube_dim in range(num_cube_dims)
        ]
        _otf2.GlobalDefWriter_WriteCartCoordinate(glob_def_writer, 0, rank,
                                                  cube_coordinates)

    _otf2.Archive_CloseGlobalDefWriter(archive, glob_def_writer)

    # write local mappings for MPI communicators and metrics */
    # write local mappings for metrics, this is an identity map, just to write
    # something out

    _otf2.Archive_OpenDefFiles(archive)

    metric_map = _otf2.IdMap_Create(_otf2.ID_MAP_DENSE, NUM_OF_CLASSES)
    for c in range(NUM_OF_CLASSES):
        _otf2.IdMap_AddIdPair(metric_map, c, c)

    for rank in range(num_ranks):
        mpi_comm_map = _otf2.IdMap_Create(_otf2.ID_MAP_SPARSE, 2)

        # Each location uses its rank as the communicator id which maps to the global 0 */
        _otf2.IdMap_AddIdPair(mpi_comm_map, rank, MPI_COMM_MPI_COMM_WORLD)
        _otf2.IdMap_AddIdPair(mpi_comm_map, rank + num_ranks,
                              MPI_COMM_MPI_COMM_SELF)

        for thread in range(num_threads):
            # Open a definition writer, so the file is created. */
            def_writer = _otf2.Archive_GetDefWriter(
                archive, locations[num_threads * rank + thread])

            # Write metric mappings to local definitions. */
            _otf2.DefWriter_WriteMappingTable(def_writer, _otf2.MAPPING_METRIC,
                                              metric_map)

            if otf2_MPI or otf2_HYBRID:
                # Write MPI Comm mappings to local definitions. */
                _otf2.DefWriter_WriteMappingTable(def_writer,
                                                  _otf2.MAPPING_COMM,
                                                  mpi_comm_map)

            # Write clock offsets to local definitions. */
            _otf2.DefWriter_WriteClockOffset(def_writer, 0, 0, 0.0)
            _otf2.DefWriter_WriteClockOffset(def_writer, t, 0, 0.0)

            _otf2.Archive_CloseDefWriter(archive, def_writer)

        _otf2.IdMap_Free(mpi_comm_map)
    _otf2.IdMap_Free(metric_map)

    _otf2.Archive_CloseDefFiles(archive)

    # Finalize. */
    _otf2.Archive_Close(archive)

    _otf2.AttributeList_Delete(attributes)

    print("Done\n")