aml.h 39.4 KB
Newer Older
Swann Perarnau's avatar
Swann Perarnau committed
1 2 3 4 5 6 7 8
/*******************************************************************************
 * Copyright 2019 UChicago Argonne, LLC.
 * (c.f. AUTHORS, LICENSE)
 *
 * This file is part of the AML project.
 * For more info, see https://xgitlab.cels.anl.gov/argo/aml
 *
 * SPDX-License-Identifier: BSD-3-Clause
9
 ******************************************************************************/
Swann Perarnau's avatar
Swann Perarnau committed
10

11 12 13 14 15 16 17
/**
 * \file aml.h
 *
 * \brief Main AML header file, contains all high level
 * abstractions declarations.
 **/

18 19 20
#ifndef AML_H
#define AML_H 1

21
#include <assert.h>
22
#include <errno.h>
23 24 25 26 27 28 29
#include <inttypes.h>
#include <numa.h>
#include <numaif.h>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
30
#include <stdlib.h>
31 32
#include <string.h>
#include <strings.h>
33 34 35
#include <sys/mman.h>
#include <unistd.h>

36
#include "aml/utils/bitmap.h"
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
37
#include "aml/utils/error.h"
38
#include "aml/utils/inner-malloc.h"
39
#include "aml/utils/vector.h"
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
40
#include "aml/utils/version.h"
41

42
////////////////////////////////////////////////////////////////////////////////
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
/**
 * @}
 * @defgroup aml "AML Library functions"
 * @brief Initialize/Finalize library.
 *
 * General functions of aml library.
 * Initialization of internal structures, cleanup of everything at the end.
 *
 * @see aml_error
 * @see aml_version
 * @{
 **/

////////////////////////////////////////////////////////////////////////////////

/**
60
 * Initializes the library.
61 62 63 64 65 66
 * @param argc: pointer to the main()'s argc argument; contents can get
 *        modified.
 * @param argv: pointer to the main()'s argv argument; contents can get
 *        modified.
 * @return 0 if successful; an error code otherwise.
 **/
67
int aml_init(int *argc, char **argv[]);
68 69

/**
70
 * Terminates the library.
71 72
 * @return 0 if successful; an error code otherwise.
 **/
73
int aml_finalize(void);
74

75
////////////////////////////////////////////////////////////////////////////////
76

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
77
/**
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 * @}
 * @defgroup aml_area "AML Area"
 * @brief Area High-Level API
 *
 * AML areas represent places where data can belong.
 * In shared memory systems, locality is a major concern for performance.
 * Beeing able to query memory from specific places is of a major interest
 * two achieve this goal. AML Areas provide mmap / munmap low level functions
 * to query memory from specific places materialized as areas. Available area
 * implementations dictate the way such places can be arranged and with which
 * properties. It is important to notice that function provided through Area API
 * are low-level functions and are not optimized for performance as allocator
 * are.
 *
 * @image html area.png "Illustration of areas on a copmlex system." width=700cm
 *
 * @see aml_area_linux
 *
 * @{
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
97 98
 **/

99 100 101 102 103 104
////////////////////////////////////////////////////////////////////////////////

/**
 * aml_area_data is an opaque handle defined by each aml_area
 * implementation. This not supposed to be used by end users.
 **/
105 106
struct aml_area_data;

107 108 109 110 111 112 113 114
/**
 * Opaque handle to pass additional options to area mmap hook.
 * This is implementation specific and cannot be used as a
 * generic interface but rather for customizing area behaviour
 * on per mmap basis.
 **/
struct aml_area_mmap_options;

115 116 117 118 119 120
/**
 * aml_area_ops is a structure containing implementations
 * of an area operations.
 * Aware users may create or modify implementation by assembling
 * appropriate operations in such a structure.
 **/
121 122
struct aml_area_ops {
	/**
123
	 * Building block for coarse grain allocator of virtual memory.
124
	 *
125 126
	 * @param[in] data: Opaque handle to implementation specific data.
	 * @param[in] size: The minimum size of allocation.
127 128 129 130 131
	 *        Is greater than 0. Must not fail unless not enough
	 *        memory is available, or ptr argument does not point to a
	 *        suitable address.
	 *        In case of failure, aml_errno must be set to an appropriate
	 *        value.
132 133
	 * @param[in/out] opts: Opaque handle to pass additional options to area
	 *        mmap hook. Can be NULL and must work with NULL opts.
134
	 * @return a pointer to allocated memory object.
135
	 **/
136
	void* (*mmap)(const struct aml_area_data  *data,
137 138
		      size_t                       size,
		      struct aml_area_mmap_options *opts);
139 140

	/**
141 142
	 * Building block for unmapping of virtual memory mapped with mmap()
	 * of the same area.
143
	 *
144 145 146 147 148 149
	 * @param data: An opaque handle to implementation specific data.
	 * @param ptr: Pointer to data mapped in physical memory. Cannot be
	 *        NULL.
	 * @param size: The size of data. Cannot be 0.
	 * @return: AML_AREA_* error code.
	 * @see mmap()
150
	 **/
151
	int (*munmap)(const struct aml_area_data *data,
152 153 154 155
		      void                       *ptr,
		      size_t                      size);
};

156 157 158 159 160 161 162
/**
 * An AML area is an implementation of memory operations for several type
 * of devices through a consistent abstraction.
 * This abstraction is meant to be implemented for several kind of devices,
 * i.e the same function calls allocate different kinds of devices depending
 * on the area implementation provided.
 **/
