The cyclic_array.tcl Type Mapping File

The following listing shows the callback and utility procedures as well as the TV::prototype commands needed to implement a type mapping that allows you to view a distributed array.

# Check that the type is what we expect, and that we can 
# locate the appropriate fields.
#
# We're expecting
#    struct cyclic_array 
#    {
#        int * local_elements;
#        int local_count;
#        int global_count;
#        int numprocs;
#        int myproc;
#    };
    
proc da_validate {instance_id} {
    global _da_info
    
    set fields [TV::type get $instance_id struct_fields]
    #
    # We'll save four properties of each type:
    #    The offset of the pointer to the local array.
    #    The target type identifier.
    #    The target type size
    #    The offset of the local_count
    #    The offset of the global count
    set typeinfo [list {} {} {} {} {}]
    set matched 0
    
    foreach field $fields {
        set name [lindex $field 0]
        set addressing [lindex $field 2]
    
        switch -- $name {
            local_elements  {
                set typeinfo [lreplace $typeinfo 0 0 \
                        [extract_offset $addressing]]
                # Extract the target type too.
                set field_typeid \
                        [TV::type get [lindex $field 1] target]
    
                set typeinfo [lreplace $typeinfo 1 1 $field_typeid]
                set typeinfo [lreplace $typeinfo 2 2 \
                        [TV::type get $field_typeid length]]
    
                incr matched
            }
    
            local_count {
                set typeinfo [lreplace $typeinfo 3 3 \
                        [extract_offset $addressing]]
                incr matched
            }
    
            global_count {
                set typeinfo [lreplace $typeinfo 4 4 \
                        [extract_offset $addressing]]
                incr matched
            }
        }
    }
    
    if {$matched != 3} {
        return false
    }
    
    set _da_info($instance_id) $typeinfo
    return true;
}
    
    
#
# Copy any properties we require when defining a new type as a 
# typedef for a type which already has this prototype.
#
proc da_typedef {new_id old_id} {
    global _da_info
    set _da_info($new_id) $_da_info($old_id)
}
    
#
# Return the target type for this array.
#
proc da_type {instance_id} {
    global _da_info
    set typeinfo $_da_info($instance_id)
    
    return [lindex $typeinfo 1]
}
    
#
# It's a two-dimensional array.
#
proc da_rank {type_id} {
    return 2
}
    
#
# Compute the bounds of the required element of the array.
#
proc da_bounds {type_id address} {
    global _da_info
    set typeinfo $_da_info($type_id)

    set address [expr $address + [lindex $typeinfo 4]]
    set bound [read_store $address int]
    
    return "\[$bound\]\[$bound\]"
}
    
#
# Compute the address of the required element of the array.
#
proc da_address {type_id address indices replication} {
    #
    # Each element lives in only one place, so we return a null
    # result if asked for other places for it.
    if {$replication != 0} {
        return ""
    }
    
    global _da_info _da_nprocs
    
    set typeinfo $_da_info($type_id)
    set bound [read_store \
                    [expr $address + [lindex $typeinfo 4]] int]
    
    set distributed_index [lindex $indices 0]
    set other_index [lindex $indices 1]
    set node [expr $distributed_index%$_da_nprocs]
    set local_index [expr $distributed_index/$_da_nprocs]
    
    set element_size [lindex $typeinfo 2]
    
    #
    # We have to work out the whole address.
    #
    set delta [expr $element_size* \
                ($other_index+$bound*$local_index)]
    
    return \
        "$node {addc [lindex $typeinfo 0]; indirect; addc $delta}"
}
    
#
# Return the list of process/thread identifiers over which this
# array is distributed. In this simple example, any of these 
# arrays are distributed over all the processes.  
    
proc da_distribution {type_id address} {
    #
    # For the moment we assume this is all items in our 
    # workers group.
    global GROUP WGROUP _da_nprocs
    
    # Choose the first process in the focus set.
    set proc [lindex [TV::focus_processes] 0]
    
    # Find the relevant worker group identifier.
    set group_id $WGROUP($proc)
    
    # Extract the member identifiers from the worker
    # contents.
    set res [lrange $GROUP($group_id) 1 end]
    
    # Save the number of processes for later.
    set _da_nprocs [llength $res]
    
    return $res
}

 
 
 
 
support@etnus.com
Copyright © 2001, Etnus, LLC. All rights reserved.
Version 5.0