[RFC] _gfortran_{ioparm,filename,line} vs. thread-safety
Jakub Jelinek
jakub@redhat.com
Mon Oct 3 14:51:00 GMT 2005
On Sat, Oct 01, 2005 at 02:02:23PM +0200, FX Coudert wrote:
> My 2 cents on that question...
>
> >One possibility is to add a bitmask field that says which fields have been
> >initialized by the caller and libgfortran would only use those, plus
> >reorder the CHARACTER vars, so that all pointers are groupped together,
> >then all lengths (current layout is very space inefficient on 64-bit
> >arches, as 25% of memory is padding).
>
> I'm just wondering whether this will trade memory for CPU. I think the
> memory used by the whole structure is not that much, and it will not
> really add up to huge numbers (I/O is commonly done in a serial way).
> So, I think keeping things pretty low on CPU (on the library part) would
> be a good point.
I don't think a bitmask for fields that are set would degrade performance,
IMHO quite the opposite. If you care about data locality for strings,
it can be solved easily as in the patch below.
On Sun, Oct 02, 2005 at 08:32:22PM +0200, Thomas Koenig wrote:
> We could recognize options like PAD="yes" at compile-time if the
> value of the options are constants (or at run-time if somebody
> specifies a variable), and then set a corresponding bit in a
> bit field. For cases where a few values are possible, we could
> use an enum and stuff the rest into a few bit fields.
>
> Output character variables should still be handled by the library,
> but INQUIRE can be special-cased, and we could remove a lot of
> character fields for the rest of the I/O functions that way.
>
> Does this make sense?
There are actually far more things that can be special cased.
I think we can have special st_parameter_* structure for all
the I/O commands (except that READ/WRITE/IOLENGTH would share the same
structure).
ATM I'm thinking of something like the following patch (just the io.h
bits, will need to change libfortran/{io/*,runtime/error.c} as well to
prove that it could work, plus then modify trans-io.c to match it.
For say
open (UNIT=99,FORM='unformatted',ACCESS='direct',STATUS='scratch',RECL=16)
the frontend would translate this into:
{
st_parameter_open open_args;
open_args.common.flags
= (IOPARM_OPEN_HAS_RECL_IN|IOPARM_OPEN_HAS_STATUS
|IOPARM_OPEN_HAS_ACCESS|IOPARM_OPEN_HAS_FORM);
open_args.common.unit = 99;
open_args.recl_in = 16;
open_args.status = "scratch";
open_args.status_len = 7;
open_args.access = "direct";
open_args.access_len = 6;
open_args.form = "unformatted";
open_args.form_len = 11;
_gfortran_st_open (&open_args);
}
As a separate optimization, we perhaps later could do what Thomas suggested,
i.e. parse constant literal strings at compile time. If we know that
all user created character variables passed as arguments to I/O functions
have non-NULL char * part (I believe so, except maybe Cray pointers,
but guess that would be undefined behaviour in that case), we could encode
the preparsed strings in the char */int pairs, say
ACCESS='direct'
would become
open_args.access = NULL;
open_args.access_len = ACCESS_DIRECT;
--- libgfortran/io/io.h.jj 2005-09-27 22:09:50.000000000 +0200
+++ libgfortran/io/io.h 2005-10-03 11:15:14.000000000 +0200
@@ -199,80 +199,145 @@ typedef enum
{READING, WRITING}
unit_mode;
-/* Statement parameters. These are all the things that can appear in
- an I/O statement. Some are inputs and some are outputs, but none
- are both. All of these values are initially zeroed and are zeroed
- at the end of a library statement. The relevant values need to be
- set before entry to an I/O statement. This structure needs to be
- duplicated by the back end. */
+#define CHARACTER1(name) \
+ char * name; \
+ gfc_charlen_type name ## _len
+#define CHARACTER2(name) \
+ gfc_charlen_type name ## _len; \
+ char * name
+
+#define IOPARM_LIBRETURN_MASK (3 << 0)
+#define IOPARM_LIBRETURN_OK (0 << 0)
+#define IOPARM_LIBRETURN_ERROR (1 << 0)
+#define IOPARM_LIBRETURN_END (2 << 0)
+#define IOPARM_LIBRETURN_EOR (3 << 0)
+#define IOPARM_ERR (1 << 2)
+#define IOPARM_HAS_IOSTAT (1 << 3)
+#define IOPARM_HAS_IOMSG (1 << 4)
typedef struct
{
+ GFC_INTEGER_4 flags;
GFC_INTEGER_4 unit;
- GFC_INTEGER_4 err, end, eor, list_format; /* These are flags, not values. */
+ const char *filename;
+ GFC_INTEGER_4 line;
+ CHARACTER2 (iomsg);
+ GFC_INTEGER_4 *iostat;
+}
+st_parameter_common;
-/* Return values from library statements. These are returned only if
- the labels are specified in the statement itself and the condition
- occurs. In most cases, none of the labels are specified and the
- return value does not have to be checked. Must be consistent with
- the front end. */
+#define IOPARM_OPEN_HAS_RECL_IN (1 << 5)
+#define IOPARM_OPEN_HAS_FILE (1 << 6)
+#define IOPARM_OPEN_HAS_STATUS (1 << 7)
+#define IOPARM_OPEN_HAS_ACCESS (1 << 8)
+#define IOPARM_OPEN_HAS_FORM (1 << 9)
+#define IOPARM_OPEN_HAS_BLANK (1 << 10)
+#define IOPARM_OPEN_HAS_POSITION (1 << 11)
+#define IOPARM_OPEN_HAS_ACTION (1 << 12)
+#define IOPARM_OPEN_HAS_DELIM (1 << 13)
+#define IOPARM_OPEN_HAS_PAD (1 << 14)
- enum
- {
- LIBRARY_OK = 0,
- LIBRARY_ERROR,
- LIBRARY_END,
- LIBRARY_EOR
- }
- library_return;
+typedef struct
+{
+ st_parameter_common common;
+ GFC_INTEGER_4 recl_in;
+ CHARACTER2 (file);
+ CHARACTER1 (status);
+ CHARACTER2 (access);
+ CHARACTER1 (form);
+ CHARACTER2 (blank);
+ CHARACTER1 (position);
+ CHARACTER2 (action);
+ CHARACTER1 (delim);
+ CHARACTER2 (pad);
+}
+st_parameter_open;
- GFC_INTEGER_4 *iostat, *exist, *opened, *number, *named;
- GFC_INTEGER_4 rec;
- GFC_INTEGER_4 *nextrec, *size;
+#define IOPARM_CLOSE_HAS_STATUS (1 << 5)
- GFC_INTEGER_4 recl_in;
- GFC_INTEGER_4 *recl_out;
+typedef struct
+{
+ st_parameter_common common;
+ CHARACTER1 (status);
+}
+st_parameter_close;
- GFC_INTEGER_4 *iolength;
+#define IOPARM_INQUIRE_HAS_EXIST (1 << 5)
+#define IOPARM_INQUIRE_HAS_OPENED (1 << 6)
+#define IOPARM_INQUIRE_HAS_NUMBER (1 << 7)
+#define IOPARM_INQUIRE_HAS_NAMED (1 << 8)
+#define IOPARM_INQUIRE_HAS_NEXTREC (1 << 9)
+#define IOPARM_INQUIRE_HAS_RECL_OUT (1 << 10)
+#define IOPARM_INQUIRE_HAS_FILE (1 << 11)
+#define IOPARM_INQUIRE_HAS_ACCESS (1 << 12)
+#define IOPARM_INQUIRE_HAS_FORM (1 << 13)
+#define IOPARM_INQUIRE_HAS_BLANK (1 << 14)
+#define IOPARM_INQUIRE_HAS_POSITION (1 << 15)
+#define IOPARM_INQUIRE_HAS_ACTION (1 << 16)
+#define IOPARM_INQUIRE_HAS_DELIM (1 << 17)
+#define IOPARM_INQUIRE_HAS_PAD (1 << 18)
+#define IOPARM_INQUIRE_HAS_NAME (1 << 19)
+#define IOPARM_INQUIRE_HAS_SEQUENTIAL (1 << 20)
+#define IOPARM_INQUIRE_HAS_DIRECT (1 << 21)
+#define IOPARM_INQUIRE_HAS_FORMATTED (1 << 22)
+#define IOPARM_INQUIRE_HAS_UNFORMATTED (1 << 23)
+#define IOPARM_INQUIRE_HAS_READ (1 << 24)
+#define IOPARM_INQUIRE_HAS_WRITE (1 << 25)
+#define IOPARM_INQUIRE_HAS_READWRITE (1 << 26)
-#define CHARACTER(name) \
- char * name; \
- gfc_charlen_type name ## _len
- CHARACTER (file);
- CHARACTER (status);
- CHARACTER (access);
- CHARACTER (form);
- CHARACTER (blank);
- CHARACTER (position);
- CHARACTER (action);
- CHARACTER (delim);
- CHARACTER (pad);
- CHARACTER (format);
- CHARACTER (advance);
- CHARACTER (name);
- CHARACTER (internal_unit);
- gfc_array_char *internal_unit_desc;
- CHARACTER (sequential);
- CHARACTER (direct);
- CHARACTER (formatted);
- CHARACTER (unformatted);
- CHARACTER (read);
- CHARACTER (write);
- CHARACTER (readwrite);
-
-/* namelist related data */
- CHARACTER (namelist_name);
- GFC_INTEGER_4 namelist_read_mode;
+typedef struct
+{
+ st_parameter_common common;
+ GFC_INTEGER_4 *exist, *opened, *number, *named;
+ GFC_INTEGER_4 *nextrec, *recl_out;
+ CHARACTER1 (file);
+ CHARACTER2 (access);
+ CHARACTER1 (form);
+ CHARACTER2 (blank);
+ CHARACTER1 (position);
+ CHARACTER2 (action);
+ CHARACTER1 (delim);
+ CHARACTER2 (pad);
+ CHARACTER1 (name);
+ CHARACTER2 (sequential);
+ CHARACTER1 (direct);
+ CHARACTER2 (formatted);
+ CHARACTER1 (unformatted);
+ CHARACTER2 (read);
+ CHARACTER1 (write);
+ CHARACTER2 (readwrite);
+}
+st_parameter_inquire;
- /* iomsg */
- CHARACTER (iomsg);
+#define IOPARM_DT_END (1 << 5)
+#define IOPARM_DT_EOR (1 << 6)
+#define IOPARM_DT_LIST_FORMAT (1 << 7)
+#define IOPARM_DT_HAS_REC (1 << 8)
+#define IOPARM_DT_HAS_NAMELIST_READ_MODE (1 << 9)
+#define IOPARM_DT_HAS_SIZE (1 << 10)
+#define IOPARM_DT_HAS_IOLENGTH (1 << 11)
+#define IOPARM_DT_HAS_INTERNAL_UNIT_DESC (1 << 12)
+#define IOPARM_DT_HAS_FORMAT (1 << 13)
+#define IOPARM_DT_HAS_ADVANCE (1 << 14)
+#define IOPARM_DT_HAS_INTERNAL_UNIT (1 << 15)
+#define IOPARM_DT_HAS_NAMELIST_NAME (1 << 16)
-#undef CHARACTER
+typedef struct
+{
+ st_parameter_common common;
+ GFC_INTEGER_4 rec, namelist_read_mode;
+ GFC_INTEGER_4 *size, *iolength;
+ gfc_array_char *internal_unit_desc;
+ CHARACTER1 (format);
+ CHARACTER2 (advance);
+ CHARACTER1 (internal_unit);
+ CHARACTER2 (namelist_name);
+ char pad[16 * sizeof (void *)];
}
-st_parameter;
+st_parameter_dt;
-extern st_parameter ioparm;
-iexport_data_proto(ioparm);
+#undef CHARACTER1
+#undef CHARACTER2
extern namelist_info * ionml;
internal_proto(ionml);
Jakub
More information about the Fortran
mailing list