163
struct aml_area {
164
	/** Basic memory operations implementation **/
165
	struct aml_area_ops *ops;
166
	/** Implementation specific data. Set to NULL at creation. **/
167 168
	struct aml_area_data *data;
};
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
169 170

/**
171
 * Low-level function for getting memory from an area.
172 173 174
 * @param[in] area: A valid area implementing access to target memory.
 * @param[in] size: The usable size of memory returned.
 * @param[in, out] opts: Opaque handle to pass additional options to area
175
 * @return virtual memory from this area with at least queried size bytes.
176 177
 * @return NULL on failure, with aml_errno set to the appropriate error
 * code.
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
178
 **/
179 180 181
void *aml_area_mmap(const struct aml_area        *area,
		    size_t                        size,
		    struct aml_area_mmap_options *opts);
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
182 183 184

/**
 * Release data provided with aml_area_mmap() and the same area.
185 186
 * @param area: A valid area implementing access to target memory.
 * @param ptr: A pointer to memory address provided with aml_area_mmap()
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
187
 *        by same area and size.
188 189 190
 * @param size: The size of memory region pointed by "ptr".
 * @return an AML error code on operation success.
 * @see aml_area_mmap()
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
191 192 193 194 195
 **/
int
aml_area_munmap(const struct aml_area *area,
		void                  *ptr,
		size_t                 size);
196

197
////////////////////////////////////////////////////////////////////////////////
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
/**
 * @}
 * @defgroup aml_tiling "AML Tiling"
 * @brief Tiling Data Structure High-Level API
 *
 * Tiling is an array representation of data structures.
 * AML tiling structure can be defined as 1D or 2D contiguous arrays.
 * Tiles in tilings can be of custom size and AML provides iterators to
 * easily access tiles element.
 * @{
 **/

////////////////////////////////////////////////////////////////////////////////

/**
 * Tiling types passed to some tiling routines.
 * Regular, linear tiling with uniform tile sizes.
 **/
217
#define AML_TILING_TYPE_1D 0
218 219 220 221 222 223

/**
 * Tiling types passed to some tiling routines.
 * 2-dimensional cartesian tiling with uniform tile sizes, stored
 * in rowmajor order
 **/
224
#define AML_TILING_TYPE_2D_ROWMAJOR 1
225 226 227 228 229 230

/**
 * Tiling types passed to some tiling routines.
 * 2-dimensional cartesian tiling with uniform tile sizes, stored
 * in colmajor order
 **/
231 232
#define AML_TILING_TYPE_2D_COLMAJOR 2

233 234 235 236
/**
 * aml_tiling_data is an opaque handle defined by each aml_tiling
 * implementation. This not supposed to be used by end users.
 **/
237
struct aml_tiling_data;
238 239 240 241 242 243

/**
 * aml_area_tiling_iterator_data is an opaque handle defined by each
 * aml_tiling_iterator implementation. This not supposed to be used
 * by end users.
 **/
244 245
struct aml_tiling_iterator_data;

246 247 248 249 250 251
/**
 * aml_tiling_iterator_ops contains the specific operations defined
 * by an aml_tiling_iterator.
 * Aware users may create or modify implementation by assembling
 * appropriate operations in such a structure.
 **/
252 253
struct aml_tiling_iterator_ops;

254 255 256 257 258 259
/**
 * \brief aml_tiling_iterator is a structure for iterating over
 * elements of an aml_tiling.
 * \todo Provide a detailed explanation of what is a tiling iterator.
 **/
struct aml_tiling_iterator;
260

261 262 263 264 265 266 267
/**
 * aml_tiling_ops is a structure containing a set of operation
 * over a tiling. These operation are the creation and destruction
 * of iterators, access to tiles indexing, size and tiling dimension.
 * Aware users may create or modify implementation by assembling
 * appropriate operations in such a structure.
 **/
268
struct aml_tiling_ops {
269 270 271
	/**
	 * \todo Doc
	 **/
272 273 274
	int (*create_iterator)(struct aml_tiling_data *tiling,
			       struct aml_tiling_iterator **iterator,
			       int flags);
275 276 277
	/**
	 * \todo Doc
	 **/
278 279
	int (*destroy_iterator)(struct aml_tiling_data *tiling,
				struct aml_tiling_iterator **iterator);
280 281 282
	/**
	 * \todo Doc
	 **/
283
	int (*tileid)(const struct aml_tiling_data *tiling, va_list coords);
284 285 286
	/**
	 * \todo Doc
	 **/
Kamil Iskra's avatar
Kamil Iskra committed
287
	size_t (*tilesize)(const struct aml_tiling_data *tiling, int tileid);
288 289 290
	/**
	 * \todo Doc
	 **/
Kamil Iskra's avatar
Kamil Iskra committed
291 292
	void* (*tilestart)(const struct aml_tiling_data *tiling,
			   const void *ptr, int tileid);
293 294 295
	/**
	 * \todo Doc
	 **/
296
	int (*ndims)(const struct aml_tiling_data *tiling, va_list results);
297 298
};

299 300 301 302 303 304 305
/**
 * An aml_tiling is a multi-dimensional grid of data, e.g a matrix, a stencil
 * etc...
 * Tilings are used in AML as a description of a macro data structure that will
 * be used by a library for doing its own work. This structure is exploitable
 * by AML to perform optimized movement operations.
 **/
306
struct aml_tiling {
307
	/** @see aml_tiling_ops **/
308
	struct aml_tiling_ops *ops;
309
	/** @see aml_tiling_data **/
310 311 312
	struct aml_tiling_data *data;
};

313
/**
314
 * Provides the tile id of a tile.
315 316 317 318 319 320
 * @param tiling: an initialized tiling structure.
 * @param coordinates: a list of size_t coordinates, one per dimension of the
 *        tiling.
 * @return -1 in case of invalid coordinates, else the id of the tile
 *         (that is, its order in memory), to use with other functions.
 **/
321 322
int aml_tiling_tileid(const struct aml_tiling *tiling, ...);

323
/**
324
 * Provides the information on the size of a tile.
325 326 327 328 329
 * @param tiling: an initialized tiling structure.
 * @param tileid: an identifier of a tile (a value between 0 and the number
 *        of tiles minus 1).
 * @return the size of a tile.
 **/
Kamil Iskra's avatar
Kamil Iskra committed
330
size_t aml_tiling_tilesize(const struct aml_tiling *tiling, int tileid);
331

332
/**
333
 * Provides the information on the location of a tile in memory.
334 335 336 337 338 339
 * @param tiling: an initialized tiling structure.
 * @param ptr: an address of the start of the complete user data structure
 *        that this tiling describes.
 * @param tileid: an identifier of a tile (a value between 0 and the number
 *        of tiles minus 1).
 * @return the address of the start of the tile identified by "tileid", within
340
 * the provided user data structure.
341 342 343
 **/
void *aml_tiling_tilestart(const struct aml_tiling *tiling,
			   const void *ptr,
Kamil Iskra's avatar
Kamil Iskra committed
344
			   int tileid);
345

346
/**
347
 * Provides the dimensions of the entire tiling in tiles.
348 349 350 351 352
 * @param tiling: an initialized tiling structure.
 * @param sizes: a list of output (size_t *), one per dimension of the tiling.
 *               Will contain the size of each dimension in tiles upon return.
 * @return 0 if successful, an error code otherwise.
 **/
353 354
int aml_tiling_ndims(const struct aml_tiling *tiling, ...);

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
/**
 * \todo Doc
 **/
struct aml_tiling_iterator_ops {
	/**
	 * \todo Doc
	 **/
	int (*reset)(struct aml_tiling_iterator_data *iterator);
	/**
	 * \todo Doc
	 **/
	int (*next)(struct aml_tiling_iterator_data *iterator);
	/**
	 * \todo Doc
	 **/
	int (*end)(const struct aml_tiling_iterator_data *iterator);
	/**
	 * \todo Doc
	 **/
	int (*get)(const struct aml_tiling_iterator_data *iterator,
		   va_list args);
};

/**
 * \todo Doc
 **/
struct aml_tiling_iterator {
	/** @see aml_tiling_iterator_ops **/
	struct aml_tiling_iterator_ops *ops;
	/** @see aml_tiling_iterator_data **/
	struct aml_tiling_iterator_data *data;
};

/**
389
 * Allocates and initializes a new tiling iterator.
390 391 392 393 394 395
 * @param tiling: an initialized tiling structure.
 * @param iterator: an address where the pointer to the newly allocated iterator
 *        structure will be stored.
 * @param flags: reserved for future use; pass 0 for now.
 * @return 0 if successful; an error code otherwise.
 **/
396 397 398
int aml_tiling_create_iterator(struct aml_tiling *tiling,
			       struct aml_tiling_iterator **iterator,
			       int flags);
399
/**
400
 * Tears down an initialized tiling iterator.
401 402 403 404
 * @param tiling: an initialized tiling structure.
 * @param iterator: an initialized tiling iterator structure.
 * @return 0 if successful; an error code otherwise.
 **/
405
void aml_tiling_destroy_iterator(struct aml_tiling *tiling,
406
				 struct aml_tiling_iterator **iterator);
407 408


409
/**
410
 * Resets a tiling iterator to the first tile.
411 412 413
 * @param iterator: an initialized tiling iterator structure.
 * @return 0 if successful; an error code otherwise.
 **/
414
int aml_tiling_iterator_reset(struct aml_tiling_iterator *iterator);
415 416

/**
417
 * Advances a tiling iterator to the next tile.
418 419 420
 * @param iterator: an initialized tiling iterator structure.
 * @return 0 if successful; an error code otherwise.
 **/
421
int aml_tiling_iterator_next(struct aml_tiling_iterator *iterator);
422 423

/**
424
 * Checks whether the iterator is past the last tile.
425 426
 * @param iterator: an initialized tiling iterator structure.
 * @return 0 if the iterator points at a valid tile; 1 if it's past the last
427
 * tile.
428
 **/
Kamil Iskra's avatar
Kamil Iskra committed
429
int aml_tiling_iterator_end(const struct aml_tiling_iterator *iterator);
430 431

/**
432
 * Queries the iterator.
433 434
 * @param iterator: an initialized tiling iterator structure.
 * @param x: an argument of type unsigned long*; on return gets filled with the
435
 *        identifier of the tile currently pointed to.
436 437
 * @return 0 if successful; an error code otherwise.
 **/
Kamil Iskra's avatar
Kamil Iskra committed
438
int aml_tiling_iterator_get(const struct aml_tiling_iterator *iterator, ...);
439

440 441
////////////////////////////////////////////////////////////////////////////////

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
/**
 * @}
 * @defgroup aml_layout "AML Layout"
 * @brief Low level description of data orrganization at the byte granularity.
 *
 * Layout describes how contiguous element of a flat memory address space are
 * organized into a multidimensional array of elements of a fixed size.
 * The abstraction provide functions to build layouts, access elements,
 * reshape a layout, or subset a layout.
 *
 * Layouts are characterized by:
 * * A pointer to the data it describes
 * * A set of dimensions on which data spans.
 * * A stride in between elements of a dimension.
 * * A pitch indicating the space between contiguous elements of a dimension.
 *
 * The figure below describes a 2D layout with a sub-layout
 * (obtained with aml_layout_slice()) operation. The sub-layout has a stride
 * of 1 element along the second dimension. The slice has an offset of 1 element
 * along the same dimension, and its pitch is the pitch of the original
 * layout. Calling aml_layout_deref() on this sublayout with appropriate
 * coordinates will return a pointer to elements noted (coor_x, coord_y).
 * @see aml_layout_slice()
 *
 * @image html layout.png "2D layout with a 2D slice." width=400cm
 *
 * Access to specific elements of a layout can be done with
 * the aml_layout_deref() function. Access to an element is always done
 * relatively to the dimensions order set by at creation time.
 * However, internally, the library will store dimensions from the last
 * dimension to the first dimension such that elements along the first dimension
 * are contiguous in memory. This order is defined called with the value
 * AML_LAYOUT_ORDER_FORTRAN. Therefore, AML provides access to elements
 * without the overhead of user order choice through function suffixed
 * with "native".
 * @see aml_layout_deref()
 * @see aml_layout_deref_native()
 * @see aml_layout_dims_native()
 * @see aml_layout_slice_native()
 *
 * The layout abstraction also provides a function to reshape data
 * with a different set of dimensions. A reshaped layout will access
 * the same data but with different coordinates as pictured in the
 * figure below.
 * @see aml_layout_reshape()
 *
 * @image html reshape.png "2D layout turned into a 3D layout." width=700cm
 *
 * @see aml_layout_dense
 * @see aml_layout_pad
 * @{
 **/

////////////////////////////////////////////////////////////////////////////////

struct aml_layout_ops;
struct aml_layout_data;

/** Structure definition of AML layouts **/
struct aml_layout {
	/** Layout functions implementation **/
	struct aml_layout_ops *ops;
	/** Implementation specific data of a layout**/
	struct aml_layout_data *data;
};

/** List of operators implemented by layouts. **/
struct aml_layout_ops {
	/**
	 * Layout must provide a way to access a specific element
	 * according to the provided dimensions.
	 * Coordinates bounds checking is done in the generic API.
	 * Coordinates provided by the user will match the order
	 * Of the dimensions provided by the user in the constructor.
	 * However, dimensions are always stored internally in the
	 * AML_LAYOUT_ORDER_FORTRAN order.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param coords[in]: The non-NULL coordinates on which to access data.
	 * Coordinates are checked to be valid in aml_layout_deref().
	 * @return A pointer to the dereferenced element on success.
	 * @return NULL on failure with aml_errno set to the error reason.
	 **/
	void *(*deref)(const struct aml_layout_data *data,
		       const size_t *coords);

	/**
	 * Function for derefencing elements of a layout inside the library.
	 * Layout assumes data is always stored in AML_LAYOUT_ORDER_FORTRAN
	 * order. Coordinates provided by the library will match the same
	 * order, i.e last dimension first.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param coords[in]: The non-NULL coordinates on which to access data.
	 * The first coordinate should be the last dimensions and so on to the
	 * last, coordinate, last dimension.
	 * @return A pointer to the dereferenced element on success.
	 * @return NULL on failure with aml_errno set to the error reason.
	 **/
	void *(*deref_native)(const struct aml_layout_data *data,
			      const size_t *coords);

	/**
	 * Get the order in which dimensions of the layout are
	 * supposed to be accessed by the user.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @return Order value. It is a bitmask with order bit set (or not set).
	 * Output value can be further checked against order AML_LAYOUT_ORDER
	 * flags by using the macro AML_LAYOUT_ORDER() on output value.
	 * @see AML_LAYOUT_ORDER()
	 **/
	int (*order)(const struct aml_layout_data *data);

	/**
	 * Return the layout dimensions in the user order.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param dims[out]: The non-NULL array of dimensions to fill. It is
	 * supposed to be large enough to contain ndims() elements.
	 * @return AML_SUCCESS on success, else an AML error code.
	 **/
	int (*dims)(const struct aml_layout_data *data, size_t *dims);

	/**
	 * Return the layout dimensions in the order they are actually stored
	 * in the library.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param dims[out]: The non-NULL array of dimensions to fill. It is
	 * supposed to be large enough to contain ndims() elements.
	 * @return AML_SUCCESS on success, else an AML error code.
	 **/
	int (*dims_native)(const struct aml_layout_data *data,
			   size_t *dims);

	/**
	 * Return the number of dimensions in a layout.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @return The number of dimensions in the layout.
	 **/
	size_t (*ndims)(const struct aml_layout_data *data);

	/**
	 * Return the size of layout elements.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @return The size of elements stored with this layout.
	 **/
	size_t (*element_size)(const struct aml_layout_data *data);

	/**
	 * Reshape the layout with different dimensions.
	 * Layout dimensions are checked in aml_layout_reshape() to store
	 * the exact same number of elements.
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param output[out]: A non NULL pointer to a layout where to allocate
	 * a new layout resulting from the reshape operation.
	 * @param ndims[in]: The number of dimensions of the new layout.
	 * @param dims[in]: The number of elements along each dimension of
	 * the new layout.
	 * @return AML_SUCCESS on success, else an AML error code (<0).
	 **/
	int (*reshape)(const struct aml_layout_data *data,
		       struct aml_layout **output,
		       const size_t ndims,
		       const size_t *dims);

	/**
	 * Return a layout that is a subset of another layout.
	 * Slice arguments compatibility with the original layout are
	 * checked in aml_layout_slice().
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param output[out]: A non NULL pointer to a layout where to allocate
	 * a new layout resulting from the slice operation.
	 * @param dims[in]: The number of elements of the slice along each
	 * dimension .
	 * @param offsets[in]: The index of the first element of the slice
	 * in each dimension.
	 * @param strides[in]: The displacement (in number of elements) between
	 * elements of the slice.
	 * @return A newly allocated layout with the queried subset of the
	 * original layout on succes.
	 * @return NULL on error with aml_errno set to the failure reason.
	 **/
	int (*slice)(const struct aml_layout_data *data,
		     struct aml_layout **output,
		     const size_t *dims,
		     const size_t *offsets,
		     const size_t *strides);

	/**
	 * Return a layout that is a subset of another layout, assuming
	 * dimensions are stored with AML_LAYOUT_ORDER_FORTRAN.
	 * Slice arguments compatibility with the original layout are
	 * checked in aml_layout_slice().
	 * @param data[in]: The non-NULL handle to layout internal data.
	 * @param output[out]: A non NULL pointer to a layout where to allocate
	 * a new layout resulting from the slice operation.
	 * @param dims[in]: The number of elements of the slice along each
	 * dimension .
	 * @param offsets[in]: The index of the first element of the slice
	 * in each dimension.
	 * @param strides[in]: The displacement (in number of elements) between
	 * elements of the slice.
	 * @return A newly allocated layout with the queried subset of the
	 * original layout on succes.
	 * @return NULL on error with aml_errno set to the failure reason.
	 **/
	int (*slice_native)(const struct aml_layout_data *data,
			    struct aml_layout **output,
			    const size_t *dims,
			    const size_t *offsets,
			    const size_t *strides);
};

/**
 * Tag specifying user storage of dimensions inside a layout.
 * Layout order is the first bit in an integer bitmask.
 * @see AML_LAYOUT_ORDER()
 * This tag will store dimensions in the order provided by the user,
 * i.e elements of the last dimension will be contiguous in memory.
 **/
#define AML_LAYOUT_ORDER_C (0<<0)

/**
 * Tag specifying user storage of dimensions inside a layout.
 * Layout order is the first bit in an integer bitmask.
 * @see AML_LAYOUT_ORDER()
 * This tag will store dimensions in the reversed order provided
 * by the user, i.e elements of the first dimension will be contiguous
 * in memory. This storage is the actual storage used by the library
 * inside the structure.
 **/
#define AML_LAYOUT_ORDER_FORTRAN (1<<0)

/**
 * This is equivalent to AML_LAYOUT_ORDER_C.
 * @see AML_LAYOUT_ORDER_C
 **/
#define AML_LAYOUT_ORDER_COLUMN_MAJOR (0<<0)

/**
 * This is equivalent to AML_LAYOUT_ORDER_FORTRAN.
 * @see AML_LAYOUT_ORDER_FORTRAN
 **/
#define AML_LAYOUT_ORDER_ROW_MAJOR (1<<0)

/**
 * Get the order bit of an integer bitmask.
 * The value can be further checked for equality
 * with AML_LAYOUT_ORDER_* values.
 * @param x: An integer with the first bit set
 * to the order value.
 * @return An integer containing only the bit order.
 **/
#define AML_LAYOUT_ORDER(x) ((x) & (1<<0))

/**
 * Dereference an element of a layout by its coordinates.
 * @param layout[in]: An initialized layout.
 * @param coords[in]: The coordinates on which to access data.
 * @return A pointer to the dereferenced element on success.
 * @return NULL on failure with aml_errno set to the error reason:
 * * AML_EINVAL if coordinate are out of bound
 * * See specific implementation of layout for further information
 * on possible error codes.
 **/
void *aml_layout_deref(const struct aml_layout *layout,
		       const size_t *coords);

/**
 * Equivalent to aml_layout_deref() but with bound checking
 * on coordinates.
 * @see aml_layout_deref()
 **/
void *aml_layout_deref_safe(const struct aml_layout *layout,
			    const size_t *coords);

/**
 * Get the order in which dimensions of the layout are supposed to be
 * accessed by the user.
 * @param layout[in]: An initialized layout.
 * @return The order (>0) on success, an AML error (<0) on failure.
 * @return On success, a bitmask with order bit set (or not set).
 * Output value can be further checked against order AML_LAYOUT_ORDER
 * flags by using the macro AML_LAYOUT_ORDER() on output value.
 * @see AML_LAYOUT_ORDER()
 **/
int aml_layout_order(const struct aml_layout *layout);

/**
 * Return the layout dimensions in the user order.
 * @param layout[in]: An initialized layout.
 * @param dims[out]: The non-NULL array of dimensions to fill. It is
 * supposed to be large enough to contain ndims() elements.
 * @return AML_SUCCESS on success, else an AML error code.
 **/
int aml_layout_dims(const struct aml_layout *layout, size_t *dims);

/**
 * Return the number of dimensions in a layout.
 * @param layout[in]: An initialized layout.
 * @return The number of dimensions in the layout.
 **/
size_t aml_layout_ndims(const struct aml_layout *layout);

/**
 * @brief Return the size of layout elements.
 * @param layout[in]: An initialized layout.
 * @return The size of elements stored with this layout.
 **/
size_t aml_layout_element_size(const struct aml_layout *layout);

/**
 * @brief Reshape the layout with different dimensions.
 * This function checks that the number of elements of
 * the reshaped layout matches the number of elements
 * in the original layout. Additional constraint may apply
 * depending on the layout implementation.
 * @param layout[in]: An initialized layout.
 * @param reshaped_layout[out]: A newly allocated layout
 * with the queried shape on succes.
 * @param ndims[in]: The number of dimensions of the new layout.
 * @param dims[in]: The number of elements along each dimension of
 * the new layout.
 * @return AML_SUCCESS on success.
 * @return AML_EINVAL if reshape dimensions are not compatible
 * with original layout dimensions.
 * @return AML_ENOMEM if AML failed to allocate the new structure.
 * @return Another aml_error code. Refer to the layout
 * implementation of reshape function.
 **/
int aml_layout_reshape(const struct aml_layout *layout,
		       struct aml_layout **reshaped_layout,
		       const size_t ndims,
		       const size_t *dims);

/**
 * Return a layout that is a subset of another layout.
 * The number of elements to subset along each dimension
 * must be compatible with offsets and strides.
 * This function checks that the amount of elements along
 * each dimensions of the slice actually fits in the original
 * layout.
 * @param layout[in]: An initialized layout.
 * @param reshaped_layout[out]: a pointer where to store a
 * newly allocated layout with the queried subset of the
 * original layout on succes.
 * @param dims[in]: The number of elements of the slice along each
 * dimension .
 * @param offsets[in]: The index of the first element of the slice
 * in each dimension. If NULL, offset is set to 0.
 * @param strides[in]: The displacement (in number of elements) between
 * elements of the slice. If NULL, stride is set to 1.
 * @return AML_SUCCESS on success, else an AML error code (<0).
 **/
int aml_layout_slice(const struct aml_layout *layout,
		     struct aml_layout **reshaped_layout,
		     const size_t *dims,
		     const size_t *offsets,
		     const size_t *strides);

////////////////////////////////////////////////////////////////////////////////

801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
/**
 * @}
 * @defgroup aml_dma "AML DMA"
 * @brief Management of low-level memory movements.
 *
 * AML DMA (inspired by Direct Memory Access engines) is an abstraction over the
 * ability to move data between places. A DMAs presents an interface that allows
 * clients to create an asynchronous request to move data and to wait for this
 * request to complete. Depending on the exact operation it is configured to do,
 * the DMA might transform the data during the operation.
 *
 * Implementations are mostly responsible for providing access to various types
 * of execution engine for data movement itself.
 *
 * @image html dma.png width=600
 * @{
 **/

////////////////////////////////////////////////////////////////////////////////

/**
 * Internal macros used for tracking DMA request types.
 * Invalid request type.  Used for marking inactive requests in the vector.
 **/
#define AML_DMA_REQUEST_TYPE_INVALID -1

/**
 * The request is in the format (dest layout, src layout)
 **/
#define AML_DMA_REQUEST_TYPE_LAYOUT 0

/**
 * aml_dma is mainly used to asynchronously move data.
 * aml_dma_request is an opaque structure containing information
 * about ongoing request for data movement in a dma operation.
 * @see aml_dma_ops
 * @see aml_dma_async_copy()
 **/
struct aml_dma_request;

/**
 * Opaque handle implemented by each aml_dma implementations.
 * Should not be used by end-users.
 **/
struct aml_dma_data;

/**
   aml_dma_ops is a structure containing operations for a specific
   * aml_dma implementation.
   * These operation are operation are detailed in the structure.
   * They are specific in:
   * - the type of aml_area source and destination,
   * - the progress engine performing the operation,
   * - the type of of source and destination data structures.
   *
   * Each different combination of these three points may require a different
   * set of dma operations.
   **/
struct aml_dma_ops {
	/**
	 * Initiate a data movement, from a source pointer to a destination
	 * pointer, and output a request handler for managing the transfer.
	 * @param dma: dma_implementation internal data.
	 * @param req[out]: the request handle to manage termination
	 *        of the movement.
866 867
	 * @param dest: layout describing the destination.
	 * @param src: layout describing the source.
868 869 870 871
	 * @return an AML error code.
	 **/
	int (*create_request)(struct aml_dma_data *dma,
			      struct aml_dma_request **req,
872 873
			      struct aml_layout *dest,
			      struct aml_layout *src);
874 875 876 877 878 879 880 881 882 883

	/**
	 * Destroy the request handle. If the data movement is still ongoing,
	 * then cancel it.
	 *
	 * @param dma: dma_implementation internal data.
	 * @param req: the request handle to manage termination of the movement.
	 * @return an AML error code.
	 **/
	int (*destroy_request)(struct aml_dma_data *dma,
Swann Perarnau's avatar
Swann Perarnau committed
884
			       struct aml_dma_request **req);
885 886 887 888 889 890 891 892 893 894

	/**
	 * Wait for termination of a data movement and destroy the request
	 * handle.
	 *
	 * @param dma: dma_implementation internal data.
	 * @param req: the request handle to manage termination of the movement.
	 * @return an AML error code.
	 **/
	int (*wait_request)(struct aml_dma_data *dma,
Swann Perarnau's avatar
Swann Perarnau committed
895
			    struct aml_dma_request **req);
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
};

/**
 * aml_dma is an abstraction for (asynchronously) moving data
 * from one area to another. The implementation of dma to use
 * is depends on the source and destination areas. The appropriate
 * dma choice is delegated to the user.
 * @see struct aml_area.
 **/
struct aml_dma {
	/** @see aml_dma_ops **/
	struct aml_dma_ops *ops;
	/** @see aml_dma_data **/
	struct aml_dma_data *data;
};

/**
 * Requests a synchronous data copy between two different buffers.
 * @param dma: an initialized DMA structure.
915 916
 * @param dest: layout describing the destination.
 * @param src: layout describing the source.
917 918
 * @return 0 if successful; an error code otherwise.
 **/
919 920
int aml_dma_copy(struct aml_dma *dma, struct aml_layout *dest,
		 struct aml_layout *src);
921 922 923 924 925 926 927

/**
 * Requests a data copy between two different buffers.This is an asynchronous
 * version of aml_dma_copy().
 * @param dma: an initialized DMA structure.
 * @param req: an address where the pointer to the newly assigned DMA request
 *        will be stored.
928 929
 * @param dest: layout describing the destination.
 * @param src: layout describing the source.
930 931 932
 * @return 0 if successful; an error code otherwise.
 **/
int aml_dma_async_copy(struct aml_dma *dma, struct aml_dma_request **req,
933 934
		       struct aml_layout *dest,
		       struct aml_layout *src);
935 936 937 938 939 940 941

/**
 * Waits for an asynchronous DMA request to complete.
 * @param dma: an initialized DMA structure.
 * @param req: a DMA request obtained using aml_dma_async_*() calls.
 * @return 0 if successful; an error code otherwise.
 **/
Swann Perarnau's avatar
Swann Perarnau committed
942
int aml_dma_wait(struct aml_dma *dma, struct aml_dma_request **req);
943 944 945 946 947 948 949

/**
 * Tears down an asynchronous DMA request before it completes.
 * @param dma: an initialized DMA structure.
 * @param req: a DMA request obtained using aml_dma_async_*() calls.
 * @return 0 if successful; an error code otherwise.
 **/
Swann Perarnau's avatar
Swann Perarnau committed
950
int aml_dma_cancel(struct aml_dma *dma, struct aml_dma_request **req);
951 952 953 954 955 956 957 958 959 960 961 962

/**
 * Generic helper to copy from one layout to another.
 * @param dst[out]: destination layout
 * @param src[in]: source layout
 */
int aml_copy_layout_generic(struct aml_layout *dst,
			    const struct aml_layout *src);


////////////////////////////////////////////////////////////////////////////////

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
/**
 * @}
 * @defgroup aml_scratch "AML Scratchpad"
 * @brief Stage-in, Stage-out High Level Abstraction.
 *
 * Scratchpad in an abstraction fro moving data back and forth from
 * a data representation in an area to another data representation in another
 * areas. This is especially usefull from moving to user data representation
 * to an architecure optimized representation for heavy computational work,
 * then returning the to user representation.
 * Data movement is performed with two dma engines from one area and tiling to
 * another area and tiling.
 *
 * @image html scratch.png width=600
 * @see aml_dma
 * @{
 **/

////////////////////////////////////////////////////////////////////////////////

/**
 * Scratch is mainly used to asynchronously move data back and forth between
 * two areas. aml_scratch_request is an opaque structure containing information
 * about ongoing requests for data movement.
 **/
988
struct aml_scratch_request;
989 990 991 992 993

/**
 * Opaque handle implemented by each scratches implementation.
 * Should not be used by end users.
 **/
994 995
struct aml_scratch_data;

996 997 998 999
/**
 * Scratchpad request types.
 * Invalid request type.  Used for marking inactive requests in the vector.
 **/
1000
#define AML_SCRATCH_REQUEST_TYPE_INVALID -1
1001 1002 1003 1004 1005

/**
 * Scratchpad request types.
 * Push from the scratchpad to regular memory.
 **/
1006
#define AML_SCRATCH_REQUEST_TYPE_PUSH 0
1007 1008 1009 1010 1011

/**
 * Scratchpad request types.
 * Pull from regular memory to the scratchpad.
 **/
1012
#define AML_SCRATCH_REQUEST_TYPE_PULL 1
1013 1014 1015 1016 1017

/**
 * Scratchpad request types.
 * No-op/empty request
 **/
1018
#define AML_SCRATCH_REQUEST_TYPE_NOOP 2
1019

1020 1021 1022 1023 1024 1025 1026 1027 1028
/**
 * aml_scratch_ops contain a scratch implementation specific operations.
 * These operations implementation may vary depending on the source and
 * destination of data, and thus scratch implementations use different
 * operations.
 * Aware users may create or modify implementation by assembling
 * appropriate operations in such a structure.
 * @see struct aml_scratch
 **/
1029
struct aml_scratch_ops {
1030 1031 1032
	/**
	 * \todo Doc
	 **/
1033 1034 1035
	int (*create_request)(struct aml_scratch_data *scratch,
			      struct aml_scratch_request **req, int type,
			      va_list args);
1036 1037 1038
	/**
	 * \todo Doc
	 **/
1039 1040
	int (*destroy_request)(struct aml_scratch_data *scratch,
			       struct aml_scratch_request *req);
1041 1042 1043
	/**
	 * \todo Doc
	 **/
1044 1045
	int (*wait_request)(struct aml_scratch_data *scratch,
			    struct aml_scratch_request *req);
1046 1047 1048
	/**
	 * \todo Doc
	 **/
1049
	void *(*baseptr)(const struct aml_scratch_data *scratch);
1050 1051 1052
	/**
	 * \todo Doc
	 **/
1053
	int (*release)(struct aml_scratch_data *scratch, int scratchid);
1054 1055
};

1056 1057 1058 1059 1060 1061
/**
 * An aml_scratch is abstraction aimed toward temporary use of a data structures
 * in a different area than the one where data currently resides. Scratches in
 * AML take care of asynchornously allocating and moving the data back and forth
 * between areas.
 **/
1062
struct aml_scratch {
1063
	/** @see aml_scratch_ops **/
1064
	struct aml_scratch_ops *ops;
1065
	/** @see aml_scratch_data **/
1066 1067 1068
	struct aml_scratch_data *data;
};

1069
/**
1070
 * Requests a synchronous pull from regular memory to the scratchpad.
1071 1072 1073 1074 1075
 * @param scratch: an initialized scratchpad structure.
 * @param scratchptr: an argument of type void*; the scratchpad base pointer.
 * @param scratchid: an argument of type int*; gets filled with the scratch tile
 *        identifier where the data will be pulled into.
 * @param srcptr: an argument of type void*; the start address of the complete
1076
 *             source user data structure.
1077 1078 1079 1080
 * @param srcid: an argument of type int; the source tile identifier.
 * @see aml_scratch_baseptr()
 * @return 0 if successful; an error code otherwise.
 **/
1081
int aml_scratch_pull(struct aml_scratch *scratch, ...);
1082 1083 1084

/**
 * Requests a pull from regular memory to the scratchpad. This is an
1085
 * asynchronous version of aml_scratch_pull().
1086 1087 1088 1089 1090 1091 1092
 * @param scratch: an initialized scratchpad structure.
 * @param req: an address where the pointer to the newly assigned scratch
 *        request will be stored.
 * @param variadic arguments: see aml_scratch_pull().
 * @return 0 if successful; an error code otherwise.
 * @see aml_scratch_pull()
 **/
1093 1094
int aml_scratch_async_pull(struct aml_scratch *scratch,
			   struct aml_scratch_request **req, ...);
1095
/**
1096
 * Requests a synchronous push from the scratchpad to regular memory.
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
 * @param scratch: an initialized scratchpad structure.
 * @param dstptr: an argument of type void*; the start address of the complete
 *        destination user data structure.
 * @param dstid: an argument of type int*; gets filled with the destination tile
 *        identifier where the data will be pushed into (and where it was
 *        pulled from in the first place).
 * @param scratchptr: an argument of type void*; the scratchpad base pointer.
 * @param scratchid: an argument of type int; the scratchpad tile identifier.
 * @return 0 if successful; an error code otherwise.
 * @see aml_scratch_baseptr()
 **/
1108
int aml_scratch_push(struct aml_scratch *scratch, ...);
1109 1110

/**
1111 1112
 * Requests a push from the scratchpad to regular memory.  This is an
 * asynchronous version of aml_scratch_push().
1113 1114 1115
 * @param scratch: an initialized scratchpad structure.
 * @param req: an address where the pointer to the newly assigned scratch
 *        request will be stored.
1116
 * Variadic arguments: see aml_scratch_push().
1117 1118 1119
 * @return 0 if successful; an error code otherwise.
 * @see aml_scratch_push()
 **/
1120 1121
int aml_scratch_async_push(struct aml_scratch *scratch,
			   struct aml_scratch_request **req, ...);
1122
/**
1123
 * Waits for an asynchronous scratch request to complete.
1124 1125 1126 1127
 * @param scratch: an initialized scratchpad structure.
 * @param req: a scratch request obtained using aml_scratch_async_*() calls.
 * @return 0 if successful; an error code otherwise.
 **/
1128 1129
int aml_scratch_wait(struct aml_scratch *scratch,
		     struct aml_scratch_request *req);
1130

1131
/**
1132
 * Tears down an asynchronous scratch request before it completes.
1133 1134 1135 1136
 * @param scratch: an initialized scratchpad structure.
 * @param req: a scratch request obtained using aml_scratch_async_*() calls.
 * @return 0 if successful; an error code otherwise.
 **/
1137 1138
int aml_scratch_cancel(struct aml_scratch *scratch,
		       struct aml_scratch_request *req);
1139
/**
1140
 * Provides the location of the scratchpad.
1141 1142 1143
 * @param scratch: an initialized scratchpad structure.
 * @return a base pointer to the scratchpad memory buffer.
 **/
1144
void *aml_scratch_baseptr(const struct aml_scratch *scratch);
1145

1146
/**
1147
 * Release a scratch tile for immediate reuse.
1148 1149 1150 1151
 * @param scratch: an initialized scratchpad structure.
 * @param scratchid: a scratchpad tile identifier.
 * @return 0 if successful; an error code otherwise.
 **/
1152 1153
int aml_scratch_release(struct aml_scratch *scratch, int scratchid);

1154 1155 1156 1157 1158 1159
////////////////////////////////////////////////////////////////////////////////

/**
 * @}
 **/

1160
#endif